This is the crux of the matter: the compiler does not know the class it's being passed -- it doesn't need to; the structure it cares about is constant.
This is simply untrue. Consider the following code:
- (void) foo: (NSView*) v {}
- (void) barResponder: (NSResponder *) r view: (NSView *) v button: (NSButton *) b {
[self foo: r];
[self foo: v];
[self foo: b];
}
The first call to foo: raises a warning (passing argument 1 of 'foo:' from distinct Objective-C type) while the other two pass silently. The compiler is well away of the class of objects, and of the class hierarchy. Now it may well be the case that the recipient does not care, and can indicate so by typing the parameter as 'id' rather than 'Foo*', but that's a very different thing to the compiler not knowing that class.
As for SEL and IMP, do look at methodForSelector:. We already can have the caching technique and eat it, too. And we don't have to sacrifice dynamicness for it. Let us go on without premature optimization.
I think you are missing the point I was making. If we are going to have some sort of operator overloading then, to satisfy exactly the sort of polymorphic behaviour that you were describing, you want to be able to attempt to pass any class as the operand. That said, the behaviour of an operator is likely to differ depending on the type of the operand (e.g. multiply my polynomial by (a) a rational number or (b) another polynomial, but never allow (c) an NSWindow, because that would be meaningless).
We have a choice here; we can just require ever implementation of every operator to contain some sort of switch code to find the right behviour, we can define some sort of class hierarchy based run-time matching to find a 'best match' message name or we can do that same sort of matching and perform as much of that matching as possible at compile time.
The first option is dreadfully inefficient (since the switch will run every time). The second option could have some sort of built-in caching, though it would be a different type of caching to the existing methodForSelector: cache since it would have to understand the class hierarchy of the operand as well as the recipient. The third option could be done at compile time, which has the added advantage of allowing the compiler to raise a warning if there is no known matching selector.
There is actually a forth option, which might give the best of both worlds, which would be to implement option 2 and option 3, performing the lookup (and caching it) at runtime but performing a static check at compile time to allow for warnings. This is akin to the current arrangement where sending a random message to an object can raise a compiler warning but may well work at run-time. Now that I think about it, I think that this is the plan I shall try to implement!
by Nicko — Sep 23
This is simply untrue. Consider the following code:
- (void) foo: (NSView*) v {} - (void) barResponder: (NSResponder *) r view: (NSView *) v button: (NSButton *) b { [self foo: r]; [self foo: v]; [self foo: b]; }
The first call to foo: raises a warning (passing argument 1 of 'foo:' from distinct Objective-C type) while the other two pass silently. The compiler is well away of the class of objects, and of the class hierarchy. Now it may well be the case that the recipient does not care, and can indicate so by typing the parameter as 'id' rather than 'Foo*', but that's a very different thing to the compiler not knowing that class.
As for SEL and IMP, do look at methodForSelector:. We already can have the caching technique and eat it, too. And we don't have to sacrifice dynamicness for it. Let us go on without premature optimization.
I think you are missing the point I was making. If we are going to have some sort of operator overloading then, to satisfy exactly the sort of polymorphic behaviour that you were describing, you want to be able to attempt to pass any class as the operand. That said, the behaviour of an operator is likely to differ depending on the type of the operand (e.g. multiply my polynomial by (a) a rational number or (b) another polynomial, but never allow (c) an NSWindow, because that would be meaningless).
We have a choice here; we can just require ever implementation of every operator to contain some sort of switch code to find the right behviour, we can define some sort of class hierarchy based run-time matching to find a 'best match' message name or we can do that same sort of matching and perform as much of that matching as possible at compile time.
The first option is dreadfully inefficient (since the switch will run every time). The second option could have some sort of built-in caching, though it would be a different type of caching to the existing methodForSelector: cache since it would have to understand the class hierarchy of the operand as well as the recipient. The third option could be done at compile time, which has the added advantage of allowing the compiler to raise a warning if there is no known matching selector.
There is actually a forth option, which might give the best of both worlds, which would be to implement option 2 and option 3, performing the lookup (and caching it) at runtime but performing a static check at compile time to allow for warnings. This is akin to the current arrangement where sending a random message to an object can raise a compiler warning but may well work at run-time. Now that I think about it, I think that this is the plan I shall try to implement!