【问题标题】:How to portably create a class at run-time in Common-Lisp CLOS如何在运行时在 Common-Lisp CLOS 中可移植地创建一个类
【发布时间】:2017-02-12 12:15:39
【问题描述】:

我需要在运行时创建一个类,可能不使用 eval。知道Common-Lisp中元类协议没有完全标准化,浏览了The Common Lisp Object System MetaObject Protocol之后,我尝试了下面的代码来创建一个类,实例化它,并将实例的一个槽值设置为一个数字:

(defparameter *my-class*
  (make-instance 'standard-class
                 :name 'my-class
                 :direct-slots '((:name x :readers (get-x) :writers ((setf get-x))))))

(defparameter *my-instance* (make-instance *my-class*))

(setf (get-x *my-instance*) 42) ;; => 42

不幸的是,这段代码在 SBCL 上正常工作,但在 CCL 上却不能正常工作,在 CCL 上,类创建似乎工作,但实例创建 (make-instance *my-class*) 导致以下错误:

There is no applicable method for the generic function:
  #<STANDARD-GENERIC-FUNCTION INITIALIZE-INSTANCE #x30200002481F>
when called with arguments:
  (#<error printing CONS #x302001A9F6A3>
   [Condition of type CCL:NO-APPLICABLE-METHOD-EXISTS]

我尝试查看 closer-mop 包,它应该隐藏元对象协议的各种实现之间的差异,但我找不到任何对我的范围有用的函数或类。

所以问题是:有没有一种可移植的方式来创建一个类并在运行时通过直接使用 CLOS 的元类级别来实例化它?

【问题讨论】:

  • 使用更紧密的拖把,您可以尝试ensure-classensure-class-using-class
  • 如果您也指定直接超类,CCL 似乎也可以工作:direct-superclasses (list (find-class 'standard-object))
  • 谢谢@jkiiski,问题是我应该指定超类。如果您将其发布为答案,我会接受。
  • 谢谢,@coredump,实际上ensure-class 不适用于我的参数,但如果我添加直接超类standard-object 则可以正常工作(我以为这是默认设置,但也许这是仅适用于 defclass)。
  • 哦,因为 B->C 确实没有保存。

标签: common-lisp sbcl clos ccl


【解决方案1】:

CCL 似乎也要求您手动指定直接超类。

(defparameter *my-class*
  (make-instance 'standard-class
                 :name 'my-class
                 :direct-slots '((:name x :readers (get-x) :writers ((setf get-x))))
                 :direct-superclasses (list (find-class 'standard-object))))

【讨论】:

    【解决方案2】:

    通常会使用ENSURE-CLASS 创建一个类。 ENSURE-CLASS 的目的是成为 DEFCLASS 的功能等价物。减去 DEFCLASS 所做的特殊实现特定的事情 - 例如支持开发环境的功能。

    您可以使用MAKE-INSTANCE,但例如它不会在其名称下注册该类。它也不会调用任何额外的ENSURE-CLASS-USING-CLASS 方法。

    由于元类的默认值是 standard-class,CCL 还应该为 直接超类 计算默认值,但遗憾的是它没有。

    我希望 closer-mop 能解决这些不兼容问题,但我还没有检查。

    在 CCL 中:

    ? (ensure-class 'my-class
                    :direct-slots '((:name x
                                     :readers (get-x)
                                     :writers ((setf get-x))))
                    :direct-superclasses (list (find-class 'standard-object)))
    #<STANDARD-CLASS MY-CLASS>
    ? (find-class 'my-class)
    #<STANDARD-CLASS MY-CLASS>
    ? (let ((foo (make-instance 'my-class)))
        (setf (get-x foo) 10)
        (incf (get-x foo) 32)
        (get-x foo))
    42
    

    LispWorks 确实做到了。元类默认为standard-class,直接超类为standard-object

    CL-USER 25 > (clos:ensure-class 'foobar
                     :direct-slots '((:name x
                                      :readers (get-x)
                                      :writers ((setf get-x)))))
    #<STANDARD-CLASS FOOBAR 4020001713>
    
    CL-USER 26 > (class-direct-superclasses *)
    (#<STANDARD-CLASS STANDARD-OBJECT 40E018E313>)
    

    【讨论】:

    • 感谢您的完整回答!
    猜你喜欢
    • 2013-08-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-11-01
    • 2016-02-04
    • 1970-01-01
    相关资源
    最近更新 更多