Next: , Previous: , Up: C   [Index]


Class casting

Class casting

In many cases, it’s obvious which class an object is, even when the object’s defition is removed from the place where a program needs to perform an operation on it, or the object is aliased to self or to a C variable, or you need to use a different type of language semantics with an object.

If a program has a set of expressions, as in this hypothetical example:


Integer new myInt;
myList new myList;
Key new myKey;
Symbol new *intPtr;

*intPtr = Integer new "Int 1", "1";
myList push *intPtr;
*intPtr = Integer new "Int 2", "2";
myList push *intPtr;

myKey = myList + 1;

myInt = *myKey;

myInt += 3;

... do stuff with myInt ...

myList map {
  printf ("%d\n", self value);
}

When run, the program would produce output like this.


$ ./myProg
1
2

That’s because the changes to myInt would not take effect for the member of ‘myList’, because Integer objects, when a program assigns values to them, normally assigns the value of one Integer to another. However, in the example above, you might want to work on the original list member - that is, you want the assignment to treat myInt as if it were a reference.

One way to notify Ctalk of this is to use an Object to refer to the list element, and use a class cast to notify Ctalk that the Object is actually an Integer.

Then the program example above looks like this.


Object new myIntObject;
myList new myList;
Key new myKey;
Symbol new *intPtr;

*intPtr = Integer new "Int 1", "1";
myList push *intPtr;
*intPtr = Integer new "Int 2", "2";
myList push *intPtr;

myKey = myList + 1;  

myIntObject = *myKey;

(Integer *)myIntObject += 3;  /* The cast tells Ctalk to treat myIntObject,
                                 which is declared as an Object,
                                 as an Integer, so it can work correctly
                                 with the first element of myList. */

... do stuff with myIntObject ...

myList map {
  printf ("%d\n", self value);
}

Other places that you can use class casting is when a program uses a C OBJECT *. In that case, you can tell Ctalk what class the object is. Here’s an abbreviated example from a map method in TreeNode class.


  OBJECT *t, *list_elem;

  /* rcvr_obj is a TreeNode object. */
  for (t = __LIST_HEAD(rcvr_obj), have_break = NULL; 
       t && !have_break; t = t -> next) {
    list_elem = obj_ref_str ((t -> instancevars) ? 
			     t -> instancevars -> __o_value :
			     (IS_VALUE_INSTANCE_VAR(t) ? 
			      t -> __o_p_obj -> instancevars -> __o_value :
			      "0x0"));

  ... do stuff ...

  (TreeNode *)list_elem children __mapChildren methodfn;

  (TreeNode *)list_elem siblings __mapSiblings methodfn;

  }

This is a convenient way for a program to tell Ctalk that list_elem is a TreeNode object. It’s up to the program to ensure that the C variable actually does point to an object of that class, or the program won’t work correctly at run time.

Programs can also cast self to a class, in cases where Ctalk cannot determine self's class from its context, like in this example


myList map {

  (Float *)self = 0.01f;

}

This feature is still experimental, and you should use it with caution; in particular, it’s up to the program to insure that the object actually is a member of the class that you cast it to. However, on the occasions when a program needs to excercise some control over a set of expressions’ semantics, then class casting can be useful.


Next: , Previous: , Up: C   [Index]