From: Simon Kitching Date: 2003-11-06T15:05:58+09:00 Subject: Re: Managing metadata about attribute types On Thu, 2003-11-06 at 16:27, Austin Ziegler wrote: > On Wed, 5 Nov 2003 18:08:04 +0900, Ryan Pavlik wrote: > > Austin Ziegler wrote: > > > >> It isn't inferior, and you don't need type info. Remember -- an > >> object should validate or transform its own data. > > > > I'm trying to stay out of this because I mostly disagree. This however > > warrants addressing. > > > > This is demonstrably wrong. > > Actually, it's demonstrably correct. It's exactly to the point and > perfectly accurate regarding how one should deal with data in a > dynamically typed language such as Ruby. In Text::Format, I have a > method #hyphenator= which accepts any object that responds to > #hyphenate_to with an arity of 2 or 3. I explicitly reject any other > object. In documentation, I make it clear that #hyphenate_to should > return an array of two objects. In this way, I don't care what > *class* an object is, I just care that it's type is a hyphenator (as > defined above). > > > An object cannot validate and transform its own data in this > > context in any reasonably general manner. > > Your StrongTyping module doesn't help with this, either, Ryan. It's > not a conversion module. I don't think that the concept of strict typechecking deserves quite such a roasting :-) For me, when looking at a method like def foo(param) ... end the question is "what contract is the param required to adhere to?". And maybe "what is the contract of the returned object". If the code is strictly-typed, like void foo(Map map) end then I know exactly what contract the param must adhere to: it's documented in the javadoc on the Map class. [Isn't that the definition of "type"? A contract of behaviour?] Ok, there are flaws to strict typing. The first is that the contracts tend to over-specify. The foo method probably only wants a few of the methods from the Map class, but the concrete class of the object I pass must implement them *all*. In fact, the Java collections class has an ugly hack to resolve this issue: methods are allowed to throw an Unsupported exception, which means an object might only partially fulfil the required contract. However 90% is probably good enough. And for java's Object-based collections, you lose part of the contract: what is the object type *in* the map. Generics (templates for Java) will resolve this issue (I hope). In programming languages which are always distributed with non-obfuscated source code, the source can be inspected to determine the contract. This isn't too bad a solution, provided the library author writes clean code and comments it well. Some developers are well enough disciplined to put the contract in comments. This is fairly rare, though. And there is no guarantee that those comments are actually correct and up-to-date. And then there is "try it and see", where the user has to discover the contract by trial and error. I'm not so fond of this. In the end, the problem is simply one of human<->human communication. The author of a library needs to tell the user of the library about various contracts. Strict typing is one end of the spectrum of this communication. It results in well-specified code, but at the cost of extra developer labour. Ruby is the other end; it results (generally) in completely unspecified code (see "read the source" above) but imposes little overhead on the developer. Compiler-assisted programming, where the compiler tells the user when they got it wrong is just a bonus. I wouldn't miss this as much as the lack of *communication* about types. I don't think that a true measure of the effectiveness of strict typing can be had by saying "I wrote a big application and didn't need strict typing". I suggest you try *using* a big library someone else wrote, and see if you miss it :-). Then deliver that app to a customer and see if they turn up any cases where you made a mistake about the contract of a method or parameter. Obviously I'm biased; my experience is mainly in strictly-typed languages. For smallish apps I can clearly see the benefits of Ruby. In fact, given a combination of good unit-tests and well-modularised code (so I can see all the places an object is manipulated and therefore deduce its contract), I could be convinced of Ruby for large projects too. But I think I will always wish that the *type* of parameters (and return values!) were simply documented via type declarations like Java. Cheers, Simon