class Stream s where
read :: s -> (a, s)
write :: a -> s -> s
and extend it to any type: instance Stream [Int] where
read s = ...
write a s = ...
instance Stream File where
...
and so on, and I can now pass any type that is a member of Stream, to a function that expects one.Contrast OCaml, an object type is represented as a set of (method, types) tuples and type-checking is a subset check (if type A has all the methods of type B, then it's a subtype of B regardless of anything else from visibility to semantics):
# let x =
object
method foo = 42
end;;
val x : < foo : int > = <obj>
# let y =
object
method foo = 63
method bar = 12
end;;
val y : < bar : int; foo : int > = <obj>
# x = y;;
Error: This expression has type < bar : int; foo : int >
but an expression was expected of type < foo : int >
The second object type has no method bar
# type simple = < foo : int >;;
type simple = < foo : int >
# (y :> simple) = x;;
- : bool = false
#http://en.wikipedia.org/wiki/Expression_problem
Anyway, there's been quite a few proposals to add extensible records to Haskell, which would allow row polymorphism, similar to what you just showed in OCaml:
http://hackage.haskell.org/trac/ghc/wiki/ExtensibleRecords
Too bad that it has gone nowhere in a long time.
No, I'm comparing structural typing, which is what Go implements, to nominative typing.
But that may very well be due to me having stayed in context of an other sub-thread where this was the subject, and using that as a filter for the current one.
Even if it was, one example of a difficult bug in one system does not invalidate a whole concept.
And duck typing is almost as old as programming itself...