On 04/21/2014 03:03 PM, Stefan Monnier wrote: >> That's new. Using the whole ChaneLog message has been a recommendation, >> but never a requirement. > > For `elpa', that's true, but for `emacs' it's always been a requirement, > on the premise that this should/will allow us to drop the ChangeLog > files at some point. Thanks for the clarification. >> Now there's one more step on the commit path, and a useless one at >> that: the changelog entry is available in the change itself and in the >> message to the mailing list. > > C-x v v can copy the message from ChangeLog for you (and set Author: > and Fixes: at the same time), so it's not so bad. Can it? I tried it in vc-dir and got a completely unrelated ChangeLog hunk. > The way to fix this, is to make ChangeLog unneeded. First step on this > path is to provide some way to make `C-x 4 a' usable without ChangeLog. > >>>> +The @code{cl-defstruct} package also provides a few structure >>>> +introspection functions. >>> I'm curious: when/where did you bump against a need for that? >> I have a few private macros that lexically bind structure slots, > > Which part makes it impossible/impractical to use standard accessors for > that? :conc-name, for starters. Also, :read-only, although you could argue that you shouldn't go around mutating read-only slots anyway. >> and this information is also needed for some interface-generation work >> I'm thinking of doing. > > Not sure what "interface-generation" means, but it sounds interesting. I'm just playing around at this point --- but the basic idea is that we need some way to connect independent Emacs components, and this mechanism should be more structured than some kind of do-everything-in-a-giant-cond handler function, but much lighter and more comprehensible than EIEIO. One approach is to define COM-like (wait! keep reading!) "interface" structures that bundle useful functions into composeable pieces, then have Emacs components interact in terms of these interfaces. We can make them very lightweight, and let all interfaces inherit from a common interface that lets callers ask for additional functionality: (iface-declare (iface-base nil) "Interface from which all others inherit." ((iface-query instance interface) "Get an implementation of INTERFACE from INSTANCE.")) For example, we could define some project interfaces like this: (iface-declare (project iface-base) ((project-get-root-directory project ) "Find the root directory of PROJECT.") ((project-get project property) "Get a project property PROPERTY.") ((project-put project property value) "Set a project property PROPERTY to VALUE.")) (iface-declare (project-c iface-base) ((project-c-include-directories project file) "Return a list of include directories for FILE in PROJECT. FILE is a fully-qualified name.")) iface-declare defines trivial wrapper functions that make it convenient to call through interface fields. So the generated definition of project-get, for example, would look like this: (defun project-get (inst &rest xargs) "Get a project property PROPERTY." (declare (advertised-calling-convention (project property)) (apply (cl-struct-slot-value 'project 'get inst) xargs)) If you have a project and want to see whether it supports finding C include paths, you'd just use iface-query with 'project-c, and if that succeeds, call (project-c-include-directories my-c-project file). You'd actually *make* interface instances by building an interface struct as you would any other struct and supply closures (e.g., the result of `apply-partially') for the slot values so that you can maintain state (or not) between subsequent calls on the same interface instance. Anyway, all of this would be very lightweight and (I think) resolvable completely at compile time. Note that it's probably not a good idea to go even simpler and have, say, my-git-project inherit from project directly: what if the size of project changes? (Things would break because cl-defstruct accessors hardcode field offsets, and that's a good thing.) What if you want to implement multiple pieces of optional functionality? (Sure, you can make some struct fields nullable, but then you have to provide some way to query whether a field is actually implemented.) Better to just define additional interfaces for optional functionality. The interface approach seems decently light and extensible, and the implementation complexity is low. >>>> +@defun cl-struct-set-slot-value struct-type slot-name inst value >>> We don't need this, since we can always use setf instead. >> So? We have both (setf (aref ...) ...) and (aset ...). > > That's only because (setf (aref ...) ...) needs to macroexpand to something. > [ It's one of the differences between Common-Lisp and Elisp. ] > > In your case, (setf (cl-struct-slot-value ...) ...) can macroexpand to > something without needing cl-struct-set-slot-value. Actually, in order > for (incf (cl-struct-slot-value ...)) not to compute the offset twice, > (setf (cl-struct-slot-value ...) ...) will end up expanding to something > else than a call to cl-struct-set-slot-value. > >> That test was there in cl-check-type. The test doesn't make sense to me >> either. We should drop it in both places if we drop it in cl-the. > > Great, let's drop it then. Thanks. Will do. That test never made much sense to me anyway. >>>> +(cl-define-compiler-macro cl-struct-slot-value >>> Please use (declare (compiler-macro ..)). >> Why? In both cases, the compiler macro is written out-of-line and in >> both cases, we just stick the compiler macro on the symbol's plist. > > Because that's the style we use in Elisp. Well, recently. ;-) It wasn't too long ago that the style was to let-bind dozens of variables at the top of huge functions and setq them everywhere. > Note that (declare (compiler-macro ..)) can provide the compiler-macro > "inline" or "out-of-line". Sure, but it'll be really ugly if it's inline and relatively large (as the macros here are). It goes with a trend I've noticed in the APIs you've implemented, though: you seem to prefer having people defun regular functions and combine them in interesting ways (e.g., with advice-add) instead of using top-level definition forms directly (e.g., defadvice). I largely agree with your approach. > >>> I guess this goes back to the earlier question about when/where the use >>> for this functionality came up. >> Unless we're using this functionality in generated code where, while the >> slot is constant, it's more convenient to use that slot's name than to >> try to determine the accessor name. > > Ah, so it's for code generated based on cl-struct-slot-info? > Right, that makes sense.