summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--share/txr/stdlib/struct.tl16
-rw-r--r--struct.c258
-rw-r--r--tests/012/oop.expected17
-rw-r--r--tests/012/oop.tl66
-rw-r--r--txr.1283
5 files changed, 516 insertions, 124 deletions
diff --git a/share/txr/stdlib/struct.tl b/share/txr/stdlib/struct.tl
index 6bf665fb..8cd70359 100644
--- a/share/txr/stdlib/struct.tl
+++ b/share/txr/stdlib/struct.tl
@@ -27,12 +27,10 @@
(defun sys:bad-slot-syntax (arg)
(throwf 'eval-error "~s: bad slot syntax: ~s" 'defstruct arg))
- (defun sys:prune-nil-inits (slot-init-forms super-type)
- (remove-if (tb ((kind name init-form))
+ (defun sys:prune-missing-inits (slot-init-forms)
+ (remove-if (tb ((kind name : (init-form nil init-form-present)))
(and (member kind '(:static :instance :function))
- (null init-form)
- (or (not super-type)
- (not (slotp super-type name)))))
+ (not init-form-present)))
slot-init-forms)))
(defmacro defstruct (name-spec super . slot-specs)
@@ -105,8 +103,12 @@
:)))
((word name)
(caseq word
- ((:static :instance)
+ ((:static)
+ ^(,word ,name))
+ ((:instance)
^(,word ,name nil))
+ ((:method :function)
+ (sys:bad-slot-syntax slot))
(t ^(:instance ,word ,name))))
((name)
^(:instance ,name nil))
@@ -120,7 +122,7 @@
'defstruct 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))
+ (pruned-si-forms (sys:prune-missing-inits stat-si-forms))
(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])
diff --git a/struct.c b/struct.c
index 7e022ed9..35f5fc45 100644
--- a/struct.c
+++ b/struct.c
@@ -51,13 +51,23 @@
#define STATIC_SLOT_BASE 0x10000000
+struct stslot {
+ val home_type;
+ cnum home_offs;
+ val *home;
+ val store;
+};
+
+#define stslot_loc(s) mkloc(*(s)->home, (s)->home_type)
+#define stslot_place(s) (*(s)->home)
+
struct struct_type {
val self;
val name;
cnum id;
cnum nslots;
cnum nstslots;
- cnum eqmslot;
+ struct stslot *eqmslot;
val super;
struct struct_type *super_handle;
val slots;
@@ -66,7 +76,7 @@ struct struct_type {
val boactor;
val postinitfun;
val dvtypes;
- val *stslot;
+ struct stslot *stslot;
};
struct struct_inst {
@@ -167,7 +177,7 @@ static val struct_type_finalize(val obj)
static void call_stinitfun_chain(struct struct_type *st, val stype)
{
if (st) {
- if (st->super)
+ if (st->super && opt_compat && opt_compat <= 151)
call_stinitfun_chain(st->super_handle, stype);
if (st->stinitfun)
funcall1(st->stinitfun, stype);
@@ -197,6 +207,20 @@ static struct struct_type *stype_handle(val *pobj, val ctx)
}
}
+static void static_slot_home_fixup(struct struct_type *st)
+{
+ cnum i;
+ for (i = 0; i < st->nstslots; i++) {
+ struct stslot *s = &st->stslot[i];
+ if (s->home_type == st->self) {
+ s->home = &s->store;
+ } else {
+ struct struct_type *shome = coerce(struct struct_type *,
+ s->home_type->co.handle);
+ *s = shome->stslot[s->home_offs];
+ }
+ }
+}
val make_struct_type(val name, val super,
val static_slots, val slots,
@@ -235,12 +259,15 @@ val make_struct_type(val name, val super,
val id = num_fast(++struct_id_counter);
val iter;
cnum sl, stsl;
- val null_ptr = 0;
+ cnum stsl_upb = c_num(plus(length(static_slots),
+ num(if3(su, su->nstslots, 0))));
+ struct stslot null_ptr = { nil, 0, 0, nil };
st->self = stype;
st->name = name;
st->id = c_num(id);
- st->nslots = st->nstslots = st->eqmslot = 0;
+ st->nslots = st->nstslots = 0;
+ st->eqmslot = 0;
st->slots = all_slots;
st->super = super;
st->stslot = 0;
@@ -253,6 +280,10 @@ val make_struct_type(val name, val super,
gc_finalize(stype, struct_type_finalize_f, nil);
+ st->stslot = coerce(struct stslot *,
+ chk_manage_vec(0, 0, stsl_upb, sizeof *st->stslot,
+ coerce(mem_t *, &null_ptr)));
+
for (sl = 0, stsl = STATIC_SLOT_BASE, iter = all_slots;
iter;
iter = cdr(iter))
@@ -264,27 +295,43 @@ val make_struct_type(val name, val super,
static_slot_p(super, slot),
memq(slot, static_slots));
- if (ts_p)
- sethash(slot_hash, cons(slot, id), num(stsl++));
- else
+ if (ts_p) {
+ cnum n = stsl++ - STATIC_SLOT_BASE;
+ struct stslot *ss = &st->stslot[n];
+ val key = if2(su, cons(slot, num_fast(su->id)));
+ val msl = if2(su, gethash(slot_hash, key));
+ cnum m = (coerce(cnum, msl) >> TAG_SHIFT) - STATIC_SLOT_BASE;
+
+ if (!inherited_p || (opt_compat && opt_compat <= 151)) {
+ ss->home_type = stype;
+ ss->home_offs = n;
+ ss->home = &ss->store;
+ ss->store = if2(msl, stslot_place(&su->stslot[m]));
+ } else {
+ *ss = su->stslot[m];
+ }
+ sethash(slot_hash, cons(slot, id), num(n + STATIC_SLOT_BASE));
+ } else {
sethash(slot_hash, cons(slot, id), num_fast(sl++));
+ }
if (sl >= STATIC_SLOT_BASE)
uw_throwf(error_s, lit("~a: too many slots"), self, nao);
}
stsl -= STATIC_SLOT_BASE;
- st->stslot = coerce(val *, chk_manage_vec(0, 0, stsl, sizeof (val),
- coerce(mem_t *, &null_ptr)));
+ st->stslot = coerce(struct stslot *,
+ chk_manage_vec(coerce(mem_t *, st->stslot), stsl_upb,
+ stsl, sizeof *st->stslot,
+ coerce(mem_t *, &null_ptr)));
st->nslots = sl;
st->nstslots = stsl;
+ static_slot_home_fixup(st);
sethash(struct_type_hash, name, stype);
- if (super) {
+ if (super)
mpush(stype, mkloc(su->dvtypes, super));
- memcpy(st->stslot, su->stslot, sizeof (val) * su->nstslots);
- }
call_stinitfun_chain(st, stype);
@@ -349,8 +396,14 @@ static void struct_type_mark(val obj)
gc_mark(st->postinitfun);
gc_mark(st->dvtypes);
- for (stsl = 0; stsl < st->nstslots; stsl++)
- gc_mark(st->stslot[stsl]);
+ for (stsl = 0; stsl < st->nstslots; stsl++) {
+ struct stslot *sl = &st->stslot[stsl];
+
+ if (sl->home_type == st->self)
+ gc_mark(sl->store);
+ else
+ bug_unless (sl->store != nil);
+ }
}
static void call_initfun_chain(struct struct_type *st, val strct)
@@ -639,7 +692,8 @@ static loc lookup_slot(val inst, struct struct_inst *si, val sym)
if (slot >= STATIC_SLOT_BASE) {
struct struct_type *st = si->type;
- return mkloc(st->stslot[slot - STATIC_SLOT_BASE], st->self);
+ struct stslot *stsl = &st->stslot[slot - STATIC_SLOT_BASE];
+ return stslot_loc(stsl);
} else if (slot >= 0) {
check_init_lazy_struct(inst, si);
return mkloc(si->slot[slot], inst);
@@ -651,7 +705,8 @@ static loc lookup_slot(val inst, struct struct_inst *si, val sym)
cache_set_insert(*set, id, slnum);
if (slnum >= STATIC_SLOT_BASE) {
struct struct_type *st = si->type;
- return mkloc(st->stslot[slnum - STATIC_SLOT_BASE], st->self);
+ struct stslot *stsl = &st->stslot[slnum - STATIC_SLOT_BASE];
+ return stslot_loc(stsl);
}
check_init_lazy_struct(inst, si);
return mkloc(si->slot[slnum], inst);
@@ -672,7 +727,8 @@ static loc lookup_slot(val inst, struct struct_inst *si, val sym)
cache_set_insert(*set, id, slnum);
if (slnum >= STATIC_SLOT_BASE) {
struct struct_type *st = si->type;
- return mkloc(st->stslot[slnum - STATIC_SLOT_BASE], st->self);
+ struct stslot *stsl = &st->stslot[slnum - STATIC_SLOT_BASE];
+ return stslot_loc(stsl);
}
check_init_lazy_struct(inst, si);
return mkloc(si->slot[slnum], inst);
@@ -682,7 +738,8 @@ static loc lookup_slot(val inst, struct struct_inst *si, val sym)
return nulloc;
}
-static loc lookup_static_slot(val stype, struct struct_type *st, val sym)
+static struct stslot *lookup_static_slot_desc(val stype,
+ struct struct_type *st, val sym)
{
slot_cache_t slot_cache = sym->s.slot_cache;
cnum id = st->id;
@@ -692,7 +749,7 @@ static loc lookup_static_slot(val stype, struct struct_type *st, val sym)
cnum slot = cache_set_lookup(*set, id);
if (slot >= STATIC_SLOT_BASE) {
- return mkloc(st->stslot[slot - STATIC_SLOT_BASE], stype);
+ return &st->stslot[slot - STATIC_SLOT_BASE];
} else if (slot < 0) {
val key = cons(sym, num_fast(id));
val sl = gethash(slot_hash, key);
@@ -700,7 +757,7 @@ static loc lookup_static_slot(val stype, struct struct_type *st, val sym)
if (sl) {
cache_set_insert(*set, id, slnum);
if (slnum >= STATIC_SLOT_BASE)
- return mkloc(st->stslot[slnum - STATIC_SLOT_BASE], stype);
+ return &st->stslot[slnum - STATIC_SLOT_BASE];
}
}
} else {
@@ -717,11 +774,17 @@ static loc lookup_static_slot(val stype, struct struct_type *st, val sym)
if (sl) {
cache_set_insert(*set, id, slnum);
if (slnum >= STATIC_SLOT_BASE)
- return mkloc(st->stslot[slnum - STATIC_SLOT_BASE], stype);
+ return &st->stslot[slnum - STATIC_SLOT_BASE];
}
}
- return nulloc;
+ return 0;
+}
+
+static loc lookup_static_slot(val stype, struct struct_type *st, val sym)
+{
+ struct stslot *stsl = lookup_static_slot_desc(stype, st, sym);
+ return stsl ? stslot_loc(stsl) : nulloc;
}
static loc lookup_slot_load(val inst, struct struct_inst *si, val sym)
@@ -814,7 +877,7 @@ val static_slot_set(val stype, val sym, val newval)
if (symbolp(sym)) {
loc ptr = lookup_static_slot(stype, st, sym);
if (!nullocp(ptr)) {
- if (st->eqmslot == -1)
+ if (st->eqmslot == (struct stslot *) -1)
st->eqmslot = 0;
return set(ptr, newval);
}
@@ -823,11 +886,56 @@ val static_slot_set(val stype, val sym, val newval)
no_such_slot(self, stype, sym);
}
-val static_slot_ensure(val stype, val sym, val newval, val no_error_p)
+static void static_slot_home_fixup_rec(struct struct_type *st)
+{
+ static_slot_home_fixup(st);
+
+ {
+ val iter;
+
+ for (iter = st->dvtypes; iter; iter = cdr(iter)) {
+ val stype = car(iter);
+ struct struct_type *st = coerce(struct struct_type *, stype->co.handle);
+ static_slot_home_fixup_rec(st);
+ }
+ }
+}
+
+static void static_slot_rewrite_rec(struct struct_type *st,
+ struct stslot *from,
+ struct stslot *to)
+{
+ cnum i;
+
+ for (i = 0; i < st->nstslots; i++) {
+ struct stslot *s = &st->stslot[i];
+
+ if (s->home_type == from->home_type &&
+ s->home == from->home &&
+ s->home_offs == from->home_offs)
+ {
+ *s = *to;
+ }
+ }
+
+ {
+ val iter;
+
+ for (iter = st->dvtypes; iter; iter = cdr(iter)) {
+ val stype = car(iter);
+ struct struct_type *st = coerce(struct struct_type *, stype->co.handle);
+ static_slot_rewrite_rec(st, from, to);
+ }
+ }
+}
+
+
+static val static_slot_ens_rec(val stype, val sym, val newval,
+ val no_error_p, val self,
+ struct stslot *inh_stsl)
{
- val self = lit("static-slot-ensure");
struct struct_type *st = stype_handle(&stype, self);
- loc ptr;
+ struct stslot *stsl = lookup_static_slot_desc(stype, st, sym);
if (!bindable(sym))
uw_throwf(error_s, lit("~a: ~s isn't a valid slot name"),
@@ -835,36 +943,79 @@ val static_slot_ensure(val stype, val sym, val newval, val no_error_p)
no_error_p = default_bool_arg(no_error_p);
- if (st->eqmslot == -1)
+ if (st->eqmslot == (struct stslot *) -1)
st->eqmslot = 0;
- if (nullocp((ptr = lookup_static_slot(stype, st, sym)))) {
- val null_ptr = 0;
- if (!memq(sym, st->slots)) {
- st->stslot = coerce(val *, chk_manage_vec(coerce(mem_t *, st->stslot),
- st->nstslots, st->nstslots + 1,
- sizeof (val),
- coerce(mem_t *, &null_ptr)));
- set(mkloc(st->slots, stype), append2(st->slots, cons(sym, nil)));
- ptr = mkloc(st->stslot[st->nstslots], stype);
- sethash(slot_hash, cons(sym, num_fast(st->id)),
- num(st->nstslots++ + STATIC_SLOT_BASE));
+ if (stsl != 0 && opt_compat && opt_compat <= 151) {
+ set(stslot_loc(stsl), newval);
+ } else if (stsl != 0 && inh_stsl != 0) {
+ return newval;
+ } else if (stsl != 0 && stsl->home_type == stype) {
+ set(stslot_loc(stsl), newval);
+ return newval;
+ } else if (stsl == 0 && memq(sym, st->slots)) {
+ if (!no_error_p)
+ uw_throwf(error_s, lit("~a: ~s is an instance slot of ~s"),
+ self, sym, stype, nao);
+ return newval;
+ } else if (stsl != 0) {
+ struct stslot to;
+ to.store = nil;
+ to.home_type = stype;
+ to.home = &stsl->store;
+ to.home_offs = stsl->home_offs;
+ static_slot_rewrite_rec(st, stsl, &to);
+ set(stslot_loc(stsl), newval);
+ return newval;
+ } else {
+ struct stslot null_ptr = { nil, 0, 0, nil };
+ st->stslot = coerce(struct stslot *,
+ chk_manage_vec(coerce(mem_t *, st->stslot),
+ st->nstslots, st->nstslots + 1,
+ sizeof *st->stslot,
+ coerce(mem_t *, &null_ptr)));
+ static_slot_home_fixup_rec(st);
+ set(mkloc(st->slots, stype), append2(st->slots, cons(sym, nil)));
+ stsl = &st->stslot[st->nstslots];
+
+ if (inh_stsl == 0) {
+ stsl->store = newval;
+ stsl->home_type = stype;
+ stsl->home_offs = st->nstslots;
+ stsl->home = &stsl->store;
+ if (!opt_compat || opt_compat > 151)
+ inh_stsl = stsl;
} else {
- if (!no_error_p)
- uw_throwf(error_s, lit("~a: ~s is an instance slot of ~s"),
- self, sym, stype, nao);
+ stsl->store = nil;
+ stsl->home_type = inh_stsl->home_type;
+ stsl->home_offs = inh_stsl->home_offs;
+ stsl->home = inh_stsl->home;
}
- }
- set(ptr, newval);
+ sethash(slot_hash, cons(sym, num_fast(st->id)),
+ num(st->nstslots++ + STATIC_SLOT_BASE));
+ }
{
val iter;
+
for (iter = st->dvtypes; iter; iter = cdr(iter))
- static_slot_ensure(car(iter), sym, newval, t);
+ static_slot_ens_rec(car(iter), sym, newval, t, self, inh_stsl);
+
+ return newval;
}
+}
- return newval;
+val static_slot_ensure(val stype, val sym, val newval, val no_error_p)
+{
+ val self = lit("static-slot-ensure");
+
+ if (!bindable(sym))
+ uw_throwf(error_s, lit("~a: ~s isn't a valid slot name"),
+ self, sym, nao);
+
+ no_error_p = default_bool_arg(no_error_p);
+ return static_slot_ens_rec(stype, sym, newval, no_error_p, self, 0);
}
static val call_super_method(val inst, val sym, struct args *args)
@@ -1091,17 +1242,18 @@ static cnum struct_inst_hash(val obj, int *count)
static val get_equal_method(val stype, struct struct_type *st)
{
- if (st->eqmslot == -1) {
+ if (st->eqmslot == (struct stslot *) -1) {
return nil;
} else if (st->eqmslot) {
- return st->stslot[st->eqmslot];
+ struct stslot *stsl = st->eqmslot;
+ return stslot_place(stsl);
} else {
- loc ptr = lookup_static_slot(stype, st, equal_s);
- if (!nullocp(ptr)) {
- st->eqmslot = valptr(ptr) - st->stslot;
- return deref(ptr);
+ struct stslot *stsl = lookup_static_slot_desc(stype, st, equal_s);
+ if (stsl != 0) {
+ st->eqmslot = stsl;
+ return stslot_place(stsl);
}
- st->eqmslot = -1;
+ st->eqmslot = (struct stslot *) -1;
return nil;
}
}
diff --git a/tests/012/oop.expected b/tests/012/oop.expected
new file mode 100644
index 00000000..f0bb554f
--- /dev/null
+++ b/tests/012/oop.expected
@@ -0,0 +1,17 @@
+n/a
+dog
+collie
+animal
+dog
+collie
+animal
+canine
+collie
+animal
+canine
+collie
+poodle
+#S(b a 1 b 2 c 3)
+#S(d a nil b -2 c 3)
+(10 20 300 42 42)
+(10 -20 300 42 0)
diff --git a/tests/012/oop.tl b/tests/012/oop.tl
new file mode 100644
index 00000000..24cf2726
--- /dev/null
+++ b/tests/012/oop.tl
@@ -0,0 +1,66 @@
+(load "../common")
+
+(defstruct animal nil
+ (:function whoami () "n/a")
+ (:method print (self stream) (put-string self.[whoami] stream)))
+
+(defstruct dog animal
+ (:function whoami () "dog"))
+
+(defstruct collie dog
+ (:function whoami () "collie"))
+
+(defstruct poodle dog)
+
+(defvarl a (new animal))
+(defvarl d (new dog))
+(defvarl c (new collie))
+
+(defun print-all ()
+ (pprinl a)
+ (pprinl d)
+ (pprinl c))
+
+(print-all)
+
+(defmeth animal whoami ()
+ "animal")
+
+(print-all)
+
+(defmeth dog whoami ()
+ "canine")
+
+(print-all)
+
+(defmeth poodle whoami ()
+ "poodle")
+
+(print-all)
+
+(pprinl (new poodle))
+
+(defstruct b nil
+ (:instance a 1)
+ (:instance b 2)
+ (:instance c 3)
+ (:static sa 10)
+ (:static sb 20)
+ (:static sc 30))
+
+(defstruct d b
+ (a)
+ (b -2)
+ (:static sa)
+ (:static sb -20)
+ (:static y 0))
+
+(static-slot-ensure 'b 'x 42)
+(static-slot-ensure 'b 'y 42)
+
+(let ((b (new b sc 300))
+ (d (new d)))
+ (prinl b)
+ (prinl d)
+ (prinl (list b.sa b.sb b.sc b.x b.y))
+ (prinl (list d.sa d.sb d.sc d.x d.y)))
diff --git a/txr.1 b/txr.1
index 887f7e0b..42f986e7 100644
--- a/txr.1
+++ b/txr.1
@@ -19888,9 +19888,52 @@ read from a stream, if static slots are present, they will be processed
and their values stored in the static locations they represent, thus
changing their values for all instances.
-Static slots are inherited just like instance slots. However, when one
-structure type inherits a static slot from another, that structure type
-has its own storage location for that slot.
+Static slots are inherited just like instance slots. If a given structure
+.meta B
+has some static slot
+.metn s ,
+and a new structure
+.meta D
+is derived from
+.metn B ,
+using
+.codn defstruct ,
+and does not define a slot
+.metn s ,
+then
+.meta D
+inherits
+.metn s .
+This means that
+.meta D
+shares the static slot with
+.metn B :
+both types share a single instance of that slot.
+
+On the other hand if
+.code D
+defines a static slot
+.meta s
+then that slot will have its own instance in the
+.meta D
+structure type;
+.meta D
+will not inherit the
+.meta B
+instance of slot
+.metn s .
+Moreover, if the the definition of
+.code D
+omits the
+.meta init-form
+for slot
+.metn s ,
+then that slot will be initialized with a copy of the current value of slot
+.meta s
+of the
+.meta B
+base type, which allows derived types to obtain the value of base type's
+static slot, yet have that in their own instance.
The slot type can be overridden. A structure type deriving from another
type can introduce slots which have the same names as the supertype,
@@ -19903,13 +19946,6 @@ is invoked once in a type's life time, when the type is created.
The function is also inherited by derived struct types and invoked when
they are created.
-If a newly introduced (that is to say, non-inherited) static slot isn't
-initialized by the static initialization function, its value defaults to
-.codn nil .
-If an inherited slot isn't initialized by its supertype's initialization
-function, then its initial value in the new type is a copy of the current
-value of the supertype's corresponding slot.
-
.coNP Macro @ defstruct
.synb
.mets (defstruct >> { name | >> ( name << arg *)} < super
@@ -19955,7 +19991,7 @@ symbol, as defined by the
.code bindable
function. This form is a short form for the
.cblk
-.meti (:instance < name nil)
+.meti (:instance << name )
.cble
syntax.
.meIP >> ( symbol << init-form )
@@ -19964,7 +20000,7 @@ This syntax is a short form for the
.meti (:instance < name << init-form )
.cble
syntax.
-.meIP (:instance < name << init-form )
+.meIP (:instance < name <> [ init-form ])
This syntax specifies an instance slot called
.meta name
whose initial value is obtained by evaluating
@@ -19972,15 +20008,36 @@ whose initial value is obtained by evaluating
whenever a new instance of the structure is created.
This evaluation takes place in the original lexical environment in which the
.code defstruct
-form occurs.
-.meIP (:static < name << init-form )
+form occurs. If
+.meta init-form
+is omitted, the slot is initialized to
+.codn nil .
+.meIP (:static < name <> [ init-form ])
This syntax specifies a static slot called
.meta name
whose initial value is obtained by evaluating
.meta init-form
once, during the evaluation of the
.code defstruct
-form in which it occurs.
+form in which it occurs, if the
+.meta init-form
+is present. If
+.meta init-form
+is absent, and a static slot with the same name
+exists in the
+.meta super
+base type, then this slot is initialized
+with the value of that slot.
+Otherwise it is initialized to
+.codn nil .
+
+The definition of a static slot in a
+.code defstruct
+causes the new type to have its own instance
+that slot, even if a same-named static
+slot occurs in the
+.meta super
+base type, or its bases.
.meIP (:method < name <> ( param +) << body-form *)
This syntax creates a static slot called
.meta name
@@ -20011,6 +20068,11 @@ Methods are invoked
using the
.code "instance.(name arg ...)"
syntax, which implicitly inserts the instance into the argument list.
+
+Due to the semantics of static slots, methods are naturally
+inherited from a base structure to a derived one,
+and defining a method in a derived class which also exists
+in a base class performs OOP-style overriding.
.meIP (:function < name <> ( param *) << body-form *)
This syntax creates a static slot called
.meta name
@@ -20041,6 +20103,12 @@ Such functions are called using the
.code "instance.[name arg ...]"
syntax which doesn't insert the instance into
the argument list.
+
+The remarks about inheritance and overriding
+in the description of
+.code :method
+also apply to
+.codn :function .
.meIP (:init <> ( param ) << body-form *)
The
.code :init
@@ -20183,29 +20251,33 @@ in the
type or that type's chain of ancestors, it is called a
.IR "repeated slot" .
-A repeated slot inherits initialization forms from all of its ancestors.
-
The kind of the repeated slot (static or instance) is not inherited; it
is established by the
.code defstruct
and may be different from the type of the same-named slot in the
supertype or its ancestors.
-A repeated slot only inherits the initializations which correspond to
-its kind. If a repeated slot is introduced as a static slot, then
-all of the static initializations in the ancestry chain are performed
-on that slot, which takes place during the evaluation of the
-.code defstruct
-form. If that slot is an instance slot in any of the
-ancestor structure types, their initializations do not apply and are not
-evaluated.
+If a repeated slot is introduced as a static slot, and
+has no
+.meta init-form
+then it receives the current of the a static of the same name from
+the nearest supertype which has such a slot.
-If a repeated slot is introduced as an instance slot then none of the static
-initializations in the ancestry chain are performed on it; none of the forms
-are evaluated. Those initializations target a static slot, which the derived
-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.
+If a repeated slot is an instance slot, no such inheritance of value
+takes place; only the local
+.meta init-form
+applies to it; if it is absent, the slot it initialized to
+.code nil
+in each newly created instance of the new type.
+
+However,
+.code :init
+and
+.code :postinit
+initializations are inherited from a base type and they apply to
+the repeated slots, regardless of their kind. These initializations
+take place on the instantiated object, and the slot references
+resolve accordingly.
The initialization for slots which are specified using the
.code :method
@@ -20379,10 +20451,8 @@ If
is used to redefine an existing method, the semantics can be inferred
from that of
.codn static-slot-ensure .
-In particular, the method will be imposed into all subtypes which do not
-override the method using an instance slot, overwriting any subtype-specific
-methods stored in static slots of the same name. These subtype methods
-have to be individually reinstated, if they are required.
+In particular, the method will be imposed into all subtypes which inherit
+(do not override) the method.
.coNP Macros @ new and @ lnew
.synb
@@ -20884,11 +20954,9 @@ which is equivalent to specifying a function which does nothing.
Prior to the invocation of
.metn static-initfun ,
-each new static slot shall be initialized to the value
-.code nil
-and each inherited static slot shall be initialized to
-the current value which the corresponding static slot
-holds in the supertype.
+each new static slot shall be initialized the value
+.codn nil .
+Inherited static slots retain their values from the supertype.
If specified,
.meta static-initfun
@@ -20896,11 +20964,10 @@ function must
accept one argument. When the structure type is created (before
the
.code make-struct-type
-function returns) all of the
+function returns) the
.meta static-initfun
-functions in the chain of supertype ancestry are invoked, in
-order of inheritance. Each is passed the structure type as an argument. The
-purpose is to initialize the static slots.
+functions is invoked, passed the newly created
+structure type as its argument.
The
.meta initfun
@@ -21521,36 +21588,88 @@ must be a static slot of this type.
.desc
The
.code static-slot-ensure
-first ensures that the struct type
+ensures, if possible, that the struct type
+.metn type ,
+as well as possibly one or more struct types derived from it,
+have a static slot called
+.metn name ,
+that this slot is not shared with a supertype,
+and that the value stored in it is
+.metn new-value .
+
+Note: this function supports the redefinition of methods,
+as the implementation underlying the
+.code defmeth
+macro; its semantics is designed to harmonize with expected
+behaviors in that usage.
+
+The function operates as follows.
+
+If
.meta type
-and all struct types derived from it have a static slot called
-.metn name .
-The slot is added as a static slot to every eligible type which doesn't already
-have an instance or static slot by that name.
+itself already has an instance slot called
+.meta name
+then an error is thrown, and the function has no effect, unless a
+true argument is specified for the
+.meta no-error-p
+Boolean parameter. In that case, in the same situation, the function
+has no effect and simply returns
+.metn new-value .
-Then,
-.meta new-value
-is stored into all of the
+If
+.meta type
+already has a non-inherited static slot called
.meta name
-static slots of
+then this slot is overwritten with
+.meta new-value
+and the function returns
+.metn new-value .
+Types derived from
.meta type
-and all its derived types.
+may also have this slot, via inheritance; consequently, its value
+changes in those types also.
If
.meta type
-itself already has an instance slot called
+already has an inherited static slot called
.meta name
-then an error is thrown, and the function has no effect. If the same situation
-is true of the subtypes of
+then its inheritance is severed; the slot is converted
+to a non-inherited static slot of
.meta type
-then the situation is ignored: for those subtypes, no static slot is added, and
-.meta new-value
-is not stored. If the
-.meta no-error-p
-argument is present, and its value is true, then
+and initialized with
+.metn new-value .
+Then all struct types derived from
+.meta type
+are scanned. In each such type, if the original inherited
+static slot is found, it is replaced with the same
+newly converted static slot that was just introduced into
+.metn type ,
+so that all these types now inherit this new slot from
.meta type
-is treated just like the subtypes: if it has a conflicting instance slot,
-then the situation is ignored and the subtypes are processed anyway.
+rather than the original slot from some supertype of
+.metn type .
+These types all share a single instance of the slot with
+.metn type ,
+but not with supertypes of
+.metn type .
+
+In the remaining case,
+.meta type
+has no slot called
+.metn name .
+The slot is added as a static slot to
+.metn type .
+Then it is added to every struct type derived from
+.meta type
+which does not already have a slot by that name, as if
+by inheritance. That is to say, types to which this slot is introduced share a
+single instance of that slot. The value of the new slot is
+.metn new-value ,
+which is also returned from the function. Any subtypes of
+.meta type
+which already have a slot called
+.meta name
+are ignored, as are their subtypes.
.coNP Function @ call-super-method
.synb
@@ -46577,6 +46696,42 @@ of these version values, the described behaviors are provided if
is given an argument which is equal or lower. For instance
.code "-C 103"
selects the behaviors described below for version 105, but not those for 102.
+.IP 151
+After version 151, changes were implemented to the way static slots work
+in \*(TL structs. Selecting compatibility with 151 restores most of the behaviors.
+Until 151, each structure type had its own instance of static slots whether
+they were newly defined or inherited. Under the new scheme, a derived struct
+shares one instance of each inherited static slot with its base type.
+Under the old scheme, a struct inherits the static
+initialization functions of its bases (the
+.meta static-initfun
+argument passed in
+.codn make-struct-type ).
+These are invoked invoked because they are relied upon by the
+.code defstruct
+macro to perform the initializations of all the inherited static slots.
+Under the new scheme, the static initialization functions are not inherited.
+Only the type's own
+.meta static-initfun
+is invoked to initialize its newly defined static slots that it doesn't
+share with the parent. The inherited static slots simply preserve their
+current values they have in the base type; their values are untouched by
+the introduction of a derived type. The
+.code static-slot-ensure
+also changed semantics after version 151. The old behavior was problematic
+because it affected all static slots throughout the inheritance hierarchy
+matching the name passed in by argument. Since this function is the basis
+for redefining methods, its behavior broke the semantics of overriding.
+Selecting 151 compatibility only restores the behavior of this
+function and macros based on it like
+.codn defmeth :
+in the situation when it introduces a new static slot into one or more
+struct types, in compatibility mode it introduces the slot separately into each
+type without sharing, and it recurses over the entire type hierarchy,
+storing
+.meta new-val
+into all static slots which match
+.metn name .
.IP 150
Until version 150, the
.code match-regex