combining two variables into one function name in macro

后端 未结 4 1279
没有蜡笔的小新
没有蜡笔的小新 2020-12-11 22:18

I was toying around with macros and clos, where I created an \"object\" macro to create instances

(defmacro object (class &rest args)
  `(make-instance \         


        
4条回答
  •  再見小時候
    2020-12-11 22:38

    If you want your gets to use accessor methods:

    (defmacro gets (class var object)
      `(,(intern (format nil "~a-~a" (symbol-name class) (symbol-name var))) ,object))
    

    In general, what you're trying to accomplish is not really useful. make-instance is a well known symbol, easily greppable, part of the standard and optimized by some implementations when the class name is constant. So with your object macro, you're just saving a few characters and a single-quote. Usually, one hides make-instance in specific cases where you don't want to provide a direct way to initialize instances, or more likely, when you want to provide layers of initialization (e.g. phases of initialization, Lisp slots and foreign objects).


    PS: I remember vaguely that someone prominent in the standardization of Common Lisp argued in favor of always wrapping/hiding make-instance in a function (e.g. make-), but I can't find either a reference or the reasoning.


    PPS: Here's a rather old discussion (2004) about it in comp.lang.lisp (and another one from 2002). The main reasons people cite in favor of constructor functions are:

    1. Required arguments; achievable at runtime instead of at compile-time with :initform (error ...) in a slot that requires a provided initial value

    2. Generally, hide implementation details: class instance, structure instance, cons, something else

      2.1. Not wanting to export the actual class name

      2.2. Being able to return an instance of some other class, usually a subclass

    3. Convenient shorthand for a specific class

    I striked always, because it seems proponents to constructor functions for CLOS objects don't necessarily want to hide the protocol that make-instance follows (allocate-instance, initialize-instanceshared-initialize) to implementers or extenders of the API or framework, although they might want to hide it to the consumers of the API or framework.


    For something faster, you might want to access slots directly, but that doesn't use accessor methods, and hence doesn't support side-effects, e.g. :before and :after methods:

    (defmacro gets (class var object)
      (let ((object-var (gensym)))
        `(let ((,object-var ,object))
           (declare (optimize (speed 3) (safety 0) (debug 0))
                    (type ,class ,object-var))
           (slot-value ,object-var ',var))))
    

    This might be a direct slot access on some implementations.

    Finally, you also have with-slots and with-accessors in the standard.

提交回复
热议问题