Runtime Type Mutability

From BenefitsOfDynamicTyping :

When asked, "does anyone actually change the types of objects after they've been created?", LaurentBossavit raised this point:

I'm actually not sure what we mean by the "type" of an object. (WhatAreTypes, he asked, and then washed his hands.) It strikes me that StatePattern, DecoratorPattern et al. are ways to change the type of an object at run-time, without changing either its class or its interface. Or am I being silly?

So now the question is: "Is it ever useful to, for example, change the language-level type of an object to achieve the same effects as a StatePattern?" Sounds like a CodeSmell to me... any other opinions?

I think the question is just backwards. Suppose we do change the type of an object when we use DecoratorPattern or StatePattern. What need is there to distinguish that type from the "language-level" type ? Now, you can use the DecoratorPattern or StatePattern in languages with so-called "static typing". Thus, it is useful, in these languages, to change the type of an object.

The question is, in what circumstances is it useful for the language to go to the effort of preserving the "language-level" types ?

In those circumstances when you don't want 10 programmers on the project to come up with 10 run-time-typing-with-dynamic-change hacks that don't interoperate with each other. When you change the type of an object, then different methods are dispatched on it everywhere in the program, because the type change is integrated into the object system. This is like asking, in what circumtances is it better to have strings in the language than to hack up your own class library...


SmalltalkLanguage has the "become:" feature to do something like this. I believe this action is called ObjectSwizzling?. Since it's there, I guess someone uses it?

Taking a wild guess as to why it would be useful: I suppose it might be more efficient to just change the type rather than copy the data and delete the original... but that kind of PrematureOptimizationish stuff doesn't sound like the sort of thing a dynamically typed language creator wourd be concerned about. I'm really at a loss here. Would some kind Wikizen give us some clues?

''I think it is mainly used for growable collections (an array become:s a bigger array) and for lazy object creation (i.e. a cheap dummy object is created that hangs around, and when it receives something it doesNotUnderstand, it creates the big expensive object and become:s that object). -- StephanHouben''


CommonLisp also has this capability; it is called change-class. The programmer may also specify specializations for the methods update-instance-for-changed-class to fine tune what should happen to the object when it changes class. The instance has full access to all pre- and pos- change slots. Usage of this is ConsideredEsoteric?. -- AlainPicard


The problem with copying the data and deleting the original is that there may be other objects referring to the original that should now refer to the new version. Smalltalk's #become: takes advantage of the level of indirection provided by having object references be indexes into an "object table" which then points to the actual objects in memory -- #become: replaces the pointer in the object table so that all references to that entry in the table now point to the new object. There are several situations in which changing an object's class can be useful:

-- MitchellModel

Not all Smalltalk implementations use object tables; in those that don't, #becomes: scans the image looking for references to update in place. It's rather slow. You are better off using some letter/envelope idiom which ensures there is only one reference to the object whose type you want to change. This adds a layer of indirection, but only where it is needed. Object tables add indirection to all objects.


In ObjectiveCee, the generic object type(id) is defined as:

  typedef struct objc_object {
               Class isa;
  } *id;
So it's probably possible to do something like:
  (*(struct objc_object *)myObject).isa = [otherObject class];
But I'm not sure what effects that would have on the environment. To quote PetiteAbeille?, "This is an hack... It will most likely melt your computer and fry your brain. You have been warned!" Abeille was speaking on a different topic, but it remains valid.

Another similar thing to do in ObjectiveCee is to use +poseAsClass:aClass, but that's limited in that the receiver must be a subclass of aClass which declares no additional instance variables.

It's actually possible to do a lot of crazy things with the ObjectiveCee runtime, but it may be ExcessiveCleverness? sometimes.

--JoeOsborn


You can do it in CeePlusPlus as well, with the condition that the objects must be the same size - you just build the replacement class using an in-place constructor where the other object exists. It's a very neat technique. I've used it in the past to get arrays of objects that are polymorphically the same, but not actually the same type. -- KatieLucas


Similar hacks can be done in CeeLanguage, when the object's size does not change. For example, a freeware library called Austin (http://users.footprints.net/~kaz/austin.html) can change the representation of a container among LinkedList, binary search tree (BinaryTree), AvlTree?, Splay and RedBlackTrees. Or a CeeUnion? can be used.


PythonLanguage Allows you to change __base__ (superclasses) for some types and __class__ for some other. I don't think it has a become:-like feature. RubyLanguage does not allow it by default, but the EvilRuby? module introduces class setting methods, become method, and even MultipleInheritance (which ruby normally prohibits).


See also TypeMigration. There are two separate concepts involved:

but both pages concentrate on the latter. EditHint: refactor TypeMigration into this page, and discuss typing issues more on SchemaEvolution.


CategoryLanguageTyping


EditText of this page (last edited December 3, 2007) or FindPage with title or text search