smarter way to provide interface capabilities from underlining interface

153 views
Skip to first unread message

Vasiliy Tolstov

unread,
Jun 10, 2023, 6:16:34 AM6/10/23
to golang-nuts
I have sql driver that wraps original driver.Driver, to be able to work with drivers that not have ExecerContext or QuerierContext i need to return wrapped to that supports only needed interfaces.
I'm to want to write all cases via handmade switch case and write generator that creates full combo list of methods and generate interfaces for this methods.
Does it possible to have smaller code that provides the same effect?
Or I'm miss something?

-- 
Vasiliy Tolstov,
e-mail: v.to...@selfip.ru

Tamás Gulácsi

unread,
Jun 11, 2023, 3:10:01 AM6/11/23
to golang-nuts
As Far as I See, you check all the combinations of methods in wideness order.
Why not have a generic wrapper struct, that is filled with the underlying driver.Conn's methods,
and use that if not nil, but use the generic implementation if not.

Like
```
type wrappedConn struct {
  driver.Conn
  queryContext func(...)
}
func (wc wrappedConn) QueryContext(...) ... {
  if wc.queryContext != nil { return wc.queryContext(...) }
  return wc.Conn.Query(...)
}
```

This way you only have to check for each method on driver.Conn, and fill the wrappedConn's functions as they axist/not.

Brian Candler

unread,
Jun 11, 2023, 12:31:01 PM6/11/23
to golang-nuts
I think the issue is that the *consumer* of this object checks whether certain methods (or rather, interfaces) are present, and behaves differently depending whether they are or not.

There are a whole load of public interfaces defined here:
And the supplied object, which the OP is trying to wrap, could implement some arbitrary combination of these interfaces.

I think that for *some* of these interfaces, it would be OK to provide dummy implementations if there is no underlying method to call: e.g.

But for others it's much less clear, and it may make a semantic difference whether the the object you provide implements these interfaces or not, e.g.

For these, I can't think of a better implementation that the OP's. It doesn't seem like the greatest API design though.

Vasiliy Tolstov

unread,
Jun 11, 2023, 3:56:14 PM6/11/23
to Brian Candler, golang-nuts
Yes, you are right. Mostly i'm worry about compile/run time. As i see on my mac air m1 compilation on go 1.20 slowdown to 1-2s (i think because file parsing) 
And don't know about running time of such checks for many interface implementations...
I'm try to check in number of interfaces in descending order... But don't understand how this can be optimized... May be run profile with all known sql drivers and create pairs with most used combinations.... ?

-- 
Vasiliy Tolstov,
e-mail: v.to...@selfip.ru


На 11 июня 2023 г., 19:31:01, Brian Candler <b.ca...@pobox.com> написали:
--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/4dc775df-6627-4134-8b32-e9f659e48831n%40googlegroups.com.

Brian Candler

unread,
Jun 12, 2023, 2:55:24 AM6/12/23
to golang-nuts
If runtime is a problem, then you could use a lookup table.  Suppose you have (say) 10 possible interfaces in the object: then you test those ten, build a 10-bit binary number from the 'ok' values, and use this as an index into 2^10 possible constructor functions.

You still need to compile those 2^10 functions though, each of which has a different struct type. I don't know if it's possible to use 'reflect' to build the struct type dynamically; if you can, I know you could create an instance of it dynamically.

Otherwise, I'd check for interfaces where you can safely provide a dummy implementation: Resetter, Validator, Pinger are good examples. For those, you can do what Tamás suggested: always provide an implementation in your wrapper object, and then if the underlying object doesn't have one, just do nothing and return OK. Even if you only handle those three, you'll speed up your compile time and runtime by a factor of 8.

Brian Candler

unread,
Jun 12, 2023, 7:17:31 AM6/12/23
to golang-nuts
On Monday, 12 June 2023 at 07:55:24 UTC+1 Brian Candler wrote:
I don't know if it's possible to use 'reflect' to build the struct type dynamically

FWIW, I tried it, but could only make a program which crashes spectacularly.
 
There is a comment in the documentation of reflect.StructOf which may or may not be relevant:
StructOf currently does not generate wrapper methods for embedded fields and panics if passed unexported StructFields. These limitations may be lifted in a future version.
Reply all
Reply to author
Forward
0 new messages