:settable slots

<-Previous | ^UP^ | Next->

In the Getting Started with GendL tutorial, we identified on of the biggest differences between GendL and other programming languages was that slot evaluation was always demand driven and the inbuilt dependency tracker will always ensure slot values are current whenever any input changes. This removes a big burdon from the developer and also ensures run times are fast, as we are never calculating any values we don't need to use.

However, there may be times when we need to make programatic changes to values an over-ride this default behaviour. To do this, we identify either slots as :settable and then we use the set-slot! function to programaically alter the value of the selected slot.

When we make a change to a slot value by programatically setting it, the dependency tracker is aware of this and any changes which would ordinarily cause the value to be updated are suspended. If we want to reverse this behaviour (back to default) we can use either of the restore-slot-default! or restore-slot-defaults! functions

As with a lot of different techniques, programatically altering slot values and over-riding the default behaviour has its place and is a useful additoon to the tools and techniques available to the programmer. However, we need to be aware that at the point we do this, and until we revert to default behaviour, it becomes to responsibility of the developer to manage dependencies. For this reason it is recommended to use this technique sparingly and only when a solution using the default behaviour will not give the desired results

Consider the following code

(define-object settable-slots (base-object):computed-slots((speed 25 :settable)(time 15 :settable)(distance (* (the speed) (the time)) :settable)):functions((set-speed! (&key (value 20)) (the (set-slot! :speed value)))(set-time! (&key (value 10)) (the (set-slot! :time value)))(set-distance! () (the (set-slot! :distance 100)))(reset-distance! () (the (restore-slot-default! :distance)))(reset-all! () (the (restore-slot-defaults! (list :speed :time :distance))))))

3 :computed slots, speed, time and distance have been tagged as :settable. 5 functions have been defined, 3 which set new values (using set-slot!) for the respective slots and 2 which will restore default values and behaviours (using :restore-slot-default! and :restore-slot-defaults!). If we make the object and evaluate distance we get the following

GDL-USER> (make-self 'settable-slots)

#<SETTABLE-SLOTS #x2104DC5DFD>

GDL-USER> (the distance)

375
We can now programatically change the value of speed by running the set-speed! function. If we evaluate distance, we can see that
  • The value has changed
  • But the underlying calculation is being performed as specified

GDL-USER> (the set-speed!)

NIL

GDL-USER> (the distance)

300
We can do the same with time, getting the same results

GDL-USER> (the set-time!)

NIL

GDL-USER> (the distance)

200
If we now modify the value of distance, we can see the change in that value, but then going back and changing the value of speed again, we can see that distance has not been changed. This is because distance has had its value set and any dependency tracking associated with it, which would ordinarily cause a change to its value, has been disabled

GDL-USER> (the set-distance!)

NIL

GDL-USER> (the distance)

100

GDL-USER> (the (set-speed! :value 30))

NIL

GDL-USER> (the distance)

100
However, if we now reset the value of distance only, we can see that dependency tracking has picked up the values of speed and time and has updated the value for distance

GDL-USER> (the reset-distance!)

:DISTANCE

GDL-USER> (the distance)

300
Finally, if we reset all slots, all are set back to default

GDL-USER> (the reset-all!)

(:SPEED :TIME :DISTANCE)

GDL-USER> (the speed)

25

GDL-USER> (the time)

15

GDL-USER> (the distance)

375