On Wed, 2 Sep 2020 at 10:56, Jesper Louis Andersen <
jesper.louis.ander...@gmail.com> wrote:

> Usually, my experience is that these highly dynamic interfaces is an
> indication you want to approach the problem from a different angle. You
> will converge on something that gets closer and closer to having an
> interface{}, and this means you are converging toward a world of dynamic
> typing. It often happens because you spot an initial pattern and try to
> hoist out common code. But there are situations where taking a completely
> different route yields far simpler code which is easier to handle.
>
> Code will have to branch based on the data you have available. This is the
> primary reason why languages add sum-types. Go doesn't have sum-types, so
> you'll have to build your own variant, usually by having an indicator in a
> struct what you are looking at. However, this means you have no
> exhaustiveness checks, and no automatic optimization, which is the price
> you pay for this simplification.
>

An alternative approach is to use a struct containing function fields
rather than an interface, which allows easy inspection of capabilities too.
That's the approach that Nick Craig-Wood ended up using for rclone; see
this type for an example:
https://pkg.go.dev/github.com/rclone/rclone/fs?tab=doc#Features


> On Wed, Aug 26, 2020 at 7:10 PM cpu...@gmail.com <cpui...@gmail.com>
> wrote:
>
>> Great post, thank you! Found you Wrap method looks exactly like my
>> decorate :).
>>
>> While not entirely satisfying it does solve the problem and the set of
>> optional methods in my case is always below 5 so the effort is manageable.
>> Since the optional interfaces are really narrow (always 1 method) I guess I
>> can proceed with this approach...
>>
>> Kind regards,
>> Andi
>>
>> On Wednesday, August 26, 2020 at 5:59:13 PM UTC+2
>> axel.wa...@googlemail.com wrote:
>>
>>> Hi,
>>>
>>> no, there isn't really a solution to this. I've blogged about this:
>>>
>>> https://blog.merovius.de/2017/07/30/the-trouble-with-optional-interfaces.html
>>> A combination of generics and embedding can help. So, you can do
>>>
>>> type Wrapper[T] struct {
>>>     T
>>>     otherFields
>>> }
>>>
>>> func (w *Wrapper) SomeNewMethod() {
>>> }
>>>
>>> But even then, you need to know the static type of what you're wrapping
>>> (so http Middleware, for example, couldn't use this).
>>>
>>> I'm also not super sure if it's a good idea to do this even if you
>>> could. An interface might contain multiple, interdependent methods. As an
>>> example, `http.ResponseWriter` implicitly calls `WriteHeader` the first
>>> time you call `Write`. So, if you wrap a `ResponseWriter` and overwrite
>>> `WriteHeader`, that overwritten method has to be called explicitly (the
>>> underlying `ResponseWriter` will call its own `WriteHeader`). So if you
>>> don't know what the methods of the wrapped type are and do, you might
>>> introduce very hard to find bugs.
>>>
>>> On Wed, Aug 26, 2020 at 5:49 PM cpu...@gmail.com <cpu...@gmail.com>
>>> wrote:
>>>
>>>> Hi All,
>>>>
>>>> using interfaces for behavioural testing seems a common pattern in go:
>>>>
>>>>     if typed, hasCapability := d.(Capability); hasCapability...
>>>>
>>>> I have the requirement to dynamically compose interfaces at runtime,
>>>> i.e. I cannot know upfront which set of interfaces a resulting type will
>>>> support:
>>>>
>>>>     type resultingType interface {
>>>>         basicCapability
>>>>         ...any combination of additional capabilities
>>>>     }
>>>>
>>>> If there is only a single additional/optional capability to implement
>>>> that is simple to solve, e.g. by implementing a wrapping struct that embeds
>>>> the basic capability and adds an additional capability. Applying this
>>>> pattern across multiple layers (stack of wrapping structs does not work as
>>>> the embedded interfaces don't bubble up).
>>>>
>>>> However, the number of additional capabilities that a type might have
>>>> to support could be bigger (think of physical meters which could supply
>>>> power, energy, currents, frequency etc).
>>>>
>>>> I'm solved this by using go:generate which is fed the basic and set of
>>>> optional types and generates additional types for any _combination_ of
>>>> additional types, an example is attached (and source at
>>>> https://github.com/andig/evcc/pull/310/files#diff-fa40c05651b4682eb25a198f8a4a98f0).
>>>> This is similar to the "old" pattern of simulation generics via generated
>>>> code.
>>>>
>>>> I'm wondering if using a pattern of dynamic composition is sound, if
>>>> the the go:generate approach is a good one or if there are better ways?
>>>>
>>>> Kind regards,
>>>> Andi
>>>>
>>>> --
>>>> 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/217cee40-1e00-442d-a4d2-7d4a37e41544n%40googlegroups.com
>>>> <https://groups.google.com/d/msgid/golang-nuts/217cee40-1e00-442d-a4d2-7d4a37e41544n%40googlegroups.com?utm_medium=email&utm_source=footer>
>>>> .
>>>>
>>> --
>> 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+unsubscr...@googlegroups.com.
>> To view this discussion on the web visit
>> https://groups.google.com/d/msgid/golang-nuts/bacb1b26-daf2-49b3-8d56-e9530803e6f4n%40googlegroups.com
>> <https://groups.google.com/d/msgid/golang-nuts/bacb1b26-daf2-49b3-8d56-e9530803e6f4n%40googlegroups.com?utm_medium=email&utm_source=footer>
>> .
>>
>
>
> --
> J.
>
> --
> 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+unsubscr...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/golang-nuts/CAGrdgiUJQSJwvY1eYWiRN%2BGGumJsDXfarhwpvhLoVRub0d%2BR3g%40mail.gmail.com
> <https://groups.google.com/d/msgid/golang-nuts/CAGrdgiUJQSJwvY1eYWiRN%2BGGumJsDXfarhwpvhLoVRub0d%2BR3g%40mail.gmail.com?utm_medium=email&utm_source=footer>
> .
>

-- 
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+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAJhgacg0zAZ_ffrt4NWh%2Bbz4S_BavQPhmo7tiv_D0sMjYBvJAQ%40mail.gmail.com.

Reply via email to