all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* 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

* Re: Semantics of :initform and oset-default
  2015-02-10  0:27     ` Eric Ludlam
@ 2015-02-10  2:47       ` Stefan Monnier
  0 siblings, 0 replies; 5+ messages in thread
From: Stefan Monnier @ 2015-02-10  2:47 UTC (permalink / raw
  To: Eric Ludlam; +Cc: Eric M. Ludlam, emacs-devel, Eric Ludlam

>> Hmm... I wonder if someone relies on this misfeature.
> I doubt it.

My grepping agrees.
I installed a check in oset-default which signals an error if the value
would trigger `eval' in eieio-eval-default-maybe.


        Stefan



^ 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.