Variables in two languages

Discussion in 'Mac Programming' started by Miglu, Jan 22, 2010.

  1. Miglu macrumors member

    Joined:
    Jan 22, 2010
    #1
    I have learned Java and am having a problem with pointers in Objective-C. This is from my Java book's "The allocation of memory to variables" section:

    "The local variable used to store the object appears on the stack just as if it were a local variable holding a primitive type. That particular variable, however, holds only the memory address of the object, which is stored in the heap."

    This is from the "Passing arrays as parameters" section:

    "If you pass a primitive value like an integer, Java copies the value, which means that it is impossible for a method to change it. ... however, passing an object as parameter to a method means that only the reference is copied, so the method effectively shares the object with the caller."

    Are the facts in these two quotes always true in Objective-C? The Java book does not even mention pointers, and I am wondering why they are needed so much in Objective-C. Is the definition of variable different in the two languages?
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Objective-C is lower level than Java. In reality EVERY non-primative variable in Java is a pointer. Think about the dreaded "NullPointerException" you can get in Java...
     
  3. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #3
    The way objects are handled in both Java and Objective-C are more similar than initial appearances portray. In Java, you only have one way to refer to an Object. You can't actively manipulate the pointer to the Object, but a pointer is all you have. Things like the dot operator to access an object's ivars or methods know this and always do what you want to the Object on the other side of the pointer. You can't retrieve the address yourself and manipulate it, and you can't "dereference" the pointer, all of this is handled behind the scenes for you. You can never have a "concrete" Object on the stack, pass it around, etc... you only deal with the reference/address of the Object.

    Essentially these same rules apply to an Object in Objective-C, except that the pointer is always explicit instead of Java where the pointer is always implicit. The only real difference is you can add levels of indirection in Objective-C. That's to say, you can have a pointer to an NSObject *. You can never have a concrete Object on the stack in Objective-C. The only thing you can do to an Object pointer is pass messages to it (please ignore accessors invoked via the ".". They do nothing but muck with and confuse the syntax. They are a shortcut for a message pass. A message pass is ALL you do to an Object pointer).

    You can contrast this with the system in C++ where you can have concrete Objects on the stack, and pointers to Objects. You need to use different operators based on what you're dealing with, either -> to act on an Object pointer or . to act on a concrete, "local" Object. This distinction does not exist in Objective-C or Java, everything is via a pointer in both. The only difference is in Objective-C the pointer syntax used for pointers to other primitive types is extended to Objects instead of obscuring the fact that you're dealing with a pointer like Java.

    Hope this is helpful, i know it sounds sort of obtuse, but it's really not so bad once you get a little more cozy with Objective-C, and especially if you spend a little time learning about pointers and how they are used in plain C. Once you do, hopefully it will make more sense that you never have an NSObject, only an NSObject *, and you'll never dereference an NSObject * with &.

    -Lee
     
  4. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #4
    My question is, when you use dot syntax in Cocoa via @property / @synthesize , does it always generate a method? It seems to me that the optimizer would look at "[self getIVar]" generated from self.iVar and say, "well, that is a silly waste of a method call when it can just be converted directly to an offset".
     
  5. Miglu thread starter macrumors member

    Joined:
    Jan 22, 2010
    #5
    Thanks. Now I understand. A book called "Learn Objective-C on the Mac", as well as the previous book in the series, "Learn C on the Mac", does not explain this. Neither does the "C Programming" Wikibook. It should be edited to have a chapter about coming from different languages and this should be explained in the Java section. However, is the definition of variable the same for the languages? It seems that a pointer is called a variable in Java.
     
  6. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #6
    From:
    http://developer.apple.com/mac/libr...html#//apple_ref/doc/uid/TP30001163-CH11-SW17

    What this means is that you get to keep all of the power of a message pass when using the ".", an ivar is never accessed directly. So message forwarding, dynamic-woozamawhatzits, etc. will still work fine when using the ".".

    A variable is a place to hold a value. In strongly-typed languages, every variable has an associated type. In OOP languages, i like to think of Objects as a wholly different sort of thing than a variable, because they don't just hold a value, but a whole bunch of values, and methods that go with them. I think of a variable as holding a primitive type. In a language like C/Objective-C, one primitive type is a pointer. The value stored is a memory address, and when you go there you find the type that is being pointed to. Sometimes that's another primitive like an int, sometimes in Objective-C it is an Object. There are no user-facing pointers in Java at all, period. When you say:
    Code:
    java.lang.String myString = null;
    
    in Java, this is a pointer to a String, but you don't really have to deal with that. It's null right now, if you assign something to it it will point to that thing. But you don't really think about reaching out into memory to grab that Object, etc. you just say:
    Code:
    java.lang.String myString = "xyz";
    int x = myString.length();
    
    Sure, it's going to dip it's finger somewhere into the aether (you don't get to know where, without some JVM tomfoolery) and calls length on the myString object. You don't have to worry about the specifics of where that thing is, etc.

    It doesn't hurt to KNOW that those are pointers in Java, you just don't really have to worry about it. Things like assigning one Object to another do make this more clear, though. No copy is made, etc... just the pointer is assigned, so now two things are looking at the same piece of memory. In the case of Strings in Java, this doesn't much matter because they are immutable, but if you had a mutable thing, and assigned one Object to another, changing the Object via one of those references is going to result in a change when you look at it with the other, because they are both pointing to the same thing.

    -Lee
     
  7. AlmostThere macrumors 6502a

    #7
  8. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #8
    Is there any advantage at all of using self.iVar versus directly accessing iVar? I have seen code written this way and it perplexes me that anyone would want to do that.
     
  9. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #9
    The simplest way to remember whether or not a value is a pointer: size.

    Variables' values have to live somewhere, whether on the stack, as instance variable within an object, or in allocated memory. A number, like an int or a float, is always a specific known size at compile time. structs are also defined at a fixed size. These things may exist in a specific location because the compiler knows how much space to reserve for them.

    Conversely, an object instance, such as a string, is not a known size prior to runtime. If your code cannot know the size of a value, you can pretty well assume that the name you use to access that variable will be a pointer.
     
  10. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #10
    Methods can be overridden. Direct access to ivars cannot.

    Sometimes it's better to maintain flexibility (properties and dot-accessors) as long as possible during dev, especially if the performance effects are insignificant.

    Properties don't require one-to-one correspondence to ivars. Simple example: the mean or median value of an array-like class can be a property, despite not having an ivar.

    Properties can also be KVO'ed and KVC'ed.
     
  11. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #11
    A simpler and more relevant example might the an array's object count. A table datasource would want to observe its source array's count and reload the table when ever that value changes.
     
  12. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #12
    self.iVar is really only used for objects (non-primative) data types. The reason is that you can use the built in memory management.

    EXAMPLE:
    @property (retain) NSString *myString;

    lets say we want to put a string there.
    if we do;
    myString = [NSString stringWithFormat: @"%@", someOtherString];

    Then after our next run loop myString is not valid anymore. Why? because the method stringWithFormat: returns an autoreleased string.
    self.myString = [NSString stringWithFormat: @"%@", someOtherString];

    works perfectly.

    AND!!!!
    if myString was already assigned to a string variable that was retained, version1 leaks that first string, version two does not!

    The method generated for setMyString would look something like this.
    - (void) setMyString: (NSString *) str {
    [str retain];
    [myString release];
    myString = str;
    } // the ordering of these retains and releases are important.
    // example, if myString == str already, if we released myString before retaining str, then we might dealloc the string
     
  13. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #13
    In the long version, would you want to do a nil check before releasing myString? Not being picky, but my apps do tend to be.
     
  14. Miglu thread starter macrumors member

    Joined:
    Jan 22, 2010
    #14
    Pointers in C are a massive source of confusion for newbies who have come from Java. My last question about this is that is the reason why pointers are used to hold objects' address instead of normal variables being used to hold them directly that the object can be assigned to other pointers without changing the object? (and primitive types do not need pointers because there is no harm from copying them, as they can not be changed).
     
  15. Cromulent macrumors 603

    Cromulent

    Joined:
    Oct 2, 2006
    Location:
    The Land of Hope and Glory
    #15
    Pointers are used to pass by reference rather than value so when you are passing around a struct it makes much more sense to pass a pointer around (and thus pass by reference) than it does to pass the struct around (thus copying it and passing by value).

    You still seem to be confused though. A pointer is just a memory address. An int or a float or a char is used to hold a value where as an int * a float * or a char * are used to hold the address of that value.

    Also don't forget that it is perfectly possible to have pointers to functions as well which allow you to do callback functions (qsort() is the famous example often used for function pointers). You can think of them in the same sort of light as delegate methods in Objective-C which when you get down to it are basically just callback functions.

    Pointers to primitive types are just as useful. For instance pointers (pre-C99 anyway) where the only method to have dynamically allocated arrays. Also because C has no concept of a string you normally end up using malloc to and thus char * to pass around various null terminated strings.

    Edit:

    Think of it this way.

    You have a house and you want to give your friend a copy of it. This is an extremely expensive operation as they would need to take the designs and then build a copy.

    You have another friend who you just want to tell how to get to your house, so you give them your address.

    You then decide to change the paint job on your house. The person who copied your house still has the old version as they have not repainted their house yet. You have not changed the address of your house though so the person who you gave your address too will end up at the house with the nice new paint job.
     
  16. gnasher729 macrumors P6

    gnasher729

    Joined:
    Nov 25, 2005
    #16
    In Objective-C, sending any message including "release" to a nil-object is guaranteed to have no effect at all; if the message is supposed to return a value then it will return zero/NO/0.0/nil, whatever is appropriate.

    So if an object is nil, then [anObject release] has no effect and is safe.
     
  17. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #17
    They are generally a massive source of confusion for everyone that first encounters them. Having your experience colored by another language doesn't help, but they will make sense eventually. I would recommend a short amount of time with plain C getting used to the general syntax and figuring out concepts like pointers before diving headlong into Objective-C. Others disagree with this, but I feel like a foundation in C will serve you well outside of the context of Objective-C.

    There's a lot going on there. I'll try to break it down. The first part:
    This was a design choice in Objective-C. There are languages (C++, surely others) that do let you choose if you want a "local" Object. In C++ they can simply be declared:
    Code:
    std::string myString = "Test";
    
    The assignment part of this is more tricky than it seems, invoking
    Code:
    string& operator= ( const char* s )
    , but anyhow... C++ also lets you have pointers to Objects like Objective-C. I like having pointers to Objects only, because it means EVERY Object you're dealing with is off in the heap, you know you have a pointer to it, you know exactly how to deal with it. In C++ you need to know if you have a std::string * or just a std::string, and must apply different operators to invoke methods, etc.

    I can imagine you might then question, if Objective-C were to only pick one, why pick pointers? My opinion on this is the great expense that can be incurred in copying a large object around when it needs to be passed to a function (if you only have Object "values", this is what you'd have to do), assigned to another local instance, etc. Every instance variable has to be copied, etc. And what if you have Objects that are instance variables of other Objects? Then copying the parent will mean copying the child. That could get very, very expensive. With pointers only, if you just want another pointer to the Object, the assignment of a 4 or 8-byte pointer is very cheap. If you really DO need a copy, there are explicit methods to make one, so you get to control when you really need this behavior.

    There is also a LOT more space on the heap than on the stack. This means that if you wanted to have an array of 200 Objects in a method, you'd use the size of all of the Objects ivars, and however the system stores function pointers for its methods, etc. taking up memory * 200. You could very easily overwhelm the stack, get a stack overflow, and have your program die. You'd have to break things into extremely small bits to deal with the inability to stick your Objects on the heap.

    So Objective-C has a heap-only, pointer-only Object system. I like this, I'm sure some people don't. However, this really isn't different from Java at all. You just don't deal with the pointers explicitly in Java. But it does do pointer-only, heap-only Objects, too. You just don't see *s everywhere, the pointers are implicit in Java.

    So now the next part, that I had a little more trouble understanding:
    I'm not sure what you're asking, but I'll try to answer one interpretation, which is that you want an easy "copy" mechanism for Objects that just uses the = operator. This is a result of the compromises of the language design that I discussed above. There is an easy way to make copies, though:
    http://developer.apple.com/mac/libr...Reference.html#//apple_ref/occ/intf/NSCopying
    Many Objects will implement this protocol, and allow for a simple [myObject copy] message to be sent to an Object. You can just assign the result of this to another Object * and get the result you're looking for.

    I am having trouble understanding what you mean here, too. Primitive variables can be changed, that's the whole point. I'm sure that's not what you meant, though. The real issue here is that primitive types have a well-understood size, and it is pretty small. The largest I can think of might be 16-bytes. Copying 1,2,4,8, or 16 bytes around is pretty trivial. Copying around a few thousand may not be, in the case of a very large Object. It's also pretty important to have a type to assign literals to.

    One could certainly imagine a system like Java stripping out primitives like int and short and replacing them with their object equivalents Integer and Short, then taking literals like 5 and simply replacing that with a fixed Integer object with the value 5 stored, but this seemed to even be outside of the Object-Oriented-only design of Java. People love primitives, and for things like loop control variables, it seems overkill to use Objects. Also, x + y where x and y are ints is pretty straight forward. If they were Integers, an Integer method would have to be invoked that would return a new Integer Object. It seems like a lot of overhead.

    On your road to understanding pointers, you really need to not think of them as a different sort of thing than other primitives. I would just ignore Objects and pointers to them in Objective-C for now. Just deal with the concept in C. A pointer is a primitive type whose value is a memory address. An int's value might be 4 or 2334235, a char's value might be 'A' or '%', etc. A pointer's value might be the address 0x87432309 on a system with 32-bit addresses. If the pointer is of type int *, the integer value stored in the 4 (normally, sometimes 8) bytes starting at memory address 0x87432309 might be 7. A pointer is just a few bytes (enough to store a memory address on a specific system) that stores memory addresses. That's it. There's no magic.

    There are a few special operators that you can apply to deal with pointers, because otherwise you really couldn't do anything with the memory address values they store. These operators are:
    * This operator dereferences a pointer. So if you have an int *, when you apply this operator to it, you get an int with the value stored at the address your int * points to. This is, unfortunately, the same operator used for multiplication when applied to primitive numeric types, but this is a unary operator (takes only one operand, instead of two).
    & This operator gives you the address of a variable. So if you have an int and apply & to it, you get an int * whose value is the address in memory where the int variable is stored.

    Once you DO graduate to dealing with Objective-C, when you have an Object pointer you can just forget about these. The only operator applied to Object pointers is the message pass, []. You cannot dereference an Object pointer because, as we discussed earlier, there are no plain Objects in Objective-C. You cannot have an NSObject, only an NSObject *. You CAN get an address of an Object *, but then you just have an Object **, which is pretty rarely used. It comes up, normally with NSError values, but don't worry about that right now.

    Please spend a few days getting used to pointers in plain C. Write a few programs, print out the pointers with the %p format specifier for the printf family, pass them to functions, print the pointer's value and the value stored at the address they hold, etc. Declare an int, and an int * and assign the address of the int using & to the int *, then change the int with an assignment statement, then display the value pointed to but the int *, etc.

    This will click. It may take an hour, it may take a few days, it may take a few weeks. But this is critical to the understanding of how memory is used by your program, where your variables are being stored, and how to effectively program and deal with APIs you come across that expect to be passed things by reference (using a pointer).

    Cromulent mentioned function pointers, which are great, but I wouldn't worry much about those for now. Focus on pointers to primitive types in plain C now, then deal with some Objects in Objective-C, and tackle function pointers when you need them. His point is good, but you should bite off a small chunk at a time if you're already a bit perplexed.

    Good Luck!

    -Lee
     
  18. Sydde macrumors 68020

    Sydde

    Joined:
    Aug 17, 2009
    #18
    In fact, as long as you stay entirely within the bounds of Objective-C and Cocoa, you should never have to deal directly with function pointers. It may be helpful at some point to fully understand, but what is going on is really more important than how it is happening most of the time.
     
  19. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #19
    Not necessarily, quartz uses function pointers to have call back functions for things like stippling patterns.
     

Share This Page