| Exploring Solution Spaces © Copyright 2003-2006, by C. Keith Ray | ||||||||||||||||||||||||
|
Archives
Subscribe |
2006.Jan.06 Fri I think Martin Fowler's "Implicit Interface Implementation" is just what Java, C#, and C++ need -- a way to get polymorphism without inheritance, when there isn't already an explicitly-declared capital-I Interface. Ironically, there is an explicitly declared small-i interface declared - the class interface. Quote:
I predict that if there is enough discussion of this in the blogosphere, Microsoft will add it into C#; Sun would add it to Java only if Microsoft adds it to C#; C++ will never have it. Somewhat related to this is one of Robert Martin's Principles of Object-Oriented Design: "The Interface Segregation Principle", which says "Clients should not be forced to depend on methods that they do not use. Interfaces belong to client, not to hierarchies." In a dynamic system like Smalltalk, Ruby, or Python, we don't need explicit interfaces, so "The Interface Segregation Principle" doesn't seem to apply. In static systems like Java and C++, one could declare interfaces specific to each client, but it seems that few people do. The principle seems to more about dependency-breaking than anything else. I'd be interested in hearing from people who have actually done this extensively. By the way, Objective-C, the language used for Cocoa programming on MacOS X, has three ways of dealing with interfaces. One is the 'duck typing' approach - no inheritance, no explicitly defined interfaces, no compile-time checking. Example: @interface Duck : NSObject -(id) init; -(void) dealloc; // called indirectly through release. -(void) quack; // the class method 'alloc' is inherited from NSObject. @end @implementation Duck //etc... @end //class DuckCall declared similarly. id duck = [[Duck alloc] init]; [duck quack]; [duck release]; duck = [[DuckCall alloc] init]; [duck quack]; [duck release]; The next way is with an explicit interface, called a protocol. A class declared to conform to a protocol must implement all the methods in that protocol. (And additional syntax to allow distributed objects can optionally specify that method parameters are 'in', 'out', 'inout', 'bycopy', or 'byref'.) You compile-time checking with protocols. @protocol Quackable -(void) quack; @end @interface Duck : NSObject < Quackable > -(id) init; -(void) dealloc; // called indirectly through release. -(void) quack; // the class method 'alloc' is inherited from NSObject. @end @implementation Duck //etc... @end // class duck-call declared similarly id < Quackable > duck = [[Duck alloc] init]; // The compiler warns us [duck quack]; // if Duck isn't Quackable. // you can also confirm at run-time that an object implements a protocol: assert([duck conformsToProtocol:@protocol(Quackable)]); [duck release]; duck = [[DuckCall alloc] init]; [duck quack]; [duck release]; The third way to declare an interface, where implementing its methods is optional, is via a 'category'. This is often used in Cocoa where a user-interface object has an optional delegate. The delegate may implement one or more methods that the user-interface object will call (if the method exists) at particular times. This avoid having to subclass user-interface objects. It's similar to implementing a "Listener" class for the Java Swing framework.
@interface NSObject ( Quackable )
-(void) quack;
@end
// Duck and DuckCall classes are declared like the first example.
NSObject* duck = [[Duck alloc] init];
if ( [duck respondsToSelector:@selector(quack)] )
{
[duck quack];
}
[duck release];
duck = [[DuckCall alloc] init];
if ( [duck respondsToSelector:@selector(quack)] )
{
[duck quack];
}
[duck release];
The value of informal protocols in Objective-C is that the method-argument-types and returns are type-checked by the compiler. So if a "fly:to:" method took arguments of double and NSPoint, the compiler could detect if you used the wrong types in making that call -- and since neither double nor NSPoint are object types, it's essential that the types be correct to avoid a crash from passing parameters of the wrong size. While it would be nice to have Objective-C be able to declare that a class has the same interface as an existing class without having to make a separate protocol declaration, the "duck-typing" built into the language lets us use implicit interfaces and informal interfaces fairly easily, with some compile-time checking (for argument and return types) and the same run-time checking that Ruby and Smalltalk have. |
|||||||||||||||||||||||