2:0
protobj: Prototype-Delegation Object Model
1 Introduction
Protobj was a Scheme exercise, and is packaged for those curious,
not intended for practical use. Protobj was written primarily as a syntax-rules learning exercise, and secondarily because people asked about
prototype object models for Scheme from time to time.
Protobj implements a simple prototype-delegation object model,
somewhat similar to that of
Self, and also related to those of SLIB
object and OScheme. The Protobj library defines both a verbose set of
procedures, and terse special syntax.
Protobj is based on objects with named slots that can contain
arbitrary values. Object have immediate slots, and single parent objects from
which additional slots are inherited. When setting in a child object a slot
inherited from the parent, a new immediate slot is created in the child so that
the parent is unaffected and the slot is no longer inherited.
Methods are simply closures stored in slots. When a method is
applied, the first term of the closure is the receiver object. Unlike Self,
getting the contents of the slot is distinguished from invoking a method
contained in the slot. This distinction was made due to the way first-class
closures are often used in Scheme.
An object is cloned by invoking the clone method. The default root object’s clone method creates a new child object without any immediate slots,
rather than copying any slots. This behavior can be overridden to always copy
certain slots, to copy immediate slots, or to copy all inherited slots. An
overriding clone method can be implemented to apply its parent’s clone method to itself and then set certain slots in the new child
appropriately.
Protobj was originally writtin in R5RS, SRFI-9, SRFI-23, and
SRFI-39.
2 Tour
The following is a quick tour of Protobj using the terse special syntax.
Bind a to the new object that is created by cloning the default root object (% is special syntax for invoking the clone method):
Verify that a is an object and that a’s parent is the default root object:
> (eq? (^ a) (current-root-object)) |
#t |
Add to a a slot named x with value 1:
Get a’s slot x’s value:
Bind b to a clone of a:
Get b’s slot x’s value, which is inherited from a:
Set a’s slot x’s value to 42, and observe that b inherits the new value:
Set b’s slot x’s value to 69, and observe that a retains its own x value although ’s x value has been changed:
Add to a an xplus slot containing a closure that implements a method of the
object:
> (! a xplus (lambda ($ n) (+ (? $ x) n)))
Apply the method to the a and b objects (b inherits any new slots added to a):
Observe the shorthand syntax for applying methods to an object
multiple times, with the syntax having the value of the lastmost application:
> (@ a (xplus 1000) (xplus 7)) |
49 |
Bind to c an object that clones a and adds slot y with value 101:
> (define c (% a (y 101)))
Get the values of both the x and y slots of c:
Finally, bind d to a clone of a that overrides a’s x slot:
> (define d (% a (x 1) (y 2) (z 3)))
3 Basic Interface
The basic interface of Protobj is a set of procedures.
(object? x) → boolean?
|
x : any/c |
Predicate for whether or not x is a Protobj object.
(object-parent obj) → (or/c #f object?)
|
obj : object? |
Yields the parent object of object obj.
(object-set! obj slot-symbol val) → void?
|
obj : object? |
slot-symbol : symbol? |
val : any/c |
Sets the slot identified by symbol slot-symbol in object obj to value val.
(object-get obj slot-symbol) → object?
|
obj : object? |
slot-symbol : symbol? |
Yields the value of slot named by symbol slot-symbol in object obj (immediate or inherited). If no slot of that name exists, an
error is signaled.
(object-get obj slot-symbol noslot-thunk) → any/c
|
obj : object? |
slot-symbol : symbol? |
noslot-thunk : (-> any) |
Yields the value of slot named by symbol slot-symbol in object obj (immediate or inherited), if any such slot exists. If no slot
of that name exists, then yields the value of applying closure noslot-thunk.
(object-apply obj slot-symbol arg ...) → any
|
obj : object? |
slot-symbol : symbol? |
arg : any/c |
Applies the method (closure) in the slot named by slot-symbol of object obj. The first term of the method is obj, and one or more arg are the remaining terms. If no such slot exists, an error is
signaled.
(object-apply/noslot-thunk | | obj | | | | | | | noslot-thunk | | | | | | | slot-symbol | | | | | | | arg ...) | | → | | any |
|
obj : object? |
noslot-thunk : (-> any) |
slot-symbol : symbol? |
arg : any/c |
Like object-apply, except that, if the slot does not exist, instead of signaling
an error, the value is the result of applying noslot-thunk.
(object-raw-clone/no-slots-copy obj) → void?
|
obj : object? |
(object-raw-clone/copy-immed-slots obj) → void? |
obj : object? |
(object-raw-clone/copy-all-slots obj) → void? |
obj : object? |
These procedures implement different ways of cloning an object,
and are generally bound as clone methods in root objects. object-raw-clone/no-slots-copy does not copy any slots, object-raw-clone/copy-immed-slots copes immediate slots, and object-raw-clone/copy-all-slots copies all slots including inherited ones.
(current-root-object) → object?
|
(current-root-object obj) → void? |
obj : object? |
Parameter for the default root object. The initial value is a
root object that has object-raw-clone/no-slots-copy in its clone slot.
4 Terse Syntax
Since Protobj’s raison d’etre was to play with syntax, here it is.
Note that slot names are never quoted.
Parent of obj.
(! obj slot val)
|
(! obj (slot val) ...) |
|
|
Sets object obj’s slot slot’s value to val. In the second form of this syntax, multiple slots of obj may be set at once, and are set in the order given.
Yields the values of the given slots of obj. If more than one slot is given, a multiple-value return is used.
(@ obj slot arg ...)
|
(@ obj (slot arg ...) ...) |
|
|
Applies obj’s slot method, with obj as the first term and args as the remaining terms. In the second form of this syntax,
multiple methods may be applied, and the value is the value of the last method
application.
(% obj (slot val) ...)
|
(%) |
|
|
Clones object obj, binding any given slots to respective given vals.
5 Known Issues
6 History
Version 2:0 — 2016-02-29
Version 1:2
2011-11-08
Version 1:1 — 2009-03-03
License is now LGPL 3.
Converted to authors new Scheme administration system.
Changed slot lists and slot pairs to be explicitly mutable, for PLT 4.x.
Version 1:0 — 2005-06-19
Fixed bug in %protobj:apply* (thanks to Benedikt Rosenau for reporting).
Changed $ syntax to ?, so that $ could be used for “self” in methods.
Documentation changes.
Version 0.1 — 2005-01-05
7 Legal
Copyright 2005, 2009, 2011, 2016 Neil Van Dyke. This program is Free
Software; you can redistribute it and/or modify it under the terms of the GNU
Lesser General Public License as published by the Free Software Foundation;
either version 3 of the License, or (at your option) any later version. This
program is distributed in the hope that it will be useful, but without any
warranty; without even the implied warranty of merchantability or fitness for a
particular purpose. See http://www.gnu.org/licenses/ for details. For other
licenses and consulting, please contact the author.