Forwarders work by obtaining a pointer to the object that they are
modifying and doing a become. A become swaps the two objects in
memory, so everyone who previously pointed to the old object now point
to the forwarder instead. The forwarder intercepts all incoming
messages and may do whatever it likes with them. When the forwarder
gets a message it does not understand, it merely passes it on to the
object it took the place of. No other object needs to know that a
forwarder is being used!!
As an example, if you wanted to make a cause blindness spell, here is
the mob code for the spell:
!@implementation *Blindness* (*Forwarder*)
{
}
!- basicSee- x ;; i stop the basicSee- message, so it never gets passed on
{ ;; and the person will never see anything!
}
!@end
All you need is some code to cast it (meaning install the forwarder) like:
!- castBlindness- victim
{
[*Blindness* forwardTo- victim]
(cat vicitm "has been blinded!" nl)
}
And to be nice, a cure blindness spell (remove the forwarder):
!- cureBlindness- victim
{
;; checks to make sure the object has a forwarder first
(if (or (null [victim isForwarder]) [victim |Unforward-| *Blindness*])
(cat "Blindness not present." nl)
(cat "Blindness removed." nl))
}
Note that it is entirely possible that a forwarder can have a
forwarder placed on top of it. As a result, you can end up with
chains of forwarders all modifying the same object. The important
thing is that it all still works! It is hard to realize the power of
forwarders at first, but there is little that you can't do with them.
Most importantly, your code stays very modular, your code never has to
make special cases else where just in case someone has been blinded,
etc.
Eventually, we plan on coming up with all sort of specialized
forwarders, like ones that get rid of themselves after a certain
amount of time, etc.
The price to pay for forwarders is execution speed, not only because
each forwarder normally adds an extra message pass, but because your
instances can no longer directly access their instance variables
without doing a message pass. Obviously, since a forwarder could be
overriding any message, it could be overriding one of your instance
variables, therefore you won't get the correct (forwarder's) value
unless you passed a message.