diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2016-01-03 11:16:48 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2016-01-03 11:16:48 -0800 |
commit | 11ac283d7eda2bac2f19d62d014043f66c8de84c (patch) | |
tree | 2b0289573ae6c8337c94734aa58b46b282e916e9 | |
parent | 629c448f272fe23cefe6eb2b2b90dc8dfb3bbf86 (diff) | |
download | txr-11ac283d7eda2bac2f19d62d014043f66c8de84c.tar.gz txr-11ac283d7eda2bac2f19d62d014043f66c8de84c.tar.bz2 txr-11ac283d7eda2bac2f19d62d014043f66c8de84c.zip |
defstruct: order function slots before other static slots.
This allows the initializer expressions for static slots
to instantiate objects, and those instances can rely on
methods being set up.
* share/txr/stdlib/struct.tl (sys:prune-nil-inits): Recognize
:function keyword as denoting a static slot.
(defstruct): Represent methods and functions as (:function
...) items rather than (:static ...) so they can be
distinguished. Function slots appear before other static
slots in the static slot list, and their initializing
code is placed into the the static-initfun lambda of the
sys:make-struct-type call in this order.
* txr.1: Documented.
-rw-r--r-- | share/txr/stdlib/struct.tl | 32 | ||||
-rw-r--r-- | txr.1 | 31 |
2 files changed, 48 insertions, 15 deletions
diff --git a/share/txr/stdlib/struct.tl b/share/txr/stdlib/struct.tl index 7e0d2af1..ee4bfd18 100644 --- a/share/txr/stdlib/struct.tl +++ b/share/txr/stdlib/struct.tl @@ -29,7 +29,7 @@ (defun sys:prune-nil-inits (slot-init-forms super-type) (remove-if (tb ((kind name init-form)) - (and (member kind '(:static :instance)) + (and (member kind '(:static :instance :function)) (null init-form) (or (not super-type) (not (slotp super-type name))))) @@ -56,13 +56,13 @@ "~s: method ~s needs \ \ at least one parameter" 'defstruct name)) - ^(:static ,name - (lambda ,args - (block ,name ,*body)))) - (:function ^(:static ,name - (lambda ,args - (block ,name - ,*body)))) + ^(:function ,name + (lambda ,args + (block ,name ,*body)))) + (:function ^(,word ,name + (lambda ,args + (block ,name + ,*body)))) ((:static :instance) (when body (sys:bad-slot-syntax slot)) @@ -112,11 +112,15 @@ ^(:instance ,name nil)) (name ^(:instance ,name nil))))) - (stat-si-forms [keep-if (op eq :static) slot-init-forms car]) + (super-type (find-struct-type super)) + (stat-si-forms [keep-if (op member @1 '(:static :function)) + slot-init-forms car]) + (pruned-si-forms (sys:prune-nil-inits stat-si-forms super-type)) + (func-si-forms [keep-if (op eq :function) pruned-si-forms car]) + (val-si-forms [keep-if (op eq :static) pruned-si-forms car]) (inst-si-forms [keep-if (op eq :instance) slot-init-forms car]) (stat-slots [mapcar second stat-si-forms]) - (inst-slots [mapcar second inst-si-forms]) - (super-type (find-struct-type super))) + (inst-slots [mapcar second inst-si-forms])) (whenlet ((bad [find-if [notf bindable] (append stat-slots inst-slots)])) (throwf 'eval-error @@ -124,17 +128,15 @@ "~s: slot name ~s isn't a bindable symbol" "~s: invalid slot specifier syntax: ~s") 'defstruct bad)) - (set stat-si-forms (sys:prune-nil-inits stat-si-forms super-type)) - (set inst-si-forms (sys:prune-nil-inits inst-si-forms super-type)) (let ((arg-sym (gensym)) (type-sym (gensym))) ^(sys:make-struct-type ',name ',super ',stat-slots ',inst-slots - ,(if stat-si-forms + ,(if (or func-si-forms val-si-forms) ^(lambda (,arg-sym) ,*(mapcar (aret ^(when (static-slot-p ,arg-sym ',@2) (static-slot-set ,arg-sym ',@2 ,@3))) - stat-si-forms))) + (append func-si-forms val-si-forms)))) ,(if (or inst-si-forms instance-init-form instance-fini-form) ^(lambda (,arg-sym) ,*(if (cdr instance-fini-form) @@ -19094,6 +19094,37 @@ type doesn't have. When an instance of the structure is created, then the instance initializations are performed on that slot from all of the ancestor structure types in which that slot is also an instance slot. +The initialization for slots which are specified using the +.code :method +or +.code :function +specifiers is re-ordered with regard to +.code :static +slots. Regardless of their placement in the +.code defstruct +form, +.code :method +and +.code :function +slots are initialized before +.code :static +slots. This ordering is useful, because it means that when the initialization +expression for a given static slot constructs an instance of the struct type, +any instance initialization code executing for that instance can use +all functions and methods of the struct type. +However, note the static slots which follow that slot in the +.code defstruct +syntax are not yet initialized. If it is necessary for a structure's +initialization code to have access to all static slots, even when the +structure is instantiated during the initialization of a static slot, +a possible solution may be to use lazy instantiation using the +.code lnew +operator, rather than ordinary eager instantiation via +.codn new . +It is also necessary to ensure that that the instance isn't accessed until all +static initializations are complete, since access to the instance slots of a +lazily instantiated structure triggers its initialization. + The structure name is specified using two forms, plain .meta name or the syntax |