3

Actually I am from java background and I am learning objective c.I am very confused about strange behaviour of objective C."Please Read 3rd Question its important one."

Questions are provided in sequence so please give answers in sequence as its understandable to me and others.

Question 1
I have two classes derived from NSObject: A and B:

@interface A : NSObject 
@end                               

@interface B : NSobject
-(void)display; // It displays "I am class B"
@end

Now if I do this:

A *a = [[B alloc]init]; // Show warning not error (it must be illegal)
[a display];            // prints "I am class B"

It calls the display method of class B. I don't think that it should happen because:

  1. A doesn't have the method display. By polymorphism.

  2. This could be a security threat as I am creating reference of any class and passing object of any another class and accessing data by it.

  3. There could be design issues as Dog class instance gets an object of Printer class and now i am calling print method on Dog instance.

  4. I have reference of NSArray and passed object of NSMutableArray and now i am calling NSMutableArray method on this instance.

    [nsarr addObject:@:abc]; //Looking very odd

Question 2
If I have Foo protocol and if any class is not confirming it. It should not be allowed to get object of that class in protocol reference.

@protocol Foo
@required
-(void)abc;
@end    

If i call:

id<Foo> obj= [[B alloc]init]; // Shows warning ignore it for now as it must be illegal also
[obj display];                // It will call display method which should be illegal  
  1. It should not happen, as B is not conforming to protocol Foo and obj is taking B object and calling B instance method. I think its very bad because of polymorphism and security

Question 3
If my class has a class method which returns an object of that class which is not autoreleased, the compiler shows warning. If I pass the object returned by that class (not conforming protocol) method to reference of protocol. (IT SHOULD BE AN ERROR).

id<Foo> obj = [Abc aClassMethodReturnsObjectWhichNotAutoreleased]; //show warning

It shows a warning which is good. Abc did not conform to the protocol Foo

BUT

id<Foo> obj = [NSArray arrayWithObjects:@"abc",@"def",nil]; // It does **not** show a warning as it will return autorelease object. NSArray doesn't conform protocol Foo

Why does the above assignment to the NSArray class not show a warning as it is showing in the previous example.

Thanks in advance.

EDIT

*Answer 3rd Question:*As NSArray returns id object which will allow to pass in "id obj" but in "aClassMethodReturnsObjectWhichNotAutoreleased" case the method returns "ABC *" pointer so that is why compiler giving warning in this case.

codester
  • 36,891
  • 10
  • 74
  • 72
  • Hi Sahil, welcome to SO. You will most likely get better quality answers if you separate this question into three different questions so that people who answer can focus on one topic at a time. – lnafziger Nov 10 '12 at 15:27

3 Answers3

2

Objective-C and Java have very different type rules, as you have discovered.

Java is strictly statically typed, which means that types must match, and you can never make an assignment that is not allowed by the type conversion rules.

Objective-C is dynamically typed with optional static types. You can break out of the type system at any time. For some cases, the compiler will emit warnings, but it is still allowed.

This is the reason why you are seeing the behavior. Objective-C is not broken, it just have different rules than the ones you know from Java.

Apple has a lot of documentation of the specific rules, perhaps you would want to read Enabling Static Behavior.

Here are some more resources about dynamic vs static typing for you:

Dynamic type languages versus static type languages and What do people find so appealing about dynamic languages?

Community
  • 1
  • 1
driis
  • 161,458
  • 45
  • 265
  • 341
  • 1
    I don't understand - was the comment meant as a question ? In that case **yes**, some of the static typing safety you know from Java is lost in Objective-C. But the dynamic typing enables more dynamic behavior than what is allowed in a static language. It is a tradeoff - the Objective C designers choose dynamic typing. – driis Nov 10 '12 at 14:54
2

Question 1:

A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display];  //prints "I am class B"

Here you are using a static type A for the variable named a. You are then assigning a different type of object (B) to the variable.

Unlike java, Objective-C does not enforce the static typing requirement, however it does warn you when it is being compiled since the compiler detected a difference between the declared type and the actual type of the object. It happily stuffs the B object into your variable though, so a is now pointing to the B object that you created. Once the program is compiled and running (at run-time), A *a is treated the same as id a.

Another feature of Objective-C is that you can send any message to any object at any time. This is part of the dynamic nature of Objective-C. Obviously there are cases where sending the wrong message to an object can cause bad things (tm) to happen so you need to ensure that you only send appropriate messages. There are various functions that can test the class of an object at run-time, or even test to see if it is able to handle a particular message before you send it in order to prevent the bad things. If you are using static typing (like in this example) then the compiler will issue warnings to tell you that you may have made a mistake and should review the code.

Question 2:

This is actually very similar to question 1. The compiler is warning you that you are assigning what appears to be an incorrect value to the variable, however at run-time you can send any message to any object, so it will work on the actual object instead of the "expected" object from the type declaration.

Question 3:

Good question. I would have thought that you would get a warning there too. Maybe someone else can help out on that. My first thought is that this is a bug and should be reported as such, but there may be a reason for it that I'm not aware of....

lnafziger
  • 25,760
  • 8
  • 60
  • 101
  • @Inafziger Thanks for your solution.Can you please provide some reference where i can get more detail – codester Nov 10 '12 at 16:56
  • Actually, @driis provided a very good link (Enabling Static Behavior) that talks about this. Let me know if you need more info than that. – lnafziger Nov 10 '12 at 17:04
1
A *a = [[B alloc]init]; //Show warning not error (it must be illegal)
[a display];  //prints "I am class B"

Because you initialized variable from B class that have display property. It's correct

NeverBe
  • 5,213
  • 2
  • 25
  • 39
  • The Object B was only assigned to the Variable A which carry the object B arround. That is the reason a can display it – Vinh Nov 10 '12 at 14:50
  • @NeverBe But you don't have display method in A class and you are passing message display to A class which do not implement it.That is illegal and A and B do not have any relationship. – codester Nov 10 '12 at 14:57
  • `a` is not an instance of class A—looking at its value, you can see that it is an instance of class B. Assigning that to the `a` variable is a little like calling a cat a dog. You can call it a dog all you want, but it's still going to meow. (And yes, it's confusing to call a cat a dog. That's why the compiler warned you against it.) – andyvn22 Nov 10 '12 at 15:01
  • @SahilWasan objc have more flex syntax: id obj = [B new]; [obj display]. It will work – NeverBe Nov 10 '12 at 15:10
  • @andyvn22 compiler is just warning me but at run-time its executing "meow" on "dog" instance and acording to me it must be an error because you can not execute "meow" on "dog" instance which do not implement it and "dog" do not have any relationship to cat. – codester Nov 10 '12 at 15:11
  • @NeverBe yes it will work and but as programmer i know that its id object and i have to take care it carefully.But in my case ios is handling "a" as id which is very strange and result in error and bug. – codester Nov 10 '12 at 15:14
  • I am trying to tell you your supposed dog is actually a cat, you're just *calling* it a dog. `[[B alloc] init]` returns a B object, and that object remains a B object, even though you erroneously place it in a variable of type A. The `a` variable contains a B object. Yes, that's confusing. That's why the compiler's telling you not to do it! – andyvn22 Nov 10 '12 at 15:15