views:

1288

answers:

4

In Java, it is very easy to code the following design:

public abstract class Pizza {
    public static final Pizza.NULL = new Pizza() {
        /* "null" implementations */
    }

    /* actual/abstract implmentations */
}

What is the preferred method to attain the same efficient scenario in Objective-C? I have been unable to find any documentation on the subject, and I have tried a couple different scenarios with static const, #define etc. but none of them seem to work out as well as the Java method above.

I would like to avoid writing a concrete NullPizza class that has a static method to obtain the singleton instance, as it seems more 'proper' for it to be some final property/field of the highest-level interface. (Pizza, in this case.)

Edit: While I understand how the NULL pattern specifically would be handled due to Obj-C's unique method of handling method calls to 'nil', what about other static common instances, such as Response.YES and Response.NO? (See comments for discussion.)

+7  A: 

There is no need for this type of pattern in Objective-C because it is not considered a runtime error to message a nil instance of a class. If the method has a defined return type, there are defined returns from messaging a nil object (e.g., methods that return an integer return 0 when messaging a nil object).

Jason Coco
That's true, I was simply using the NOP as an example. What would you do in a situation where there are two default implementations of a class, say Response, and you wanted a Response.YES and a Response.NO that were static, final implementations?
craig
just create factory methods which return those instances, as +[NSDecimalNumber zero] and +[NSDecimalNumber one] do. BTW there's no 'final' in ObjC.
Graham Lee
That was my initial plan, but how do you ensure that the instance returned is not modified? The instance should be a singleton, so you aren't wasting memory returning a new instance every time, but if every call to [Pizza null] returns the same reference, couldn't that object be altered?
craig
In ObjC, how were you planning to actually use whatever object [Pizza null] might return? Really, the point is that there is no actual need for a null pizza instance like there is in Java.
Jason Coco
Again though, take the Response example. If [Response yes] returns a particular singleton instance, how can I ensure (since this instance is shared throughout the app) that none of its properties will be changed? Will I have to write a ResponseNo class and override the setters? This seems tedious.
craig
You can make all the properties of the Response object read only and set the yes/no attribute in the init method. That way your singleton instance cannot be modified and neither can its child attributes.
Naren
+1  A: 

There are two things which can help here. The first is nil, the Objective-C equivalent of the Java NULL pointer - it can actually receive messages and respond to them. It will always return nil if the return value is an object, and 0 if the return value is some primitive type. Therefore if the Null behaviour of your object is "do nothing" you can easily just use nil as the Null value.

The other thing which is helpful is for when you need to store a placeholder or null value in a container object - these usually throw exceptions if you attempt to add nil as a value. Instead you can use the singleton +[NSNull null], which does nothing except act as a "this space intentionally left blank" object.

With these two weapons at your disposal there should be no reason to write a null instance of a custom class :-)

Graham Lee
See comment to Jason. :)
craig
see my comment in reply to your comment :-) and now let's leave the meta-thread... ;-)
Graham Lee
A: 

For your Response.YES and Response.NO, I assume you have instances that you do want to change, rather than just making all Response properties read-only.

A common pattern in Cocoa is to have both immutable and mutable versions of a class (NSArray versus NSMutableArray). For your response example, it would make sense to have an immutable Response class that has the static YES and NO methods, and a MutableResponse subclass that exposes setters for those times where you do want objects to change them. Does this cover your second example?

JimG
A: 

I don't think there is an easy way to provide this implementation. You're asking for something that is a language feature of Java to be implemented in Objective-C - you can do it but you have to write the code that is in the Java runtime yourself - there is nothing to stop you doing this but it's not something the language has built in.

It's a bit like asking "How do I show a Windows style 'one menu per window" UI in Cocoa' - you can do it but it's not provided for free from the framework. Or, "how can I easily implement Objective-C's nil pointer handling in Java?"

If you really want to see this type of functionality I think you should follow the NSArray/NSMutableArray design pattern. Declare a superclass that can handle all of your special cases:

@interface NullPizza : NSObject
{
}
- (BOOL)areYouANullPizza;
@end

and then subclass with your real Pizza and include a newNullPizza class method (which is just syntax sugar):

@interface Pizza : NullPizza
{
}

+ (Pizza*)Null;
@end

@implementation Pizza
+ (Pizza*)newNullPizza
{
    return [[NullPizza]alloc init]; // Singleton code left as an exercise.
}

- (BOOL)areYouANullPizza;
{
    return NO;
}
@end

Note that if you wanted to implement a +(Pizza*)NULL method on Pizza you should autorelease the new NullPizza you create.

Disclaimer, I typed this code straight into SO. I'd be surprised if it compiles but you get the idea.

Roger Nolan