News for hackers. Stuff that matters.
Re:Is Go Duck-Typed? by lmm on Wednesday March 04, 2020 @07:59PM (#22489911)
A function explicitly has no further semantics than its inputs and outputs. The receiving function shouldn't, and won't, assume anything about what the function it's passed does. Whereas when you're passed a bundle of named functions that (presumably) share state between them, it's very natural to assume that this implies relationships between how those functions will behave (even in the simplest examples, e.g. Java's Iterator has only two methods, but it also specifies a relationship between what those two methods return). And so it's very easy to write code that relies on those relationships, and then breaks when passed a bundle of named functions that does not conform to that relationship.
Re:Is Go Duck-Typed? by jerf on Thursday March 05, 2020 @09:25AM (#22493699)
"then breaks when passed a bundle of named functions that does not conform to that relationship."

In that case, the fault lies with the thing that put unrelated functions together and passed them to a thing expecting them to be related. I'm not claiming that structural typing will somehow prevent programmers from deliberately writing wrong things, because I mean, what type system can make that promise? My point is that it is in my experience very rare for something expecting "something that can write bytes" to be accidentally passed "something that can write novels" or something equally unrelated, and then the world blows up in a bad way (that is, not just an exception thrown, because that's just a risk of dynamic languages, but actual bad things happening).

Dynamic languages can at least still get what I said wrong; in Go it's even harder because as others have pointed out, Write([]byte) and Write(NovelInput) Novel still can't cross. But even in dynamic languages, this isn't a problem I had.

Re:Is Go Duck-Typed? by lmm on Thursday March 05, 2020 @10:01AM (#22494024)
Nothing can go wrong with a single function like Write - but in that case you don't need a structural type, you can just pass a write function. As soon as you pass a bundle of two or more functions, you're implying a relationship between them, and it's then easy to accidentally violate that relationship - for instance, a structural type will almost always admit a mutable implementation where the relationship breaks down if the thing is mutated in between calls to the two functions.
Re:Is Go Duck-Typed? by throwaway894345 on Thursday March 05, 2020 @11:42AM (#22495181)
Like I said elsewhere in the thread, you can have the same problem with callbacks:

    func receiver(next func() bool, getItem func() Foo) {}
vs

    type FooIter interface { Next() bool; Item() Foo }

    func receiver(iter FooIter) {}
You're more likely to pass the wrong set of callbacks than to pass the wrong FooIter implementation since the type system doesn't require the callbacks to be related to the same data nor named any certain way.
Re:Is Go Duck-Typed? by lmm on Thursday March 05, 2020 @06:38PM (#22499609)
Replied elsewhere.
Re:Is Go Duck-Typed? by throwaway894345 on Thursday March 05, 2020 @11:40AM (#22495159)
You have the same issue if you pass multiple callbacks to a given function, except as previously mentioned, you're more likely to pass the wrong set of callbacks than to pass the wrong interface implementation (because interface methods are named must be bound to the same data).
Re:Is Go Duck-Typed? by lmm on Thursday March 05, 2020 @06:37PM (#22499607)
Right, but you don't do that. The people who are happy passing functions around are not happy passing multiple callbacks around, by and large. (For example, rather than separate hasNext and next functions, you'd have a single function that returned an optional value).
Re:Is Go Duck-Typed? by throwaway894345 on Friday March 06, 2020 @10:20AM (#22504222)
I agree, but we're arguing about a hypothetical bug scenario that has probably never ever happened: accidentally implementing this sort of stateful interface. These stateful interfaces are already very rare (at least in Go) and accidentally implementing an interface is itself vanishingly rare (I don't think I've ever heard of this happening in practice). It doesn't make sense to me to take grievance with Go's interfaces (which offer strictly stronger protections than callbacks), but be okay with naked callbacks on the basis that "people tend not to use them in a stateful manner" (never mind the stateless scenario in which bare callbacks also provide weaker guarantees than Go's interfaces).
Re:Is Go Duck-Typed? by lmm on Saturday March 07, 2020 @08:33PM (#22515659)
> we're arguing about a hypothetical bug scenario that has probably never ever happened: accidentally implementing this sort of stateful interface. These stateful interfaces are already very rare (at least in Go)

Any interface can be implemented by something that's accidentally (or intentionally) stateful - there's nothing that prevents that in Go. And a interface containing more than one function almost certainly has an implicit relationship between those functions that an implementation could accidentally violate.

> and accidentally implementing an interface is itself vanishingly rare (I don't think I've ever heard of this happening in practice).

Accidentally implementing an interface must happen all the time - not in the sense of unrelated functions having a name collision, but in the sense of implementing a type that looks like another type and not explicitly looking through all the interfaces that other type implements and what expectations they carry.

> It doesn't make sense to me to take grievance with Go's interfaces (which offer strictly stronger protections than callbacks), but be okay with naked callbacks on the basis that "people tend not to use them in a stateful manner" (never mind the stateless scenario in which bare callbacks also provide weaker guarantees than Go's interfaces).

Naked callbacks make it clear what the expectation is and where the responsibility lies. It's the same as the idea that bad encryption is worse than no encryption at all, or a datastructure that is "mostly threadsafe" is worse than one that immediately errors when used from multiple threads.