From: Peter Date: 2003-11-22T11:47:44+09:00 Subject: Re: "stereotyping" (was: Re: Strong Typing (Re: Managing metadata about attribute types) ) > Oh, I see. You know, I think I know of a script language that did that. > Actually, what it had were a sort of virtual method system, where you could > have the same method name implement several variations of itself, but each > one was tagged to a "context." When you call the method, you could call it > in the default context and the default method would execute, or put the > object into some other context and call the method, and an entirely different > method would execute. The method names could be the same; they were only > differentiated by their context. Yup. And what I mean to say is that that context can be provided by the interface the method belongs to. It's merely an idea, I don't know how it will look in practice. And in case you would uberhaupt decide to borrow something from the idea above, please don't get me started about the dangers of defaults ;-) > I know it's a shortcoming, but the whole notion of interfaces has lots of > things that restrict what you can do. That's why you can mix them in > anywhere, and all the usual Ruby rules still apply. > > But I think where might want both a run-time method morphing scheme AND to be > able to promise it through an interface, I really think we would have to come > up with a name aliasing scheme (perhaps that was your suggestion originally, > I think). It would serve the purpose. > > But let's also not forget that interfaces wouldn't DOMINATE Ruby. They're > just there to provide a little help to code sharers. I doubt it can be all > things to all people. Granted. But my feeling is that it would be nicer to have the benefits of interface checking without any loss in flexibility. There will be loss in code size, but I do like the idea of saying something in code instead of in documentation - which interface checking could partly do IMO. Documentation makes promises, interfaces could formalize them. But you'd have to get it right... > I think if the interface mechanism were there, it would appear as a short hop > to adding in an "alternate context" sort of mechanism. Right now, that's a > couple steps ahead, so it's seems far-off, but with interfaces working, it > wouldn't. Agreed. I'm just a bit worried that you're proposal as it is now - or was when I last checked it - will limit flexibility initially, which will make its acceptance a bit harder. What I hope from your proposal is that it's really a way of declaring that you're duck typing. I feel that it would be better to have your approach be built from the ground up with the same dynamism and flexibility in mind - especially in the context of ruby. Anyway, the "alternate context" sort of mechanism is just a possibility for an extra abstraction level. > But interfaces are for making contracts. Contracts are like plans. You can't > design it poorly up-front, start making promises, then rescind the promises. > The interfaces (when used, they ARE optional) are supposed to be a layout of > what something can and can't do. Ruby provides flexibility enough by itself, > interfaces should provides firmness. My point is that an existing interface, e.g., from a library makes a number of promises, and when reusing some of the components making these promises, you'd only need a subset of those promises. It's not a matter of good design, but a matter of granularity. As interfaces declare collections of methods, each method offering some functionality, it should be clear that not in all contexts the functionality of each of these methods is required, but only a subset. To make it concrete... if I'd use the String class, which offers a number of methods, it's easily imagineable that there's a method I'll never use in my code, e.g., unpack. Duck typing then means that instead of passing my code a String, it is OK to pass it an object which implements all methods from String except for unpack. Does this make the interface that String provided poorly designed? What I really want to say is that good design is always an issue, but to have no interference with duck typing, you need to deal with the issue of granularity as well. And this can be provided by superinterfacing and subinterfacing - the former being only necessary when you have fixed interfaces that can't be extended dynamically. This would be nice if it was what you wanted, but it seems like it's your implementation that would need it - correct me if I'm wrong. > I see where you're driving at. The interface is not compared through method > signatures. There are methods which require InputOutput by name, not by a > set of method signatures, so superclassing to Input and thus generating a > unique signature of methods would not make those methods happy. They still > just want objects which fulfill the InputOutput contract. > > Again though, my experience is: when you design the interfaces, just design > them right. Like I said, an interface contains a number of methods, right? Each method holds a number of promises, possibly WRT other methods, right? To me a method that supplies only part of the promises logically is another method. A method is really a request to do something, and the promises of a method kind of catch the idea of what the request asked for (if that's not so, your code will malfunction). But no matter how well you design your interface, it's unthinkable that you can provide just these promises that are required by any code that will ever use it. Of course in the current setting, the set of promises of a method is entailed by the signature of that method, hence my String example above. > But looking at the method signature idea: I think if you matched interfaces > based on method signatures, you're talking about having methods which all > have their own (potentially) uniquely generated requirement signature. That > means that every object passed in every parameter would have to be checked to > ensure each object passed had all the right methods. That's a lot of > run-time overhead. It's much simpler just to compare the parameter types > (named interfaces or none) to the interface description to see that they > match the requirements for that method. It would be much, much faster just > doing that, and if you designed the interfaces correctly, you get the same > reassurance. Have you ever considered lazily checking interfaces? Suppose you have a method requiring an argument that implements a certain interface. Instead of checking the interface at the time of the method call, you'd check parts of it when the interface of the argument is used. By this last thing I mean when a method from the interface is actually called on the argument that implements the interface, then you'd check for the existence of the method. Type-checking the arguments to the method call are of course then also lazily done within that method call. Provided that you use all methods from the interface, the interface will be type-checked completely during the call. If you don't use all these methods, it was unnecessary to require them all anyway. Now if you read this carefully, this sounds exactly like any ruby method call. Thus there's no overhead. But if you also provide a way to distinguish between calls to methods from a certain interface and other methods, then you can print the detailed error diagnostics you wanted since you know what interface is involved. Additionally it doesn't seem to imply any runtime overhead except when the interface is actually violated in the sense of a duck typing error. Also if you'd really need more info, you could provide it and make sure all work necessary for that only happens when a method from an interface is actually missing. And I just realized this also works well for the ObjectProxy example... Also I don't see how it can break duck typing in any way since now the only difference lies in error diagnostics. I don't know if I make sense here to you, if I don't, I'll work out an example tomorrow - it's bed time here. I also don't know if you appreciate the difference in how it works. Peter