Live data from Hacker News

Is Go Duck-Typed?

bionic.fullstory.com

71–80 of 89 posts

Re: Is Go Duck-Typed?

#71
post #66
post #53

Earlier quoted context omitted.

Isn't this just the stuff making all lambdas implicitly implement a single-method interface and such?

On JVM level, yes. But on Java level, the type of the method is structurally matched to the type of the interface.

The name of the function is typically the same though, even with structural typing. This doesn’t seem quite like that.

Re: Is Go Duck-Typed?

#72
post #2

This is called Structural Typing[0] and is in contrast to Nominal Typing[1] (e.g. Java). 0: https://en.wikipedia.org/wiki/Structural_type_system 1: https://en.wikipedia.org/wiki/Nominal_type_system

Is it just me or is the wikipedia article for duck typing really bad? The example they have is not illustrative or explanatory at all. class Duck: def fly(self): print("Duck flying") class Sparrow: def fly(self): print("Sparrow flying") class Whale: def swim(self): print("Whale swimming") for animal in Duck(), Sparrow(), Whale(): animal.fly() output: Duck flying Sparrow flying AttributeError: 'Whale' object has no at…

Duck typing really only makes sense in the context of dynamic typing.

Re: Is Go Duck-Typed?

#73
post #54
post #52

Earlier quoted context omitted.

Are records structural in Standard ML? What happens if you have multiple records with the same structure but different names? I thought structural typing of records was not very useful without row polymorphism.

Records of the same structure but different names are equivalent. In fact tuples are just sugar over records with numeric fields starting from 1. Note that this is not the same as in OCaml, afaik.

It depends. OCaml explicitly has polymorphic records as well.

Re: Is Go Duck-Typed?

#74
post #72

Earlier quoted context omitted.

Is it just me or is the wikipedia article for duck typing really bad? The example they have is not illustrative or explanatory at all. class Duck: def fly(self): print("Duck flying") class Sparrow: def fly(self): print("Sparrow flying") class Whale: def swim(self): print("Whale swimming") for animal in Duck(), Sparrow(), Whale(): animal.fly() output: Duck flying Sparrow flying AttributeError: 'Whale' object has no at…

Duck typing really only makes sense in the context of dynamic typing.

That's a given. That comment doesn't further the conversation in any way though?

Re: Is Go Duck-Typed?

#75
post #70
post #49

Earlier quoted context omitted.

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'…

"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 th…

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?

#76

Earlier quoted context omitted.

Neg is used to implement operator overloading for unary minus; it's unclear how you would implement this functionality without only doing one thing.

Thanks for clarifying that; I was actually aware of the link to syntactic sugar and it's probably true that you want to control that independently. After all, who doesn't want to hijack unary minus for the purpose of as hackneyed rendering of EBNF? C++ certainly does it :) Anyway a serious answer to your comment would be to create a field or ring concept. This would unify some or all of the arithmetic operations. A n…

> After all, who doesn't want to hijack unary minus for the purpose of as hackneyed rendering of EBNF?

Ha!

> Anyway a serious answer to your comment would be to create a field or ring concept.

Yeah, this is true. We really, really struggled to create a set of traits for numerics, even regardless of these more advanced ideas... so it's unclear this would work. But it's certainly closer than I had thought :)

Re: Is Go Duck-Typed?

#77
post #72

Earlier quoted context omitted.

Duck typing really only makes sense in the context of dynamic typing.

That's a given. That comment doesn't further the conversation in any way though?

You said it was a dynamic typing issue, not a duck typing one, when in fact the two are inseparable in the example you gave. That is absolutely an example of duck typing, you’re calling the same method on three different types with no subtyping relationship with a single invocation.

Re: Is Go Duck-Typed?

#78
post #39

Earlier quoted context omitted.

> Golang furthers the notion of capabilities as shared method signatures, by loosely binding this into interfaces, and enforcing many errors by static type checks at compile time. This, I think, is the main point of the parent comment. I think the distinction (and overlap) come into focus when you think computationally: how is a type computed ? Type semantics are determined by the type checker, and Go's interface typ…

While Go interfaces are usually checked at compile time, this doesn't have to be the case - you don't even have to use reflection. Consider the following program. package main import "fmt" type Dog struct{} func (d Dog) NumberOfLegs() int { return 4 } func (d Dog) Genus() string { return "Canin" } func main() { var dog interface{} = Dog{} fmt.Println(dog.(interface{ NumberOfLegs() int }).NumberOfLegs()) fmt.Println(d…

Why do good people downvote what they don't understand?

https://play.golang.org/p/d0TkGTCZa2S

Runtime results in panic:

  4
  Canin
  panic: interface conversion: main.Dog is not interface { 
  Happy() bool }: missing method Happy
  goroutine 1 [running]: main.main() /tmp/sandbox251002434/prog.go:18 +0x200
Using interface casting, Golang do support "duck typing" in similar fashion as ruby's Object class. Here, by convention, the instance of Dog doesn't support "type" Happy(), therefore fails at runtime.

So golang is somewhat dynamic as well, although using interface{} is kludgy and one would want to avoid that and reflection whenever possible.

Re: Is Go Duck-Typed?

#79
post #49

Earlier quoted context omitted.

My experience is the same. It's interesting to me that people are very concerned about Go's structural subtyping, but they generally have no qualms about passing functions around. Given that the contract for a function is the function signature, and the contract for an interface is [all function signatures and their associated names ], surely the latter is less error prone?

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'…

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?

#80
post #75
post #70

Earlier quoted context omitted.

"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 th…

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 d…

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.
Post reply on HN