On 4/2/06, Robert Dober <robert.dober / gmail.com> wrote:> On 4/2/06, Daniel Nugent <nugend / gmail.com> wrote:>> Well, I think you should allowed to put a selective effect on the>> remaining arguments, but it should at least allow you to be a little>> smarter than simply checking one single Type.  I'd like to see you>> able to check against multiple types as well as methods and>> combinations thereof, like>>>> def foo(arg1 : (Array and :custom_array_method) or Hash or>> :special_method)>>>> Then at least it's simply a syntactic convenience for writing>> respond_to? and kind_of? calls.  And, logically, you should be able>> to assign these parameter checks to a variabe so you can reduce the>> duplication of them, although I don't have a clue as to what a good>> syntax for that would be... Maybe something like:>>>> type_check = TypeCheck.new do |var|>>   case var>>   when Array>>     return true if var.respond_to? :custom_array_method>>   when Hash>>     return Hash>>   else>>     return true if var.respond_to? :special_method>>   end>>   return false>> end>>>> And, of course, you can do any checking you want in the block. You>> could then do this:>>>> def foo(arg1 : type_check)>> def bar(arg1, arg2 : type_check)
> I quite agree, showes my how helpless I braught this up. :-( Should> have named the thread "Easier ways to enforce contracts". Is that not> strange that we think types immediately and than are afraid of ancient> Computer Science History.
In Ruby, at least, inheritance is not a guarantee of a contract (even onobjects derived from core classes). It's far better to think in terms ofwhat an object must *do* in your method, rather than to try to considerwhat they *are* in your method. An example might help.
Transaction::Simple has a debug mechanism. It expects an object that canrespond to #<< for output (and I believe *checks* for it). By default,that means that I support String, Array, IO (and most, if not all,descendants), and StringIO. I explicitly wanted it this way, whereas ifI had placed a class check (and make no mistake: most people arefamiliar with statically typed languages and the addition of this willmake people think of Ruby in terms of static typing), I would haveprevented the use of all but the class(es) that I explicitly specified.
Unless you have a *damn* good reason to restrict a method to aparticular class, you shouldn't be doing any sort of checking at allthat way. Checking on method presence (e.g., #respond_to?) is moreuseful (but only partially so; you should check the #arity of a method),but even that fails if the person forgets to implement #respond_to? whenthey've implemented #method_missing. It's also an extra run-time checkthat, well, Ruby already does for you.
Make no mistake: I'm not afraid of static typing. I just think that it'suseless in the context of real software development. I've beendeveloping software for ... a long time. Professionally a little lessthan that. ;) I really *cannot* think of a time when I found that statictyping did anything except get in my way.
> My programs often pass objects of an unexpected "contract, behavior,> type, mixin interface" you name it. I would like a modern language to> help me, the *stupid* programmer to be more *effective* Ruby claims> that.
It's called "unit tests." If your programs are often passing objectsthat don't behave the way you want those objects to behave, then it's abug that you should be ensuring doesn't come out of the caller; in Rubyit's often far more efficient to ensure that the caller doesn't screw upinstead of the callee doing checks ... that Ruby already does. This isone reason I'm so consistently opposed to the Eater Nil that isperiodically proposed: it changes the behaviour to silently fail insteadof noisily fail if I get something I'm not supposed to (usually a nil;in the stuff that I've developed, you won't typically get a Real Objectthat doesn't work).
> So let me suggest the following syntax>> def foo (bar, foobar)  is a shortcut to> def foo( bar, foobar : Object) which is a shortcut to> def foo( bar, foobar : { |para| Object === para } )  so we can put any> constraint in there.
> I still think that is a good thing for readability and maintenance and> *nobody* would be forced to use it. Furthermore we are not forced to> use the block inside the formal parameter list, it would just give us> the opportunity.
It's exceedingly ugly. It's also no better, in implementation terms,than placing the contract enforcement as lines of code at the top of themethod. Except that the latter is clearer, explicit, and infinitely moremaintainable than writing a miniprogram in the parameter list. (And caneasily be extracted to a unit test where that sort of thing probablybelongs in most Ruby code.)
Don't get me wrong: there are times when specifying a type is necessary.Those types when you're dealing with pure Ruby are vanishingly small.I'm looking at implementing some metacode for PDF::Core that includesclass specification (because the PDF specification has a defined numberof object classes). If I'm interacting with SOAP, it is useful tospecify the types/classes that I'm interacting with.
(I would also suggest that if you're going to allow a block for thissort of thing, you need to actually allow for inter-parameter validationas well, e.g., if bar is String then foobar must be Fixnum; if bar isFixnum, then foobar must be String. Of course, that gets into morecomplex validation, which really does underscore my point that thisbehaviour belongs in the method itself. Maybe we can have preconditionand postcondition sections of methods, but putting all this in theparameter list is ugly and nonsensical.)
> I really fail to see why this is inhibiting the language. Such> programs fail explicitly and early, which is better (I claim) than> maybe failing later or just not behaving as expected.
Ah. That's where you're wrong: such programs would not fail any earlierthan they do now. The singular "advantage" to statically typed languagesis that they fail during the compile stage if there's a mismatch. Yourmethod still won't fail until it is called.
-austin--Austin Ziegler * halostatue / gmail.com               * Alternate: austin / halostatue.ca