This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

make-instance in defconstant

4 posts · 1892 views

Hello,

I need to set a constant to be one instance of a class, but when I use:
(defconstant +html-view+ (make-instance 'html-view))
the compile fails with "no such class 'html-view" (compiled in slime via load-system). I can fix this by slapping an eval-when around the defclass call, but this strikes me as pretty bizarre. Wouldn't defclass already be defined at load/compile time anyway? It also causes problems in SBCL as I then start getting the "constant redefined" error (presumably asdf is reloading the files several times for some reason, perhaps something to do with the dependancies).

Code:
(defclass html-view ()
   ())
(defconstant +html-view+ (make-instance 'html-view))

(defgeneric render (component view))

(defmethod render ((component standard-object) (view html-view))
  ;...
   )

(defun test-it ()
       (render (make-instance 'web-page) +html-view+))
I suppose since what I'm doing here is using html (and xml) singletons I could just specialize on the meta-class instead but I don't like this for later when I start adding methods and slots of these views.

Thanks in advance,
Jason

Re: make-instance in defconstant

dangerousdan wrote:Wouldn't defclass already be defined at load/compile time anyway?
Not necessarily. The class name is associated with a class, but the class itself is not yet created enough to be instantiated at compile time. My suggestion would be to put class definitions in a different file than DEFCONSTANT.
dangerousdan wrote:It also causes problems in SBCL as I then start getting the "constant redefined" error (presumably asdf is reloading the files several times for some reason, perhaps something to do with the dependancies).
Use DEFINE-CONSTANT from Alexandria with a proper test to resolve this.

But, in general, using DEFCONSTANT with anything else than characters, symbols or numbers is pointless. Just use DEFPARAMETER, there will be no difference, since object instances can't be inlined anyway, and they are not really constant anyway (DEFCONSTANT doesn't give any guarantees that the internal state of the object would not change).

Also, why is +html-view+ in the example given even a class? You can specialize methods on symbols with EQL specializers, like this:
(defgeneric render (component view))

(defmethod render ((component standard-object) (view (eql 'html-view)))
  ;;...
  )

(defun test-it ()
  (render (make-instance 'web-page) 'html-view))

Re: make-instance in defconstant

Thanks for the quick reply.
Ramarren wrote:My suggestion would be to put class definitions in a different file than DEFCONSTANT.
I thought about doing this, but I only considered having a single constants file, which would have a circular dependency problem (i.e. normally the constants file would be the file all others depend on, but in this case it depends on other files). I suppose I could make a special "view-constants" file. I think I'll try that. Good suggestion.
Ramarren wrote:Use DEFINE-CONSTANT from Alexandria with a proper test to resolve this.
I looked into using it, but I saw several strong arguments against doing so (e.g. it makes defconstant equivalent to defparameter, it doesn't work in certain cases anyway, etc.).
Ramarren wrote: But, in general, using DEFCONSTANT with anything else than characters, symbols or numbers is pointless. Just use DEFPARAMETER, there will be no difference, since object instances can't be inlined anyway, and they are not really constant anyway (DEFCONSTANT doesn't give any guarantees that the internal state of the object would not change).
Fair argument. I guess I wanted to use constant so they can be + variables instead of * variables (i.e. seeing +html-view+ defined with defparameter instead of defconstant might seem odd, no?) since the code would never change them.
Ramarren wrote: Also, why is +html-view+ in the example given even a class? You can specialize methods on symbols with EQL specializers, like this:
(defgeneric render (component view))

(defmethod render ((component standard-object) (view (eql 'html-view)))
  ;;...
  )

(defun test-it ()
  (render (make-instance 'web-page) 'html-view))
html-view is a class and can have it's own slots and specializers. At this early stage nothing has been added to it, but there will be.

Re: make-instance in defconstant

I thought about a different way to do it, which although not all that sane is, I think, over-engineered in a funny way:
(defparameter *view-cache* (make-hash-table))

(defconstant +html-view+ 'html-view)

(defgeneric get-or-create-view (view-designator)
  (:method ((view-designator symbol))
    (or (gethash view-designator *view-cache*)
        (setf (gethash view-designator *view-cache*)
              (make-instance view-designator)))))

(defmethod render ((component t) (view symbol))
  (render component
          (get-or-create-view view)))
And the GET-OR-CREATE-VIEW function can even be specialized on either concrete symbols, or non-symbols, to give different behaviour.