emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Emacs-diffs] trunk r117002: Correctly treat progn contents as tople


From: Daniel Colascione
Subject: Re: [Emacs-diffs] trunk r117002: Correctly treat progn contents as toplevel forms when byte compiling
Date: Mon, 21 Apr 2014 21:46:58 -0700
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:24.0) Gecko/20100101 Thunderbird/24.4.0

On 04/21/2014 09:25 PM, Stefan Monnier wrote:
>>> That's not the kind of example I was thinking if.  Do you have a real
>>> example, maybe?
>> Try writing a macro that emits a defstruct, then a function that uses
>> cl-typep for that struct, all wrapped in the same toplevel progn.
> 
> That's getting closer to an actual example.  I still can't think of
> a case where you'd want to use cl-typep in this way, tho.

cl-struct-slot-value uses typep  It makes sense to do so given that
cl-struct-slot-value knows the name of the struct, but not necessarily
the name of its predicate function --- which might not even exist.

The chunk below is from the iface code I'm working on. This code isn't
even close to done --- it's just here to give you a sense of the
problem. You see that we declare a structure, then emit some functions
that use the structure. Some of these functions go on to do things with
values that are allegedly of the structure type, and they use typep to
check that these values are actually of the struct type. This approach
is a perfectly logical way to go about writing code, and we should
support it. Forcing users to do something else is especially pernicious
because the problem we're discussing only shows up when compiling (or
loading) files --- in normal interactive development, everything seems fine!

(eval-and-compile
  (defun iface--make-member-wrapper (iface-name member)
    "Create a lisp form defining an interface accessor.
IFACE-NAME is a symbol giving the name of the interface being
defined.  MEMBER is an element of the MEMBERS parameter to
`iface-declare'."
    (cl-destructuring-bind ((member-name inst-arg &rest xarglist)
                            &optional doc) member
      (unless (and inst-arg
                   (symbolp inst-arg)
                   (not (eql (aref (symbol-name inst-arg) 0) ?\&)))
        (error (concat "Interface members must accept an instance as"
                       " their first argument")))
      `(defun ,member-name (,inst-arg &rest xargs)
         ,doc
         (declare (advertised-calling-convention (,inst-arg ,@xarglist)
                                                 ,emacs-version))
         (apply (cl-struct-slot-value ',iface-name ',member-name ,inst-arg)
                ,inst-arg xargs)))))

(cl-defmacro iface-declare ((name base) &rest members)
  "Create a new interface called NAME, inheriting from BASE.
MEMBERS is a list of member specifiers.  Each is a list of the form
 ((NAME . ARGUMENTS) DOCUMENTATION), where NAME is a symbol
naming the interface member, ARGUMENTS is a cl-lib-style argument
list, and DOCUMENTATION is documentation to attach to that
function."
  (let ((doc (and (stringp (car members)) (pop members)))
        (prefix (concat (symbol-name name) "--iface-")))
    `(progn
       (cl-defstruct (,name (:include ,base)
                            (:conc-name ,(intern prefix))
                            (:copier nil))
         ,@(if doc (list doc))
         ,@(mapcar #'caar members))
       ,@(mapcar (lambda (member)
                   (iface--make-member-wrapper name member))
                 members)
       ',name)))

>> The reason we have automated tests is to make sure we can maintain this
>> "level of detail". That it's not immediately useful to you isn't a
>> reason not to include it. I can't believe this issue is even
>> contentious: the current behavior is a clear bug.
> 
> It's a clear bug if we assume Common-Lisp semantics.  But in many cases,
> Elisp chooses to provide simpler semantics, to allow a simpler and/or
> more naive implementation.

I don't care whether we diverge from CL in sets of supported features
and names of functions, but we should try hard to match CL's fundamental
execution semantics. Practically every possible bad lisp idea was tried
before Common Lisp came around. The CL people knew about the precise
problem we're discussing on this thread and codified the best solution
in the language. There are solutions in CL for problems that we haven't
even encountered yet. The less closely we follow CL, the less we benefit
from the experience baked into the specification and the harder it is to
fix problems that eventually do come up.

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]