diff --git a/ChangeLog b/ChangeLog index 89dc9e67c..d580c160c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2010-03-07 Richard Frith-Macdonald + + * Source/Additions/GSObjCRuntime.m: + * Headers/Additions/GNUstepBase/GSObjCRuntime.h: + Add function to add 'overrides' as a form of programmatically + controlled category similar to behaviors, giving an app control + over the order in which methods are added to a class. + 2010-03-05 Richard Frith-Macdonald * Source/Additions/GSCompatibility.h: diff --git a/Headers/Additions/GNUstepBase/GSObjCRuntime.h b/Headers/Additions/GNUstepBase/GSObjCRuntime.h index e1f1aa783..7401b28e3 100644 --- a/Headers/Additions/GNUstepBase/GSObjCRuntime.h +++ b/Headers/Additions/GNUstepBase/GSObjCRuntime.h @@ -116,9 +116,66 @@ GSObjCMethodNames(id obj, BOOL recurse); GS_EXPORT NSArray * GSObjCVariableNames(id obj, BOOL recurse); +/** + *

A Behavior can be seen as a "Protocol with an implementation" or a + * "Class without any instance variables". A key feature of behaviors + * is that they give a degree of multiple inheritance. + *

+ *

Behavior methods, when added to a class, override the class's + * superclass methods, but not the class's methods. + *

+ *

Whan a behavior class is added to a receiver class, not only are the + * methods defined in the behavior class added, but the methods from the + * behavior's class hierarchy are also added (unless already present). + *

+ *

It's not the case that a class adding behaviors from another class + * must have "no instance vars". The receiver class just has to have the + * same layout as the behavior class (optionally with some additional + * ivars after those of the behavior class). + *

+ *

This function provides Behaviors without adding any new syntax to + * the Objective C language. Simply define a class with the methods you + * want to add, then call this function with that class as the behavior + * argument. + *

+ *

This function should be called in the +initialize method of the receiver. + *

+ *

If you add several behaviors to a class, be aware that the order of + * the additions is significant. + *

+ */ GS_EXPORT void GSObjCAddClassBehavior(Class receiver, Class behavior); +/** + *

An Override can be seen as a "category implemented as a separate class + * and manually added to the receiver class under program control, rather + * than automatically added by the compiler/runtime. + *

+ *

Override methods, when added to a receiver class, replace the class's + * class's methods of the same name (or are added if the class did not define + * methods with that name). + *

+ *

It's not the case that a class adding overrides from another class + * must have "no instance vars". The receiver class just has to have the + * same layout as the override class (optionally with some additional + * ivars after those of the override class). + *

+ *

This function provides overrides without adding any new syntax to + * the Objective C language. Simply define a class with the methods you + * want to add, then call this function with that class as the override + * argument. + *

+ *

This function should usually be called in the +initialize method + * of the receiver. + *

+ *

If you add several overrides to a class, be aware that the order of + * the additions is significant. + *

+ */ +GS_EXPORT void +GSObjCAddClassOverride(Class receiver, Class override); + GS_EXPORT NSValue * GSObjCMakeClass(NSString *name, NSString *superName, NSDictionary *iVars); diff --git a/Source/Additions/GSObjCRuntime.m b/Source/Additions/GSObjCRuntime.m index ffac35949..804c96721 100644 --- a/Source/Additions/GSObjCRuntime.m +++ b/Source/Additions/GSObjCRuntime.m @@ -757,30 +757,6 @@ GSProtocolFromName(const char *name) } -/** - *

A Behavior can be seen as a "Protocol with an implementation" or a - * "Class without any instance variables". A key feature of behaviors - * is that they give a degree of multiple inheritance. - *

- *

Behavior methods, when added to a class, override the class's - * superclass methods, but not the class's methods. - *

- *

It's not the case that a class adding behaviors from another class - * must have "no instance vars". The receiver class just has to have the - * same layout as the behavior class (optionally with some additional - * ivars after those of the behavior class). - *

- *

This function provides Behaviors without adding any new syntax to - * the Objective C language. Simply define a class with the methods you - * want to add, then call this function with that class as the behavior - * argument. - *

- *

This function should be called in the +initialize method of the receiver. - *

- *

If you add several behaviors to a class, be aware that the order of - * the additions is significant. - *

- */ void GSObjCAddClassBehavior(Class receiver, Class behavior) { @@ -853,6 +829,55 @@ GSObjCAddClassBehavior(Class receiver, Class behavior) GSFlushMethodCacheForClass (receiver); } +void +GSObjCAddClassOverride(Class receiver, Class override) +{ + unsigned int count; + Method *methods; + + if (YES == class_isMetaClass(receiver)) + { + fprintf(stderr, "Trying to add override (%s) to meta class (%s)\n", + class_getName(override), class_getName(receiver)); + abort(); + } + if (YES == class_isMetaClass(override)) + { + fprintf(stderr, "Trying to add meta class as override (%s) to (%s)\n", + class_getName(override), class_getName(receiver)); + abort(); + } + if (class_getInstanceSize(receiver) < class_getInstanceSize(override)) + { + fprintf(stderr, "Trying to add override (%s) with instance " + "size larger than class (%s)\n", + class_getName(override), class_getName(receiver)); + abort(); + } + + BDBGPrintf("Adding override to class %s\n", class_getName(receiver)); + BDBGPrintf(" instance methods from %s\n", class_getName(override)); + + /* Add instance methods */ + methods = class_copyMethodList(override, &count); + if (methods != NULL) + { + GSObjCAddMethods (receiver, methods, YES); + free(methods); + } + + /* Add class methods */ + BDBGPrintf("Adding class methods from %s\n", + class_getName(object_getClass(override))); + methods = class_copyMethodList(object_getClass(override), &count); + if (methods != NULL) + { + GSObjCAddMethods (object_getClass(receiver), methods, YES); + free(methods); + } + GSFlushMethodCacheForClass (receiver); +} +