[ All Fragments ]
Many object-oriented languages encourage you to define a
get_foo and set_foo function for each member
variable foo. These allow you to control access to the
variables and provide for future extensibility. For example,
set_foo could be modified to keep a table of values of
foo.
Dylan provides for this extensibility without having to write the accessor functions up front. Consider a simple Dylan class:
define class <vehicle> (<object>)
slot driver,
required-init-keyword: driver:;
end class;
This creates two functions, driver and
driver-setter. Under normal circumstances, these two functions
will be inlined and optimized into direct accesses.
Dylan provides some handy syntatic sugar to make these functions look like members of a C structure:
define variable *test-car* = make(<vehicle>, driver: "Frank");
// These two expressions return the same value.
*test-car*.driver;
driver(*test-car*);
// These three statements perform the same assignment.
*test-car*.driver := "Sally";
driver(*test-car*) := "Sally";
driver-setter("Sally", *test-car*);
If you later discover that you can't allow direct access to the
driver slot, you can rename the slot and create two explicit
functions named driver and driver-setter to
replace it. The following example maintains a hash table mapping drivers to
their cars:
define constant *driver-to-car-map* = make(<table>);
define class <vehicle> (<object>)
slot %driver,
required-init-keyword: driver:;
end class;
define method initialize(vehicle :: <vehicle>, #key, #all-keys)
*driver-to-car-map*[vehicle.%driver] := vehicle;
end method;
define constant driver = %driver;
define method driver-setter(driver, vehicle :: <driver>)
=> (value :: <object>)
*driver-to-car-map*[driver] := vehicle;
vehicle.%driver := driver;
end method;