From: itsme213 Date: 2005-01-10T13:51:22+09:00 Subject: Duck Typing as Pattern Matching I am not a type-system expert, but I started thinking about Ruby-based duck typing some time ago and came up with something that seems promising to me. I wondered what other Ruby-ists think of the general idea. Duck typing should specify the minimal behavior required from an object that gets bound to a variable. Pattern matching (functional languages, Lisp loop macros, etc.) binds a set of variables (all at once) by stating the minimum necessary to extract values for the pattern variable from the target objects, ignoring other irrelevant bits of that object. Both are about matching criteria and binding of variables. Pattern matching is more concise than the corresponding code to bind each variable separately (think regexes, or multiple value assignment), and it happens to also convey type information (defines a criteria to match objects). Ruby already uses some special-case patterns: multi-value assignment, *splat, &block. So the basic idea is: duck typing = pattern matching Types are patterns. An object is a member of a type if the type pattern matches that object. Preliminary examples below, please don't get hung up on the (very tentative) syntax: ::[x, y] = obj # x = obj[0], y = obj[1]; # illustration only, defer *splat for now ::[x, {k1: y}] = obj # x = obj[0], y = obj[1][:k1] def f ( [x, y] ) : [] # def f ( xy ); x = xy[0]; y = xy[1].. # assert returns.respond_to? :[] # Notice how revealing the signature has become def f ( m(): x ) # you may prefer var : type style instead... later .. # def f (x) # assert x.respond_to?(:m) def f ( [ *m() ] : x ) # def f (x) # assert x.all?{|y| y.respond_to?(:m)}, or #each equivalent M1 = ::(m1()) # things that have #m1() M1M2 = M1 && ::(m2()) # things with m1(), m2() def f ( M1M2: x ) # def f (x) # assert: x responds to :m1 and :m2 def f ( (m1(), m2()): x, (m3(): y, m4(): z) ) # you may prefer var : type style instead... later .. # def f ( x, yz ) # assert x.respond_to?(:m1) && x.respond_to(:m2) # y = yz.m3() # z = yz.m4() # Notice how revealing the signature has become. I am interested in any initial reactions. Thanks.