Tingle is not only an idea oriented language, it is also a dynamic language. It allows us to manipulate classes at run time, for instance using the operators "renew" and "asnew".
The former changes the class of a single object ("become"). We can do this when someone graduates and proceeds to take a job at his university:
class Student = person student. class Personnel = person personnel. renew john Personnel
This leaves all variables of the former Student object intact, but the variables from the idea student and from the intersection of the ideas person and student will not be reachable anymore (because no more methods will be defined on the object that have these in scope) until John decides that it was more fun being a student, and changes again.
This, by the way, is why Tingle has no constructors. Section 10 showed how to use companion objects as factories, but when you allow objects to be created piece by piece, neither constructors nor factories are satisfactory solutions. So instead of constructors, Tingle provides initializers: each individual instance variable can have any expression as its initial value. Such an expression is evaluated the first time when the variable is read (except if it is written to first). This involves a big trade-off though, as these expressions cannot receive parameters like constructors can; so companion objects as factories have to supplement them.
Actually, if John takes a job at the university immediately after graduating, chances are that he will additionally enroll as a Ph.D. student. So we might compose a class out of the idea person, plus the idea student, plus the idea personnel. But this means that we might have to solve conflicts between top methods of Student and Personnel, where we would prefer to keep both, for instance getID() for student ID as well as for personnel ID. We can avoid having to fix this if we know that John will in all circumstances act either as a student, or as a member of personnel, but never both at the same time. In that case we can use "asnew" to create an extra role:
johnAsPersonnel = asnew john Personnel
This way john and johnAsPersonnel will always have the same internal state -- although only the variables of the idea person are really shared: all others are in scope for methods of only one of the roles -- but belong to different classes. (The objects john and johnAsPersonnel are identical for the "==" and "!=" operators.)
It is interesting to consider what would happen if a method were to renew self, because the answer follows directly from the principles of idea orientation. As long as the new class after renew provides a set of top methods compatible with the old class (i.e. the same external API for the object), nothing dramatic will happen. The method itself will continue, will be able to access its variables and call other methods in scope, even if they belong to ideas that are not present in the new class, and the same goes for earlier methods waiting on the call stack to continue later. The object will only behave according to its new class when it receives a new message, either from itself or from another object; and switch back to its old behaviour when returning to methods that were already active before the renew. The program logic might get messed up, but at no point is there any danger of a hard crash. This is because classes may be fiddled with at run time, but ideas are immutable.
Now that we know exactly what happens when one object changes class, we can continue to dynamically activated layers, which will change the class of many objects at once.
Contents | Appendix B: Ideas as Layers