From: Paul Sanchez Date: 2004-05-19T00:23:50+09:00 Subject: Re: How to duck type? - the psychology of static typing in Ruby In article , Marek Janukowicz wrote: > On Tue, 18 May 2004 08:48:04 +0200, Robert Klemme wrote: [...] > > I alway have to look up definitions... > > http://en.wikipedia.org/wiki/Dynamic_typing#Static_vs._dynamic_type_checking > > > > Unfortunately I'm not familiar with Objective C so I can't judge on that. > > I cannot say I know Objective C well too, but I get some basic concepts. > > > From what I've seen so far I'd assume it's similar to Java which is regarded > > as statically typed although you have access to type information at runtime > > (as seems to be the case with Objective C). But the crucial part is that > > you declare types (of variables, of method arguments) in code and these > > types are checked by the compiler. Yes and no. Objective C started off with ANSI C and added a Smalltalk-like object model on top of it. The C portions are strongly typed, but the object framework made use (initially) of a generic object type called "id", which in practice mapped to "Object*" in the underlying C implementation of the runtime. (Objective-C was initially a pre-processor which generated pure C and linked to the runtime libraries.) Since Objective C uses a single inheritance model, "Object*" could point to objects of any class because all classes were rooted in "Object". > But the feature I described in my previous post has no equivalent in > Java - I'll try to explain it (I may be very wrong, so anyone knowing > Obj-C better please correct me): > > In Obj-C, when you create a variable to hold a pointer to an object of > class Object, you have 2 choices: > > Object *obj; > id obj; > > the second pointer is "typeless", because it can point to an object of > any class. I wonder if similar mechanism could be useful in Ruby. This isn't quite correct, "id" was initially just a pre-processor mapping for "Object*". Later NeXT added "NSObject" as an alternate root class for the object hierarchy, and "id" came to mean "pointer to an instance of any class regardless of root class". They also added typed object declarations, so that "Object*" or "NSObject*" (or "MyObject*") were more restrictive than "id" and could only point to their respective classes + lineal descendents. I always felt that the strong typing was added to placate immigrants from the C++ world. > > Ruby does not do this (as does Lisp, although it seems there are some > > optimization type hints). So without these declarations it's difficult to > > do type verification at compile time without code execution. To introduce > > this wuold be a major change in the language and break lots of code. If you > > would allow for typeless and typed method arguments at the same time, you > > would increase interpreter complexity by orders of magnitude and code would > > be a real mess. I don't think, it's a good idea. > > I'll try to explain my idea in more detail. I suggest that one could put > optional type information when declaring the variable, eg: > > def some_method ( String str, second_param ) > > do |Array ar, smth, Fixnum int| > > etc. > > So basically, current typeless declaration would become something > similar to Obj-C's id, and new typed one would be similar to Obj-C's > Object*. > > Note I don't mean to change (dynamic) method dispatching here - I just > wish Ruby had some mechanism for type checking on variable assignment, > so I don't get enigmatic error messages deep inside a library I use (but > I didn't write). Of course such mechanism would not prevent some runtime > errors (given you can remove method from an object), but it would surely > be very useful (at least for me). > > In other words, this feature would be equivalent of 'strongtyping' > library, just with better syntax and compile-time checking (to avoid > runtime overhead). Objective C took a different approach by creating "protocols" (which were adopted by Java as "interfaces"). Protocols are groups of method signature declarations, with no implementation. If a class implements a protocol, then invoking any of the methods declared in the protocol for instances of that class is guaranteed to be legal. However, there are no guarantees about what will actually happen. The focus and checking is entirely on the existence of behaviors, while leaving the responsibility for the actual behavior (implementation) to each individual class. In Ruby everything is an object, so the type declaration and checking for method arguments and return values doesn't gain you anything. About all you could check would be the existence of methods as a set, rather than checking them one at a time. I worry more about the hazard of undeclared variable names. There's a story, probably apocryphal, about a space probe being lost back in the 1960's because somebody held down a keypunch key too long and turned the variable X into XX on the left-hand of an assignment. Since FORTRAN4 didn't require explicit declaration of variables, the calculation was stuffed into XX (which appeared nowhere else in the program) and X contained an incorrect value for subsequent calculations. Because of this story, I worry sometimes that variables need not be delcared in Ruby. I realize that since everything is an object there's no need for type declarations. However, I think variable set declarations would make some sense - "Here's the set of variable names I'll be using, and anything not in this set is a typo." Disclaimer - I'm not a computer scientist, I've just been programming in a bunch of languages for a long time. If I've said anything outrageous, please be gentle.