From: Austin Ziegler Date: 2003-11-20T08:00:41+09:00 Subject: Re: "stereotyping" (was: Re: Strong Typing (Re: Managing metadata about attribute types) ) On Thu, 20 Nov 2003 05:48:37 +0900, Sean O'Dell wrote: > On Wednesday 19 November 2003 12:04 pm, Austin Ziegler wrote: >> On Thu, 20 Nov 2003 02:43:31 +0900, Sean O'Dell wrote: >>> Then don't specify a type for your arguments. Some people need >>> it, some people don't. >> Who *needs* it? And why? Immediately, the classes of applications > I do. I almost didn't choose Ruby because of the lack of type checking. > I am primarily a C++ programmer. My guess is you're not hearing the > argument of scores of C++/Java programmers because they're not here, > because Ruby has zero type-checking. Likely not. Because if you're looking at choosing a scripting language based on its type-checking, you're excluding the vast majority of modern scripting languages including Perl, Python, JavaScript, and Ruby. > I mean that in all seriousness. I grant that you mean that in all seriousness. But in doing so, you're not wanting Ruby. And I mean *that* in all seriousness. Interface publication and type checking are two different things. > People don't fiddle around arguing with others, generally, they > just walk away. I have never said a word to anyone in the Python > group about what could make Python better because there's too much > wrong with it to begin with. That's my opinion of Ruby right now. > I love it, but I think there are things like lack of type checking > that are making people go "ah screw it" and just move on. Again: consider the words of Bruce Eckels. The man knows what he's talking about and is amazed by the power of not statically type checking. It's saved him loads of work. You want to add the work back *into* Ruby development. Optionally, I grant, but part of what a language designer like Matz must consider, is what changes like you're talking about would mean to the "culture" of the language. If people start using an "optional" method signature mechanism for type name enforcement, then that changes the assumed and actual dynamicity of Ruby. I suspect that the number of people thinking "ah screw it" are few and far between and instead are feeling liberated from having to specify types unnecessarily. Consider generics in Java (templates in C++). These effectively introduce the sort of dynamicity that is found in Perl, Python, and Ruby. Instead of having to do: int max(int x, int y) { return x >= y ? x : y } float max(float x, float y) { return x >= y ? x : y } double max(double x, double y) { return x >= y ? x : y } You can do: def max(x, y); x >= y ? x : y; end I know which I would prefer, and C++'s move toward generics is a halting step toward that step. >> that *need* this are (1) RPC-based programs that are dynamically >> discoverable, and therefore need cross-language inspection and >> (2) interface builders (a la Visual Basic "Property Inspectors"). >> I can't think of any other class of application that *needs* this >> sort of meta data. I fully support being able to have this >> information available, say: > Then you're not thinking hard enough about it. I can't force the > notion that type checking is useful if you really don't want to > listen. It's not that I don't want to listen: it's that type checking doesn't help in the real world. Ruby is used in a number of real world large-scale projects. >>> Doing a respond_to? for every method you need an object to >>> implement is tedious, >> Yes, it is. That's why I don't do it often. I document what the >> object requires and then I expect the user to follow it. This is >> the heart of duck-typing: you use the object given to you. Unless >> you're doing something that requires programmatic discovery (see >> my notes above), documentation is sufficient. > No, documentation is not sufficient, especially since there is so > much code out there that is NOT documented. It would be much > easier to provide a typing mechanism that could at least report > which interfaces an object provides. Developers are more likely to > take advantage of that than they are to provide documentation. *shrug* If you want to think that static type checking is really going to help, that's your call. But it won't. >> Oops. StringIO instances respond to #select, but they're not IO >> or File objects at all. Exactly how does name checking help you >> here? StringIO is a valid IO object by signature, but it's not >> "of IO". > Well, clearly the hierarchy is not designed to report properly > which interface StringIO implements, which is sort of my point. If > there were an abstract IO interface, StringIO could declare itself > an implementation of that interface, and methods that required > that interface would then have very informative error messages for > developers who passed it an non- conforming object. Useless runtime processing. >>> It saves a lot of code and headaches when you can just ask "does >>> this object implement this interface?" >> Why do you need to ask unless you're implementing one of the >> cases that I pointed out above? Look at a lot of Ruby code out >> there: it *assumes* that the object provided implements the >> interface -- and it documents it as such. > That is my point exactly. The assumption is already there. The > flexibility is already lost. You MUST provide a certain object > which provides a certain interface, or you end up with a deeply > embedded error, instead of an informative one pointing to your own > code. Incorrect. You might want to look at various libraries to see how they handle this stuff. Some do it through custom exceptions. Some do it early (a la Text::Format#hyphenator=). >>> You might not find it useful, but others definitely do. >> Mostly people new to Ruby recently from Java. Seriously. > No. People experienced in both. I've programmed for Ruby for a > year or so now and I still wish for some type checking now and > then, when I'm digging around in someone else's code trying to > figure out what parameters they expected. I tend to open the code and look at it. > I don't take being called a C++ or Java programmer as an insult. I > take it to mean that you don't, or haven't, programmed in either > enough to see type checking as a blessing, not a curse. Obviously, you're not speaking about that which you know. I recommend against it. I've done plenty of C, C++, Java, and Pascal programming -- as well as truly strongly typed languages (Ada, PL/SQL). Ada provides type checking that is *truly* useful (and exceedingly annoying because of its inflexibility), not the half-assed crap you get in C and C++. I've had to write two to twenty times the amount of code in C/C++, Java, or Pascal to do the same amount of work in Ruby. Not only that, my Ruby handles more types than my equivalent statically typed code. >>> Being able to query for the signature of an interface, with some >>> syntactic sugar to allow parameters to require them (optionally) >>> is very much, to me, The Ruby Way; fearless and visionary. This >>> should make everyone happy; people don't lose their flexibility >>> and we get all the type checking anyone should need. >> Once again: ancestry/name checking is not type checking. Neither >> is method checking (#respond_to?). Ruby divorces type from class, >> which is something that C++ doesn't do, and Java users "sorta" >> get if they think about interfaces. > Terminology issue. Okay, let's call my promotion "interface > declaration." That's all I advocate right now. Still don't like it. I'd accept method signature publication that doesn't actually do anything except provide metadata. Anything that does anything automatic is too high a cost on runtime and flexibility. You're also advocating changing the way that Ruby's object hierarchy works. In theory, because Rubyists don't generally do ancestry/name checking, this won't break anything. You realise, of course, that you could solve this outside of Ruby's core entirely: class Foo implements IO end Foo.new.implements?(IO) # => true I'll leave the implementation as an exercise for the reader. Done right, you could easily add it to all of the core classes, too. Don't be surprised, though, if few people use it -- like few people use StrongTyping. >> Anecdotally, I did some work with Ruwiki recently and Chad Fowler >> created a mock object to make the Ruwiki tokenizing process think >> that it was dealing with an instance of Ruwiki. That mock object >> has become part of Ruwiki's object hierarchy, although not as >> Chad defined it. (I abstracted the data that Chad was using into >> its own object.) If I had done ancestry checking initially, Chad >> wouldn't have been able to do this. > Ah, ancestry checking. I see where we are crossed up in this. Let > me be clearer. I only advocate "interface checking." A class is > just one form of interface. A module is another, when it's > mixed-in. I wholly support something like this: > class MyMockRuwikiClass interface RuwikiClass > end Sorry, I don't want Java. We've already got it and I prefer not to use it because it requires entirely too much typing to do what should be simple things (e.g., iterating through lists) or thinking to do what shouldn't be *that* hard (e.g., lists of heterogeneous items). What's the difference between "interface Ruwiki" and "include Ruwiki" (neither of which would work, because Ruwiki isn't a module and is therefore unable to be included into other classes). In fact, Chad was able to determine that there were four methods needed. If he had attempted to include Ruwiki in his mock class, he would have gotten *tons* more functionality. Remember: the functionality had not yet been abstracted. Because I didn't do "interface" checking, Chad was able to Do The Smart Thing without depending on me having Done The Right Thing to begin with. >>> So, although YOU might not need this, I and others do. >> Why? I'm serious. It's also a rhetorical question: why do you >> need this? What about your code demands this? Is it a presumed >> need, or a real need? If it's a presumed need, YAGNI. If it's a >> real need, why not consider if your design and/or implementation >> are too fragile. A need for static typing in Ruby is an indicator >> of code smell. Yes, I have some smelly code that I haven't >> updated to this point. > I've made a pretty good analogy in another post. If it's the post I'm thinking of, it doesn't stand up to the real world. >> If someone wants a scripting language that requires type >> checking, use PHP. Neither Perl nor Python offer type >> checking[1], although Python went through this discussion a >> couple of years ago, and they apparently did decide to implement >> an optional type system. The best form I found from my >> perspective was PyIDL. > Wait, you don't throw the baby out with the bath water. Ruby is > infinitely superior to PHP. It doesn't have to become like PHP > just to get "interface declarations." I disagree. Ruby plus static typing -- or interface checking, if you want to call it that -- isn't a language that I'm interested in. (And I must repeat that "interface checking" is still too kind for it; the reality is that any sort of name checking is a promise that's worth less than "the check's in the mail.") -austin -- austin ziegler * austin@halostatue.ca * Toronto, ON, Canada software designer * pragmatic programmer * 2003.11.19 * 16.45.48