On Mon, 17 May 2004, Tim Bates wrote: > Below is my dissertation on the subject. :P My > intention is to incorporate any comments people might have into the text > and then place it on the Wiki as an introduction to Duck Typing for the > static typist. Excellent idea, Excellent article. Thanks. > 1) People with a Static Typing background often have the urge to do > something like this: > > attr_reader :date > def date=(val) > raise ArgumentError.new("Not a Date") if val.class != Date > end > > This is not duck typing - this is trying to get Ruby to do Static Typing. Well, a more sophisticated Static Typer would do... attr_reader :date def date=(val) raise ArgumentError.new("Not a Date") if val.kind_of? Date end > 2.a) Discussing this on #ruby-lang, David Black suggested the following > optimization: > > def date=(val) > begin > @date = Date.new(val.year, val.month, val.day) > rescue > begin > val =~ /(\d{4})\s*[-\/\\]\s*(\d{1,2})\s*[-\/\\]\s*(\d{1,2})/ > @date = Date.new($1.to_i,$2.to_i,$3.to_i) > rescue > begin > @date = Date.new(val[0], val[1], val[2]) > rescue > raise ArgumentError, "Unable to parse #{val} as date" > end > end > end > end Really cute. More polymorphic, probably a bit slow as exception paths are usually expected to be "rare" and hence under optimized. (Certainly true in C++, I don't know about Ruby.) Anybody care enough to benchmark this? I would also prefer it to rescue just a No Method exception than just any Exception. You can really really really hide some horrible bugs catching just any exception. Like empty catch blocks in Java, it is a truly evil practice. > 4) The fourth and final approach, which I believe to be the Zen of Duck > Typing, is as follows: > > # Accepts an object which responds to the +year+, +month+ and +day+ > # methods. > attr_accessor :date The worse breakage I have seen in a Object Oriented System was in a language called Actor, where for optimization reasons they had forced the internal representation of their graphics type into pairs of two byte integers. This turned a very large, very useful generic 2D geometry library into something totally useless to me. ie. Never gratiutously break polymorphism, even if you personally can't think of another use for this code, somebody else can. For example, suppose you got a string from a SQL server that was a "date". But since parsing the string is difficult and expensive to do, you just don't. You stuff it into the date= method and lo and behold, it just so turns out that for this execution path you _never_ actually invoke :year, :month, :day, it just travels through your system, and gets converted to a string with .to_s and written back to SQL. If you had put additional checks in the code, it would have broken, and you would have been forced to do an expensive and useless conversion. John Carter Phone : (64)(3) 358 6639 Tait Electronics Fax : (64)(3) 359 4632 PO Box 1645 Christchurch Email : john.carter / tait.co.nz New Zealand The universe is absolutely plastered with the dashed lines exactly one space long.