user-interfaceframeworkslispcommon-lispclozure-cl

Common Lisp ltk 'button' class not found


I'm learning Common Lisp (Clozure CL) on the Mac and installed quicklisp, with the help of a generous contributor on here. The 'ltk' library works when running (ltk::ltk-eyes) or (ltk:ltktest).

Running (ql:quickload "ltk") seems to work as it return the following:

Load 1 ASDF system:
ltk
; Loading "ltk"

I have a problem running the following code taken from the 'ltk' documentation. Here's the script:

(ql:quickload "ltk") ;my addition to the script

(defun hello-1()
  (with-ltk ()
   (let ((b (make-instance 'button 
                           :master nil
                           :text "Press Me"
                           :command (lambda ()
                                      (format t "Hello World!~&")))))
     (pack b))))

Howver, when I run (hello-1) I get this:

Error: Class named BUTTON not found. While executing: FIND-CLASS, in process Listener(4). Type cmd-/ to continue, cmd-. to abort, cmd-\ for a list of available restarts. If continued: Try finding the class again Type :? for other options.

My guess is that the 'ltk' library is not properly accessed in the function definition? I tried to fix the problem by using ltk:with-ltk as it seems to be a ltk function.

(defun hello-1()
  (ltk:with-ltk ()
   (let ((b (make-instance 'button 
                           :master nil
                           :text "Press Me"
                           :command (lambda ()
                                      (format t "Hello World!~&")))))
     (pack b))))

But that produced the following error. It seems that I'm getting closer at fixing it since the 2D canvas also appeared with the GUI alerting me of the error.

enter image description here

Thanks for your help.


Solution

  • Common Lisp manipulates symbols, which belong to packages. The Lisp reader is responsible for resolving an unqualified reference to a symbol to the actual, qualified symbol. That depends on the current package being bound to *PACKAGE* when reading code. As suggested in comments, you should read §21. Programming in the Large: Packages and Symbols from P. Seibel's Practical Common Lisp.

    You can define your own package as follows:

    (defpackage :test-ltk
      (:use :cl :ltk))
    

    The :use clause is the declarative equivalent of USE-PACKAGE. The above makes the test-ltk package inherit all external symbols from the Common Lisp and LTK packages. Generally, you cannot using too many packages together because you are more likely to have conflicts: two symbols belonging to different packages but having the same name cannot be accessed in an unqualified way. This is a bit like in C++, where you are discouraged from doing using namespace std.

    In order to selectively import some symbols and not others, you use :import-from instead. For example, you could define the preceding package as follows:

    (defpackage :test-ltk
      (:use :cl)
      (:import-from :ltk #:with-ltk #:button #:pack))
    

    Here, you only list the 3 symbols you are actually accessing. The #:symbol notation represents uninterned symbols, i.e. symbols that belongs to no package and are used only for their names. You could have used strings (in uppercase) instead.

    Then, you change the current package with IN-PACKAGE. The unqualified access to symbols are resolved according to the current package's definitions:

    (in-package :test-ltk)
    
    (defun hello-1 ()
      (with-ltk ()
        (pack
         (make-instance 'button 
                        :master nil
                        :text "Press Me"
                        :command (lambda () (format t "Hello World!~&"))))))