* Semantics of :initform and oset-default
@ 2015-02-09 2:48 Stefan Monnier
2015-02-09 13:06 ` Eric Ludlam
0 siblings, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2015-02-09 2:48 UTC (permalink / raw)
To: Eric M. Ludlam; +Cc: emacs-devel
Hi Eric,
I have some questions about the default values of object slots:
- The Texinfo docs say:
[...]
The value passed to initform is automatically quoted. Thus,
:initform (1 2 3)
appears as the specified list in the default object. A symbol that
[...]
this seems to say that :initform is really an init*value*. But then
in eieio-tests.el we have:
(defclass inittest nil
((staticval :initform 1)
(symval :initform eieio-test-permuting-value)
(evalval :initform (symbol-value 'eieio-test-permuting-value))
(evalnow :initform (symbol-value 'eieio-test-permuting-value)
:allocation :class)
)
"Test initforms that eval.")
(ert-deftest eieio-test-21-eval-at-construction-time ()
;; initforms that need to be evalled at construction time.
(setq eieio-test-permuting-value 2)
(setq eitest-pvinit (inittest))
(should (eq (oref eitest-pvinit staticval) 1))
(should (eq (oref eitest-pvinit symval) 'eieio-test-permuting-value))
(should (eq (oref eitest-pvinit evalval) 2))
(should (eq (oref eitest-pvinit evalnow) 1)))
which gives a different picture, and I don't really understand it: in
the `symval' slot the :initform seems to be quoted (as documented),
but in the other two (`evalval' and `evalnow') the :initforms are
actually evaluated.
- How is it supposed to interact with oset-default? Is the value passed
to `oset-default' interpreted as a plain value (to which the slot
will always be initialized), or is it interpreted as a "maybe
value maybe expression to be evaluated", like the :initform?
Stefan
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Semantics of :initform and oset-default
2015-02-09 2:48 Semantics of :initform and oset-default Stefan Monnier
@ 2015-02-09 13:06 ` Eric Ludlam
2015-02-09 14:56 ` Stefan Monnier
0 siblings, 1 reply; 5+ messages in thread
From: Eric Ludlam @ 2015-02-09 13:06 UTC (permalink / raw)
To: Stefan Monnier, Eric M. Ludlam; +Cc: emacs-devel
On 02/08/2015 09:48 PM, Stefan Monnier wrote:
> Hi Eric,
>
> I have some questions about the default values of object slots:
>
> - The Texinfo docs say:
>
> [...]
> The value passed to initform is automatically quoted. Thus,
> :initform (1 2 3)
> appears as the specified list in the default object. A symbol that
> [...]
>
> this seems to say that :initform is really an init*value*. But then
> in eieio-tests.el we have:
>
> (defclass inittest nil
> ((staticval :initform 1)
> (symval :initform eieio-test-permuting-value)
> (evalval :initform (symbol-value 'eieio-test-permuting-value))
> (evalnow :initform (symbol-value 'eieio-test-permuting-value)
> :allocation :class)
> )
> "Test initforms that eval.")
>
> (ert-deftest eieio-test-21-eval-at-construction-time ()
> ;; initforms that need to be evalled at construction time.
> (setq eieio-test-permuting-value 2)
> (setq eitest-pvinit (inittest))
>
> (should (eq (oref eitest-pvinit staticval) 1))
> (should (eq (oref eitest-pvinit symval) 'eieio-test-permuting-value))
> (should (eq (oref eitest-pvinit evalval) 2))
> (should (eq (oref eitest-pvinit evalnow) 1)))
>
> which gives a different picture, and I don't really understand it: in
> the `symval' slot the :initform seems to be quoted (as documented),
> but in the other two (`evalval' and `evalnow') the :initforms are
> actually evaluated.
Hi Stefan,
Originally eieio only had an initvalue as you named it above because I
didn't get what was supposed to happen with the initform, and I had a
lame lambda form for cases where you might want to evaluate the form at
construction time. The doc may not have been updated correctly when I
tried to make eieio more CLOS compatible based on the feedback I was
getting.
It was pointed out that the initform is supposed to be evaluated so
there is a bit of a hybrid behavior which allows:
:initform "string"
which would work regardless of how/when things are evaluated. It also
enables the very old eieio behavior:
:initform (1 2 and other constants) ;; No quote needed
and also what a CLOS user might expect:
:initform '(1 2 and other constants) ;; same end result as above
plus function evaluation:
:initform (symbol-value 'some-variable)
which is in the test you quoted.
The logic is up in `eieio-default-eval-maybe'.
The 'evalnow, and 'evalval slots in the test differ based on when they
get evaluated.
A slot with :allocation :instance (the default) would have the form
evaluated when it is constructed. A slot with :allocation :class is
evaluated when the class is created. If just the symbol is in there, it
acts as a constant value (ie - no function form to call)
> - How is it supposed to interact with oset-default? Is the value passed
> to `oset-default' interpreted as a plain value (to which the slot
> will always be initialized), or is it interpreted as a "maybe
> value maybe expression to be evaluated", like the :initform?
oset default doesn't have anything special around when the VALUE
argument is evaluated, so that form is evaluated the way arguments to
other functions are evaluated.
If you wrote:
(oset-default 'myclass someslot '(symbol-value 'moose))
then the first quote would be 'evaluated' sticking the form
(symbol-value 'moose) into the initform for that slot. Then at
instantiation time, the symbol value of moose would be calculated and
stuck in as the slot value. ie:
ELISP> (setq moose 1)
1
ELISP> (oset-default 'foo test '(symbol-value 'moose))
(symbol-value 'moose)
ELISP> (foo "hi")
[object foo "hi" 1]
I don't know if that is correct or not. It didn't occur to me that you
could do that until I tried explaining just now.
Here is the documentation I had used at the time:
http://www.lispworks.com/documentation/HyperSpec/Body/m_defcla.htm
and the key bit of text:
> The :initform slot option is used to provide a default initial value
> form to be used in the initialization of the slot. This form is
> evaluated every time it is used to initialize the slot.
It goes on to talk about the lexical environment which I didn't/don't
know how to deal with.
I hope this helps.
Eric
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Semantics of :initform and oset-default
2015-02-09 13:06 ` Eric Ludlam
@ 2015-02-09 14:56 ` Stefan Monnier
2015-02-10 0:27 ` Eric Ludlam
0 siblings, 1 reply; 5+ messages in thread
From: Stefan Monnier @ 2015-02-09 14:56 UTC (permalink / raw)
To: Eric Ludlam; +Cc: Eric M. Ludlam, emacs-devel
> It was pointed out that the initform is supposed to be evaluated so there
> is a bit of a hybrid behavior which allows:
Ah, the historical account is quite helpful: now the weird hack makes
a lot more sense.
> A slot with :allocation :instance (the default) would have the form
> evaluated when it is constructed. A slot with :allocation :class is
> evaluated when the class is created. If just the symbol is in there, it
> acts as a constant value (ie - no function form to call)
Yes, this is the standard CLOS behavior, indeed.
ELISP> (setq moose 1)
> 1
ELISP> (oset-default 'foo test '(symbol-value 'moose))
> (symbol-value 'moose)
ELISP> (foo "hi")
> [object foo "hi" 1]
Yuck! You just forced EIEIO to use runtime code generation (since it
had to turn the (symbol-value 'moose) list into a chunk of code).
> I don't know if that is correct or not. It didn't occur to me that you
> could do that until I tried explaining just now.
Hmm... I wonder if someone relies on this misfeature.
> Here is the documentation I had used at the time:
> http://www.lispworks.com/documentation/HyperSpec/Body/m_defcla.htm
Yes, this describes the :initform semantics, but not its interaction
with `oset-default' since CLOS doesn't have anything like
`oset-default'.
> It goes on to talk about the lexical environment which I didn't/don't know
> how to deal with.
It's easy: turn every initform in the defclass definition into a lambda
expression and store that (i.e. a closure instead of a "form") into the
class's slot descriptor. Then, instead of `eval', use `funcall' in
(the equivalent of) eieio-default-eval-maybe.
Stefan "Every time you have to use `eval', a baby cries"
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Semantics of :initform and oset-default
2015-02-09 14:56 ` Stefan Monnier
@ 2015-02-10 0:27 ` Eric Ludlam
2015-02-10 2:47 ` Stefan Monnier
0 siblings, 1 reply; 5+ messages in thread
From: Eric Ludlam @ 2015-02-10 0:27 UTC (permalink / raw)
To: Stefan Monnier, Eric Ludlam; +Cc: Eric M. Ludlam, emacs-devel
On 02/09/2015 09:56 AM, Stefan Monnier wrote:
> ELISP> (setq moose 1)
>> 1
> ELISP> (oset-default 'foo test '(symbol-value 'moose))
>> (symbol-value 'moose)
> ELISP> (foo "hi")
>> [object foo "hi" 1]
> Yuck! You just forced EIEIO to use runtime code generation (since it
> had to turn the (symbol-value 'moose) list into a chunk of code).
>
>> I don't know if that is correct or not. It didn't occur to me that you
>> could do that until I tried explaining just now.
> Hmm... I wonder if someone relies on this misfeature.
>
I doubt it. The important function is eieio-oref-default which is used
for getting defaults so it can initialize objects, and produce
documentation via `describe-class'. I wrote the oset-default to be
complete. It's proven useful a couple times, but the cases I have are
all pretty simple constants except for the 'singleton' class which isn't
that complex either.
Eric
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2015-02-10 2:47 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-02-09 2:48 Semantics of :initform and oset-default Stefan Monnier
2015-02-09 13:06 ` Eric Ludlam
2015-02-09 14:56 ` Stefan Monnier
2015-02-10 0:27 ` Eric Ludlam
2015-02-10 2:47 ` Stefan Monnier
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.