Let us consider following classes:
Object subclass: Sup [].
Sup subclass: Sub [ print_superclass [ super class printOn: stdout. ] ].
When I try to run print_superclass method on Sub I get
> Sub new print_superclass.
Sub
I expected here to get Sup because the class call was moved back to the superclass of Sub which is Sup. Why does it behave like this?
Because super is a pseudo-variable pointing to the receiver of the message.
Super and self point to the same object and have the same identity.
super == self ---> true
The difference between them is that super tells the message lookup to start searching the next in the method dictionary "above" that containing the method.
The definition is confusing, but in this case, super only says that the method search for #class does not start in Sub methods, but in Sup methods. However, it does not have effect because #class is defined in a higher level of the hierarchy and its implementation refers to the class of the receiver, that is an instance of Sub
The behavior you get is the expected one. The key is in the semantics of super. Let's see some examples before analyzing your case:
Example 1
ClassA "implements msg"
ClassB "implements msg"
ClassC "implements msg"
This means that the inherited version of msg is overridden in ClassB and ClassC. In this case
super msg "sent from ClassC invokes ClassB >> msg"
super msg "sent from ClassB invokes ClassA >> msg"
super msg "sent from ClassA will signal MessageNotUnderstood"
(I'm assuming msg is not implemented above ClassA)
Example 2
ClassA "implements msg"
ClassB "does not implement msg"
ClassC "implements msg"
Then
super msg "sent from ClassC invokes ClassA >> msg"
super msg "sent from ClassB invokes ClassA >> msg"
Example 3
ClassA "implements msg"
ClassB "does not implement msg"
ClassC "does not implement msg"
Here
super msg "sent from ClassC invokes ClassA >> msg"
super msg "sent from ClassB invokes ClassA >> msg"
So, the semantics of super is: start the lookup in my superclass.
Your case
Yo have
Object "implements class"
Sup "does not implement class"
Sub "does not implement class"
Therefore, when you send super class from Sub it will invoke Object >> class, right? Which is the same as sending self class (because class is not implemented in Sub), which is Sub. And since Sub new print_superclass sends super class from Sub, you get Sub.
Related
So I have a category on NSObject called CustomCategory, as following:
#import <Foundation/Foundation.h>
#interface NSObject (CustomCategory)
-(BOOL)doSomething;
#end
#import "NSObject+CustomCategory.h"
#implementation NSObject (CustomCategory)
-(BOOL)doSomething
{
NSLog(#"Done");
return NO;
}
#end
Ideally, this will work on an object like this:
NSObject* object = [NSObject new];
[object doSomething];
However, I found that it also works in this way with no problem:
[NSObject doSomething];
So I am wondering, since it is an instance method I have added through the category, why it also works on a Class?
Instance methods on NSObject are also class methods on NSObject.
This works because of the way Objective-C does dynamic dispatch. If you send a message to any object the method implementation is looked up in the objects class. If you send a message to a class then you are sending a regular message to the class object. There the implementation is looked up in the so called meta-class. The meta-classes are automatically generated by the compiler. Class methods are just instance methods of the meta-class. This is handled transparently by the compiler.
Inheritance also works on the meta-class level. So the meta-class for a class inherits from the meta-class of its superclass. We have two parallel inheritance hierarchies there. Only root classes like NSObject are handled differently. There the meta-class can't inherit from the meta-class of the superclass as there is no superclass. For root classes the meta-class inherits from the root class itself.
And since class methods of a class are instance methods of its meta-class and NSObjects meta-class inherits from NSObject itself instance methods on NSObject are also class methods on NSObject.
For reference to anyone looking for the actual location of this in the runtime source, it currently resides in objc-runtime-new.mm's methodizeClass function:
... snip...
// Root classes get bonus method implementations if they don't have
// them already. These apply before category replacements.
if (cls->isRootMetaclass()) {
// root metaclass
addMethod(cls, SEL_initialize, (IMP)&objc_noop_imp, "", NO);
}
... snip ...
... And the +initialize method of a meta-class will add all of the method implementations from its instance and convert them into a class method.
And, contrary to what #Sven has been saying, NSObject's meta-class is not actually NSObject. A class always has a separate meta-class in the runtime, regardless of whether it is root or not.
Every Class in Objective C is internally an object, which means it's a subclass of NSObject.
I have the following protocol and class to start with...
#protocol AnimalProtocol <NSObject> // this will be my global interface
#interface Animal : NSObject // and a super class
#interface Animal () <AnimalProtocol> // take note, I hid the protocol in .m file
Now I have an AnimalList class with the addAnimal() method...
#interface AnimalList : NSObject
+ (void)addAnimal:(Animal <AnimalProtocol> *)animal;
Now say if I subclass Animal, e.g. Reptile...
#interface Reptile : Animal
If I try to add an instance of Reptile using the addAnimal() method like so,
Reptile *lizard = [[Reptile alloc] init];
[AnimalList addAnimal:lizard];
it will generate a warning..
"Incompatible pointer types sending "Reptile *" to parameter of type "Animal *"
which is true since I hid the protocol on the super class Animal. In order to remove this warning I need to include the protocol declaration on my Reptile class as well OR show the AnimalProtocol on the .h of Animal class.
My question is, how do I generate a programmatic version of the GCC warning mentioned? I would like my addAnimal() method to be really strict and if Reptile class didn't include that protocol, I would like to throw an exception.
Note: I have tried
[[lizard class] conformsToProtocol:#protocol(AnimalProtocol)]
but it didn't work. It knew, that Reptile is a subclass of Animal which "invisibly" implements AnimalProtocol. But the GCC warning was able to detect it. So I would like to know how to do this programmatically.
I have tried and failed to find a way in Pharo to find if a specific class instance has specific class as super class. By super class I am not referring only on the class that is a subclass of, but also all other classes that are up its inheritance line.
I thought that there would be a message in Object >> isSubclassOf: but alas i cant located such message
I'm not clearly sure what do you want to find, but if you want to see if anObject is and instance of aClass or it's superclasses, you can use:
anObject isKindOf: aClass
If you want to see if anObject (class) inherits from aClass, then you use:
anObject inheritsFrom: aClass
Only a class can be the subclass of another class. Thus you must first get the class of your object:
String inheritsFrom: Collection "prints: true"
'Pharo is cool' class inheritsFrom: Collection "prints: true"
This is most easily explained with a brief example. Let's say I have the following protocol and class definitions:
#protocol ProtocolA <NSObject>
#optional
+ (BOOL)methodA;
#end
#interface ClassA : NSObject <ProtocolA>
#end
ClassA may or may not define methodA. If I was working with an instance of ClassA and an instance method, I could test the instance with respondsToSelector:. In this situation, however, I cannot think of any clean way to determine if ClassA defines (responds to) methodA.
EDIT:
I was silly and did not make my example specific enough, which meant the answer to the question was not exactly the solution to my problem -- so I am including a bit more code and the warning I am getting:
Class <ProtocolA> classRef = [ClassA class];
if([classRef respondsToSelector:#selector(methodA)]) {}
The above code throws the following warning:
" Instance method 'respondsToSelector:' found instead of class method 'respondsToSelector:'"
I only just now noticed that if I explicitly cast classRef to (Class) then the warning goes away. I still find that odd.
[[instance class] respondsToSelector:#selector(methodA)]
Every instance of a class has a pointer to it's class object which can be retrieved by calling class. This object (classes are objects in Objective C) can be probed with respondsToSelector: just like any other object.
I have ClassA and ClassB. Now i want to call a method of ClassA in ClassB.So i imported ClassA in ClassB and created an object of it and called that method.Now i want to call method of classB in classA. How can i do that.
I assume your fundamental issue is a cyclic import. The answer to this is stop importing in your header file. If ClassA needs to call something from ClassB, then #import "ClassB.h" should be added to ClassA.m, not to ClassA.h. Same thing if ClassB needs to call something in ClassA. If ClassA needs to reference ClassB in its header (e.g. a property of type ClassB) then you can forward-declare the class using
#class ClassB;
at the top of your ClassA.h. This tells the compiler that there exists a class named ClassB, and that you will tell it what that class is at some later time.