Objc, cannot cast 'super' error

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Objc, cannot cast 'super' error

Dave Keck
Hey list,

Clang doesn't allow super to be casted; I'd like to present my
use-case demonstrating why I think this should be allowed, or get some
feedback on why Clang is right and my design is wrong:

I have two classes, ClassA and ClassB. ClassB inherits from ClassA,
and ClassB alone implements MyProtocol:

    @protocol MyProtocol
    - (void)handleToken: (id)token;
    @end

The contract for MyProtocol is that if you don't recognize 'token',
you send -handleToken: to super. If no superclass implements
-handleToken:, then a runtime exception is correctly generated since
no one could handle the token. (This is exactly the same as KVO's
-observeValueForKeyPath: contract.)

ClassB's implementation of -handleToken: triggers the "'ClassA' may
not respond to 'handleToken:'" warning on the call to super:

    - (void)handleToken: (id)token
    {
        if (token == myToken)
            ... handle token ...
        else
            [super handleToken: token];
    }

Without the ability to cast super, I have the following options, none
of which are optimal:

    1. Add the following code to ClassB.m:

        @interface ClassA (Stub) <MyProtocol>
        @end

       This option is bad because it'll need changing if ClassB's
superclass changes, and will have to be separated from the code that
triggers the warning.

    2. Omit the [super handleToken: call], since (at present) no other
superclass actually implements -handleToken:.

        This option is bad because it'll break if a superclass starts
implementing -handleToken:.

    3. Make MyProtocol an informal protocol on NSObject instead.

        This option is bad because a formal protocol is the correct
abstraction for my use-case.

    4. Use objc_msgSendSuper directly.

        This option is just ugly and inconsistent with the rest of my code.

Why is my design wrong?

Thanks!

David
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Objc, cannot cast 'super' error

David Chisnall-2
On 3 Jul 2011, at 12:15, Dave Keck wrote:

>    3. Make MyProtocol an informal protocol on NSObject instead.
>
>        This option is bad because a formal protocol is the correct
> abstraction for my use-case.


No it isn't.  If you are explicitly sending messages that a class does not respond to then an informal protocol is exactly what you want.  

Note that there is nothing stopping you from using both a formal and informal protocol, if you wish for explicit testing.

Using these exceptions is very bad style for several reasons:

1) Exceptions in Objective-C are intended to indicate programmer error and are very slow.  Using them for a recoverable error is bad.

2) You are overloading the meaning of an exception, making it difficult to distinguish between a real error and this error.

3) Code that assumes 1) (i.e. most Cocoa code, including code compiled with ARC enabled) will leak memory if it's in any intervening stack frames.

If you really must use exceptions, a better way of doing it would be something like:

@implementation NSObject (MyProtocol)
- (void)handleToken: (id) token
{
        NSString *reason = [NSString stringWithFormat: @"Unhandled token %@", token];
        NSDictionary *userInfo = [NSDictionary dictionaryWithObject: token
                                                             forKey: kMyProtocolUnhandledToken]
        [[NSException exceptionWithName: MyProtocolUnhandledTokenException
                                 reason: reason
                               userInfo: userInfo] raise];
}
@end

This would then ensure that you had a meaningful exception to catch, rather than doing something ugly and hackish.  

David

--
This email complies with ISO 3103
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Objc, cannot cast 'super' error

Dave Keck
Hi David,

> No it isn't.  If you are explicitly sending messages that a class does not respond to then an informal protocol is exactly what you want.

I consider informal protocols as workarounds created before formal
protocols supported @optional methods, which is why I avoided option
3. Am I wrong in that assessment?

> Note that there is nothing stopping you from using both a formal and informal protocol, if you wish for explicit testing.

I ended up doing something close to that; I still have the mentioned
MyProtocol, but also MyCategory on NSObject that implements MyProtocol
as the base case, by simply throwing a custom exception as you
describe. A much cleaner approach indeed, and it gets rid of the
warning.

> Using these exceptions is very bad style for several reasons:
>
> 1) Exceptions in Objective-C are intended to indicate programmer error and are very slow.  Using them for a recoverable error is bad.
>
> 2) You are overloading the meaning of an exception, making it difficult to distinguish between a real error and this error.
>
> 3) Code that assumes 1) (i.e. most Cocoa code, including code compiled with ARC enabled) will leak memory if it's in any intervening stack frames.

I consider my use of exceptions to be in-line with what you describe:
some programmer made an error and isn't handling a token as they
should.

Thanks for your insight!

David

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev