Temporary Variables Still Checked Out

QUESTION: Can someone please explain to me why the following is happening.

   p = ptr_new( {a:1, b:2, s:{x:0,y:0, a:[256,256,48]} } )

   print, ((*p).s.a)[2]
         48

   ((*p).s.a)[2] = ((*p).s.a)[2] * 4
   % Temporary variables are still checked out - cleaning up...

   print, ((*p).s.a)[2]
         48                          ; Value was not adjusted

   help, ((*p).s.a)[2]
   <Expression>    INT       =      48

   print, ((*p).s.a)
        256     256      48

   (*p).s.a[2] = (*p).s.a[2] * 4

   print, ((*p).s.a)[2]
        192                          ; Value *was* adjusted

Is ((*p).s.a)[2] an invalid construct? IDL doesn't seem to have problems with it in the PRINT command, and it sure seems OK to me. The message about temporary variables seems to be a clue, but I need some help on this one.

ANSWER: The answer was supplied by Stein Vidar Hagfors Haugan on the IDL newsgroup. (I have done rather more editing than normal, but I tried to preserve the flavor of the original answer.)

I think the answer to this is that the parentheses on the left hand side of the expression (called an lvalue in C terminology) effectively turn this into a temporary right hand value (rvalue), which then can't be assigned to anything, since now there is nothing "on the left" of the expression anymore. Thus, we get this error message.

The bug here (if there is a bug) is not that (*p).s.a[2] isn't adjusted, it's the fact you don't get an error when you issue the command!

Whenever you put parentheses around anything but a simple variable, IDL makes a temporary variable (an rvalue) out of it, and then decides how to do the stuff outside the parentheses. This is why putting parentheses around function calls , for example, allows you to do something like this.

   Print,(Size(a))[0]

You can't index a function call, but you can index a temporary variable. In other words, the line ((*p).s.a)[2] = ((*p).s.a)[2] * 4 is analogous to this.

   IDL> a = fltarr(5)
   IDL> (a[0:2])[2] = 6
      % Temporary variables are still checked out - cleaning up...

Note that the pointer has nothing to do with it. We can get the same result if we use structures.

   IDL> st={a:1, b:2, s:{x:0,y:0, a:[256,256,48]} }
   IDL> (st.s.a)[2]=2
      % Temporary variables are still checked out - cleaning up...

I think we see this error more often with pointers because we don't realize the sequence of letters "*p" is syntactically identical to a variable name. The value of the variable called "*p" is what is pointed to by the pointer "p" (obvious, but somehow I had to say it).

The "problem" (not really, read on!) is that structure dereference binds harder than the pointer dereference.

(Indeed, RSI doesn't seem to think that "." is an operator at all! That must be the reason why we didn't get the "p->element" notation as a shorthand for "(*p).element" as in C. I would still like to see it!).

So, to overcome the binding problem we use the (*p) construct. But, according to "my" rule above, this is analogous to "(variable)". And lo and behold, the parenthesis is not a problem.

   IDL> a = fltarr(3)
   IDL> (a)[1]=55
   IDL> print,a
         0.00000      55.0000      0.00000

So, to sum up:

[Return to IDL Programming Tips]