[armedbear-devel] Problem with defstruct accessor functions and included structures in combination with conc-names

Erik Huelsmann ehuels at gmail.com
Sat Aug 18 20:31:39 UTC 2012

Hi Ralf,

Sorry for the late response. I've been really busy improving some other
parts of ABCL which consumed all my time.

> This slot accessor is not to be generated again for "c", of course, as you
>> said. The strange thing this is that, in principle, foo-s1 is not
>> applicable to instances of "a", but to instances of "b" and "c" only. Since
>> new sub-structures of "a" (with conc-name foo-) can be defined at any time,
>> the type for the applicable structures used in the implementation of foo-s1
>> cannot be statically encoded but must be dynamically determined, or the
>> code for foo-s1 could be dynamically adapted for every new sub-defstruct of
>> "a" with conc-name foo-. I tend to believe this is not easy to implement.
> Actually, it's really easy to implement.
> I am afraid, using defmethod for the non-optimized case is not that easy
> because not all defstructs are necessarily compiled with the same
> optimization settings (e.g., they might be located in different files). In
> addition, one has to remove methods if a defstruct is recompiled with other
> slots or with different optimization settings..... :-(

The part about the accessors being defined in different files with
different optimization strategies: that's correct. However, it's not the
context of the definer, but the context of the user which causes the
optimized or non-optimized code path to be used.

With respect to recompilation/redefinition of a defstruct: the spec says
you can't do that, or at least, you can't portably depend on that ("The
consequences of redefining a
are undefined."). ABCL allows it, under certain strict conditions, but it's
not required to and doesn't support any "interesting" cases (ie changes in
the number of slots).
But the case of method removal is easy: when a defmethod is evaluated, it
will cause the original method with the same specializers to be
overwritten. That, combined with the explanation that all accessors are
always generated (but only sometimes used), should solve it.

> But the runtime cost of doing so is huge, unfortunately: we can simply use
> DEFMETHOD to define the accessors. That will automatically notice the
> accessor is already defined and add a method for each additionally defined
> type.
> [ snip ]

> I see multiple options:
> 1. Remove the type checks in the inline expansions
>    and use DEFMETHOD for the accessor functions, where we need to use the
> methods
>    only with sufficiently high SAFETY declarations
> 2. Use your patch to remove the type checks completely
> 3. Come up with a way to add dynamic type checks to the inline expansions
> and function definitions (ie not methods) - possibly executed conditionally
> with safety settings.
> 4. Do nothing (not saying it's a good option, but it's always an option)
> Do you see any others?
> Actually, I see one other solution, now that I had some time to think
about it: we could trace back to the original type and be lenient and allow
all descendants of that type access to the slot using the generated slot.
That would allow both structures B and C to be read. According to the spec
that's too lenient though:

The difference between the
 functions person-name and astro-name is that person-name can be correctly
applied to any person, including anastronaut, while astro-name can be
correctly applied only to an astronaut. An implementation might check for
incorrect use of

where "name" is a slot in the 'person' structure which is included in the
'astronaut' structure.
Just to see what other implementations do: I ran this code on clisp (2.47)
and it generates the same error. Apparently, the spec doesn't define this
case and you can't depend on exact behaviour; the only thing I *can* find
is a section on the relation between including and included structures, not
between syblings:

Whether or not the :conc-name option is explicitly supplied, the following
rule governs name conflicts of generated
 (or *accessor*<http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_a.htm#accessor>)
names: For any *structure*<http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#structure>
having a *reader*<http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_r.htm#reader>
named R for a slot named X1 that is inherited by another
that would have a
with the same name R for a slot named X2, no definition for R is generated
by the definition of S2; instead, the definition of R is inherited from the
definition of S1. (In such a case, if X1 and X2 are different slots, the *
signal a style warning.)

Which suggests that if you used FOO- for the nconc of the A structure as
well, that all should be defined and well. Testing that on clisp and ABCL
shows that it indeed is.

> I'm not sure about the performance impact of dynamic checks, but I do
> think that if we decide to apply a caching strategy, using the slow-path of
> updating the cache in case of a type-mismatch, the impact may not be much
> worse than it is today. After all, the biggest change would be to generate
> code which allows to check more than one type instead of the current single
> type.
> Given the performance impact of more complicated checks and the fact that
structures are supposed to be geared for high performance (with classes
being their flexible counter parts) *and* with the support (for my point)
that I find in the spec and "other implementations" (i.e. clisp), I'd
rather keep things the way they are at this time, although I'm open to
input of the other developers of course.

Is it a solution for you to add the FOO- conc-name option to the A class as


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/armedbear-devel/attachments/20120818/1bac7c77/attachment.html>

More information about the armedbear-devel mailing list