5 ms·
I think it's common, coming from the object oriented world, to expect polymorphism to be intrinsically tied to method overloading. But it doesn't have to be. P
by stcredzero 7y ago
I think it's common, coming from the object oriented world, to expect polymorphism to be intrinsically tied to method overloading. But it doesn't have to be.
Please provide some examples. For example, I don't think polymorphism in direct variable references is all that good.
It leaves the Go language with more freedom from the future. Everyone agrees Go needs polymorphism. So add polymorphism.
This statement confuses me. Go has polymorphism.
- uryga 7y ago> Go has polymorphism polymorphism is often distinguished into ad-hoc polymorphism (interfaces) and parametric polymorphism (generics) – i'm guessing GP was referring to the latter?
- lalaithion 7y agoYou're right, in my head I was writing parametric polymorphism, and it just didn't make it's way to my fingers somehow.
- lalaithion 7y agoIf you go and look at the Map/Reduce/Filter, Channels, Containers, and Append sections of the examples, there isn't any use of contracts. All that is required for those sections to work is to declare a type parameter, and then allow that parameter to be filled by any type, but still typecheck that all of the variables with the same parameter are the same type at the calling site. There's no need to have a contract for which methods can be called on the type, because we don't need to call any methods or access any fields. In my experience, this fills most use cases. It allows generic data structures, and generic functions over those structures. If you need a little bit of behavior for those types, such as for a TreeMap data structure or a Sort function, Go's higher order functions make this possible without contracts, by passing in functions. The draft's Containers section uses this approach to construct a TreeMap. The SliceFn function, described in the Sort section, also uses this approach: func SliceFn(type Elem)(s []Elem, f func(Elem, Elem) bool) { Sort(sliceFn(Elem){s, f}) } Although this does use method overloading via contracts in implementation (via Sort), it doesn't need it. I expect that Go's existing interfaces (which yes, are a form of polymorphism, mea culpa) + unbounded parametric polymorphism are enough to solve 90% of Go's current issues. The more complex cases are still possible to handle with parametrically polymorphic structs containing functions. Yes, that's bad code, but we'd be able to look for this use case, judge how often it occurs, and use it's use cases as data to inform further discussions on contracts. The only case I struggle to easily deal with is the numeric case. My solution doesn't allow generic numeric functions, although I think there's room to explore that in more detail.
- stcredzero 7y agoIf you go and look at the Map/Reduce/Filter, Channels, Containers, and Append sections of the examples, there isn't any use of contracts. I see. I'm of the opinion that the Go team might be more cautious and introduce a more limited form of generics first, which seems in line with what you're saying. In my experience, this fills most use cases. It allows generic data structures, and generic functions over those structures. How would one make something like ConcurrentMap? Perhaps some operations on a map could be exposed and "overridden?"
- lalaithion 7y agoIt would be simple to write a ConcurrentMap. What is more difficult is writing a function which accepts both ConcurrentMaps and TreeMaps. In Java, they would both inherit from Map. In this proposal(/Rust/Haskell) they would implement the same contract(/trait/interface). In my proposal... there isn't an elegant solution. In some cases, you can write the function to be generic over an insertion function `insert func(T)`, if all you need is assertion, and then you can pass `treeMap.insert` as the parameter. If you really truly need to be generic over the entire `Map` interface, that is one of the cases that I claim only takes up 10% of the cases. In that case, you could define a type which contains all of the functions a Map needs, and then you could construct that and manually pass that in. This can be viewed as a desugaring of contracts. One implementation that contracts could have would be to, at runtime, construct and pass a value containing the functions that the contract specified are possible.
- higherkinded 7y agoIt's "typeclass", not "interface". Though it works similar and is, in fact, just a way to define a constraint. As of your described way of desugaring the contract, looks way too cluttered. It's exactly the reason why Reader and ReaderT exist in Haskell. Even though the proposal's contract syntax doesn't look very beautiful, it's still drastically better than keeping track of drilled structs of functions, the latter will become a mess really really fast, so having a way to conveniently constraint the accepted types while having a full-blown parametric polymorphism is essential for a modern language. Not sure exactly why anyone would be against that.