From: Sean O'Dell Date: 2003-11-20T02:43:31+09:00 Subject: Re: "stereotyping" (was: Re: Strong Typing (Re: Managing metadata about attribute types) ) On Tuesday 18 November 2003 10:30 pm, Austin Ziegler wrote: > On Wed, 19 Nov 2003 08:08:25 +0900, Sean O'Dell wrote: > > > All I ever really care about is knowing whether or not an object > > implements a certain interface, and that interface can either be > > described as a mix-in module or an ancestor class. It doesn't > > really matter to me where that interface was defined, any class or > > module will do; the object could also be much more evolved than I > > expect it to be, and could even have lots of methods overridden. I > > don't really care. All I care about is if it is *at least* > > implementing a certain basic interface. > > Ancestry/name checking doesn't tell you that a method implements a > certain interface. It says that it inherits from a class or includes > a module. You can assume that a name indicates an interface, but > that's a bad assumption: > > class File > class << self > undef :read > end > end > > Oops! Now you've got something that's a File, but doesn't correspond > to the required interface. Granted, this is a pathological case, but > I could see this sort of thing being done in a sandbox situation. But if something derives or mixes in an interface, then it *does* implement the interface. The module or class *is* the implementation. Sure, you can hack it out; that can happen in any language. I can pass pointers to int where a FILE pointer is expected in C and C++. That's not the point. Here, watch this pseudo-C++ (or maybe it's Java to some): class MyFile : public File { int open(const char* filename) { throw "this implementation cannot open files"; } } I can create an object of the above class and pass it to functions that expect an object of class File. If any of those functions uses the open function, KA-BOOM. Anyone can deliberately circumvent an interface. That's not the point. The point is, there's a STRONG INDICATION that MyFile implements the File interface. It's a declaration, not a guarantee. > > It would also be nice if I could specify that certain method > > parameters can only be objects containing a certain interface. For > > example: > > > > def mymethod(:SomeModule a) > > end > > > > ...where Ruby automatically asserts for me that a has :SomeModule > > somewhere in its hierarchy, and throws an appropriate exception if > > it does not. > > Blech. I don't want Java. You're talking exactly what Ryan's > StrongTyping module does, and assuming that a name accurately > represents an interface. Then don't specify a type for your arguments. Some people need it, some people don't. > If you want to ensure something conforms to an expected interface, > test that interface. For example, adapted from Text::Format: > > def hyphenator=(x) > raise unless x.respond_to?(:hyphenate_to) > raise unless [2, 3].include?(x.method(:hyphenate_to).arity) > @hyphenator = x > end > > This would be simplified by my proposed change to #respond_to? > (although it wouldn't *really* help in this case; I'd need to have > an Array version). Doing a respond_to? for every method you need an object to implement is tedious, especially when developing a collection of related functions, and it doesn't mean that the object does what it reports to do, nor that it takes the parameters you expect. For example, if an object responds_to?(:open), what does it open? A file by name? The end of a socket? Which? However, if an object implements the :socket interface, then I know it responds_to? :open, :close:, :read, :write, :select, etc. and I know exactly what parameters to pass. These things are important. It saves a lot of code and headaches when you can just ask "does this object implement this interface?" You might not find it useful, but others definitely do. This is one of the things I think Ruby could do very well and still retain its flexibility. 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. So, although YOU might not need this, I and others do. I think this is also one of those little things that would win people over to Ruby. Having absolutely no solid type checking is a big turn-off for a lot of people, and it's what keeps them developing in C/C++, Java and so on. If they're contemplating learning a script language, this would definitely catch their eye. Sean O'Dell