[comp.sys.next] Deferred methods and strong typing

jacob@gore.com (Jacob Gore) (07/05/89)

Consider a class that has a deferred method:

  A.h:
	#import <objc/Object.h>
	@interface A:Object {...}
	- (A*)someMethod;
	...
	@end
  A.m:
	#import "A.h"
	- (A*)someMethod { return [self subclassResponsibility]; }

and a subclass that implements that method:

  B.h:
	#import "A.h"
	@interface B:A {...}
	- (B*)someMethod;
	...
	@end
  B.m:
	#import "B.h"
	- (B*)someMethod { ... actual implementation ... }

Now, consider the use of someMethod:

  C.m:
	#import "B.h"
	...
	[anInstanceOfB someMethod];

Intuition tells me that B's someMethod is to be used.  But the compiler in
0.9 gives a "multiple declarations for method `someMethod'" warning, and
then uses A's someMethod.

What's the scoop?

--
Jacob Gore	Jacob@Gore.Com		{nucsrl,boulder}!gore!jacob

andyn@stpstn.UUCP (Andy Novobilski) (07/07/89)

From the article with Jacob Gore's question about the "multiple declarations
for method `someMethod`" warning, consider the two .h interface files:

A.h
    #import ...
    @interface A : Object ..

       -(A *)someMethod;
    @end

B.h
    #import "A.h"
    @interface B : A ...

       -(B *)someMethod;
    @end

Then usage in 

C.m 
    #import "B.h"
    ...
    [anInstanceOfB someMethod];


One piece of information missing is the declaration of 'anInstanceOfB'.
The warning will be given by the compiler if 'anInstanceOfB' is declared
type 'id'.  This is because the compiler sees both interface files and
the fact the programmer has deferred binding until runtime (type id).  The
compiler then choses the first interface as the default (notice the order
of @interface statements based on "#import" ordering).

Correct type information can be given to the compiler by:

1) Typing the method:
   [(B *)anInstanceOfB someMethod];

2) Declaring anInstanceOfB to be type B:
   B *anInstanceOfB;

Hope this helps.

Andy Novobilski
andyn@stepstone.com

The Stepstone Corp. (The Objective-C People)
75 Glen Rd.
Sandy Hook, CT 06770
(203)426-1875

dml@esl.UUCP (Denis Lynch) (07/07/89)

In article <130007@gore.com> jacob@gore.com (Jacob Gore) writes:
>Consider a class that has a deferred method:
>  A.h:
>	#import <objc/Object.h>
>	@interface A:Object {...}
>	- (A*)someMethod;
>and a subclass that implements that method:
>  B.h:
>	#import "A.h"
>	@interface B:A {...}
>	- (B*)someMethod;
>Now, consider the use of someMethod:
>  C.m:
>	#import "B.h"
>	[anInstanceOfB someMethod];
>
>the compiler in
>0.9 gives a "multiple declarations for method `someMethod'" warning, and
>then uses A's someMethod.
>
>What's the scoop?

The problem is philosophically thorny, but solving it is easy. Remember that
Objective C insists on one system-wide template for each message selector.
That is, if one class has a method (int)lifeTime then all lifeTime messages
must return (int).

Your example has introduced two definitions for someMethod: one says it will
return (A*) and one says (B*). This violates Objective C's ground rules.

Philosophically your example makes sense, since indeed all Bs are As, so
B's definition of someMethod is consistent with A's, just more specific.
It would seem that Objective C doesn't analyse this case as carefully as
you did, so it missed the subtlety.

You shouldn't have any trouble if you just change the defintion of B's
someMethod to (A*). Returning a B will be legal (since Bs are As), and
the Objective C method definition things won't get in the way.

Good luck!

-- 
Denis Lynch                          
ESL Incorporated                         decwrl!borealis!\
ARPA: dml%esl.ESL.COM@ames.arc.nasa.gov    ucbcad!ucbvax!- ames!- esl!dml
SMAIL: dml@esl.ESL.COM                                  lll-lcc!/

jacob@gore.com (Jacob Gore) (07/07/89)

/ comp.sys.next / andyn@stpstn.UUCP (Andy Novobilski) / Jul  6, 1989 /

> One piece of information missing is the declaration of 'anInstanceOfB'.
> The warning will be given by the compiler if 'anInstanceOfB' is declared
> type 'id'.  This is because the compiler sees both interface files and
> the fact the programmer has deferred binding until runtime (type id).  The
> compiler then choses the first interface as the default (notice the order
> of @interface statements based on "#import" ordering).
> 
> Correct type information can be given to the compiler by:

This is the one I used:

> 2) Declaring anInstanceOfB to be type B:
>    B *anInstanceOfB;

That is where the error happened.  I don't think the compiler should have
chosen the 'someMethod' declared in class A over the one declared in class B. 

If I left 'someMethod' as type id in both the subclass (B) and the
superclass (A), the subclass's method would overrule the superclass's
method of the same name (the essense of Objective C's method inheritance
mechanism, right?).  However, once type information is provided for the
subclass and the superclass, the compiler decides that they are not the
same method at all, and proceeds to choose the first one it encounters,
which, by convention (since a subclass imports its superclass's interface),
is the superclass's method.  Not nice.

> 1) Typing the method:
>    [(B *)anInstanceOfB someMethod];

This should not be necessary.  Strong typing should not break the
inheritance chain.  For now, I declare 'someMethod' in class B as returning
(A*) instead of (B*), but hey... something is wrong here!

--
Jacob Gore	Jacob@Gore.Com		{nucsrl,boulder}!gore!jacob

dml@esl.UUCP (Denis Lynch) (07/08/89)

In article <3312@stpstn.UUCP> andyn@stepstone.com (Andy Novobilski) writes:
>
>Correct type information can be given to the compiler by:
>
>1) Typing the method:
>   [(B *)anInstanceOfB someMethod];
>
>2) Declaring anInstanceOfB to be type B:
>   B *anInstanceOfB;

Isn't it true that the warning is generated because of the *declaration* of
someMethod, not its use? (Of course the run-time problem happens because of
the use).

This seems to be pretty much required because of the *possibility* of
dynamic binding: the compiler needs to be able to figure out what someMethod
will return under any circumstances, especially since common usage is to
type everything as id.

(I know I could go try this on my machine, but it's in another room...)

This seems to be one of the prices to be paid for using dynamic binding in
a language that doesn't fully support it. In Smalltalk there is no such
problem, since someMethod will return whatever it wants. In C we don't have
that luxury.


-- 
Denis Lynch                          
ESL Incorporated                         decwrl!borealis!\
ARPA: dml%esl.ESL.COM@ames.arc.nasa.gov    ucbcad!ucbvax!- ames!- esl!dml
SMAIL: dml@esl.ESL.COM                                  lll-lcc!/

jacob@gore.com (Jacob Gore) (07/09/89)

/ comp.sys.next / dml@esl.UUCP (Denis Lynch) / Jul  7, 1989 /
> Isn't it true that the warning is generated because of the *declaration* of
> someMethod, not its use? (Of course the run-time problem happens because of
> the use).

Yes, but the two problems are related: because (B*) is not recognized as a
subtype of (A*), the method in class B is treated as an alternative to the
one in class A, instead of being treated as its replacement (for instances
of B and of its subclasses).

> This seems to be pretty much required because of the *possibility* of
> dynamic binding: the compiler needs to be able to figure out what someMethod
> will return under any circumstances, especially since common usage is to
> type everything as id.

But subtyping is implemented correctly in at least some cases.  For
example, you can do:

	@implementation B:A
	...
	(A*)someMethod {
		...
		return self;
	}

Even though the return value is of type (B*), it is (correctly) understood
to match the declared return type, (A*).

So it doesn't look like a language problem (I was worried for a while that
the concept of subtyping was omitted altogether, and was quite relieved to
find out otherwise), but just a compiler bug.

Does the Stepstone compiler exhibit the same problem, or is it limited to
the 0.9 version of NeXT's compiler?  (If I understand the docs correctly,
they are no longer the same beast.)

--
Jacob Gore	Jacob@Gore.Com		{nucsrl,boulder}!gore!jacob