Hi -- On Mon, 10 Jan 2005, itsme213 wrote: > 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. My main first reaction was that I find the reference to duck typing misleading. I think what you're sketching out here is, in some respects, the opposite of duck typing; that is, rather than simply asking an object to do something at the moment you want it to do that thing, you're introducing a wrapper/notation mechanism which, as I understand it, will prevent you from getting to that point at all under certain conditions. Thus your mechanism actually causes you to *avoid* duck typing. That doesn't make it good or bad in itself -- it would just be clearer, I think, not to label it duck typing. I know we're supposed to ignore all that punctuation for now... :-) but one way or another, *something* would have to encapsulate all that information, so it would be likely to look at least somewhat like what you've got, which for me would be a fairly major drawback. I love the clean, not very punctuation-heavy look of Ruby so much that I'm willing to give it lots of weigh against possible language features and innovations. I'd rather have some explicit calls to #respond_to? than a system for abbreviating those calls into punctuation -- even though it's more words, even though it takes longer to type. Ruby is already very concise; even doing a couple of explicit assignments (as in the expansion of your last example) is a lot shorter than it would be if, say, memory had to be allocated, or variable type declared. Maybe there's some way to develop the pattern-matching idea but not necessarily put it all in the method signature. Could incremental things, like allowing #respond_to? to take an array or multiple arguments, work in that direction? David -- David A. Black dblack / wobblini.net