common-lisptk-toolkitsbcl

nodgui and SBCL(?): How to avoid the type error "The value NIL is not of type STREAM when binding STREAM" right from the beginning?


Always when I start to try packages for Common Lisp GUI programming I encounter problems at a very early stage. I'm using SBCL 2.1.1 and 2.3.8 with Debian "Bullseye" and currently, I want to understand its usage with the LTk Examples.

The hello world example in the (with-nodgui () ) is no problem. Yet if it comes to the "first (real) example" starting with

(wm-title *tk* "Feet to Metres")

I end up in the debugger with the condition mentioned in the subject of this post (in Slime such as in the shell).

You can easily recognise that I am the contrary of an expert since such error messages always overwhelm my abilities to find a starting point for searching the cause.

When I tried to compile the following LET-form of the example without the WM-TITLE

(let ((content (make-instance 'frame)))
  (...))

the error message kept the same.

Is it posssible that you can give me a hint how to avoid it? That would be a kind of an early christmas present for me.

(I was close to "crosscheck" whether it is a problem with the rigidity of SBCL by trying out CLisp. Yet I had to realise, that therefore I have to get involved into some initial configuration work for setting up CLisp since it didn't want to quickload :nodgui out-of-the-box, let alone find ASDF ... And I really(!) do not want to open a new box of annoying [a posteriori tiny little] problem areas. I just want to follow the examples to design the GUI I want to have WITHOUT ending up in the debugger without knowing why - making me cry ... and I want to do it with SBCL)

Best regards

P.S.: It might be helpful, to mind the Backtrace - yet at this level unfortunately not for me.

Backtrace:
  0: ((FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN FLUSH-WISH))
  1: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
  2: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN FLUSH-WISH) {53B59E7B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" taken owner=worker> T NIL)
  3: ((FLET "WITHOUT-INTERRUPTS-BODY-11" :IN SB-THREAD::CALL-WITH-RECURSIVE-LOCK))
  4: (SB-THREAD::CALL-WITH-RECURSIVE-LOCK #<FUNCTION (FLET SB-THREAD::WITH-RECURSIVE-LOCK-THUNK :IN NODGUI::SEND-WISH) {7F325273612B}> #<SB-THREAD:MUTEX "Anonymous recursive lock" taken owner=worker> T NIL..
  5: (NODGUI::SEND-WISH "wm title . {Feet to Metres}")
      Locals:
        #:ITEM = "wm title . {Feet to Metres}"
  6: ((:METHOD WM-TITLE (WIDGET T)) #<WIDGET {10079B22E3}> "Feet to Metres") [fast-method]
      Locals:
        TITLE = "Feet to Metres"
        NODGUI::W = #<WIDGET {10079B22E3}>
  7: (SB-INT:SIMPLE-EVAL-IN-LEXENV (WM-TITLE *TK* "Feet to Metres") #<NULL-LEXENV>)
  8: (EVAL (WM-TITLE *TK* "Feet to Metres"))
  9: ((LAMBDA NIL :IN SWANK:INTERACTIVE-EVAL))
 10: (SWANK::CALL-WITH-RETRY-RESTART "Retry SLIME interactive evaluation request." #<FUNCTION (LAMBDA NIL :IN SWANK:INTERACTIVE-EVAL) {1008258DAB}>)
 11: (SWANK::CALL-WITH-BUFFER-SYNTAX NIL #<FUNCTION (LAMBDA NIL :IN SWANK:INTERACTIVE-EVAL) {1008258D8B}>)
      Locals:
        FUN = #<FUNCTION (LAMBDA () :IN SWANK:INTERACTIVE-EVAL) {1008258D8B}>
        PACKAGE = NIL
 12: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SWANK:INTERACTIVE-EVAL "(wm-title *tk* \"Feet to Metres\")") #<NULL-LEXENV>)
 13: (EVAL (SWANK:INTERACTIVE-EVAL "(wm-title *tk* \"Feet to Metres\")"))
 14: (SWANK:EVAL-FOR-EMACS (SWANK:INTERACTIVE-EVAL "(wm-title *tk* \"Feet to Metres\")") "COMMON-LISP-USER" 38)
      Locals:
        BUFFER-PACKAGE = "COMMON-LISP-USER"
        CONDITION = #<TYPE-ERROR expected-type: STREAM datum: NIL>
        FORM = (SWANK:INTERACTIVE-EVAL "(wm-title *tk* \"Feet to Metres\")")
        ID = 38
        OK = NIL
        RESULT = NIL
 15: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
      [No Locals]
 16: (SWANK/SBCL::CALL-WITH-BREAK-HOOK #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {539F452B}>)
 17: ((FLET SWANK/BACKEND:CALL-WITH-DEBUGGER-HOOK :IN "/home/.../sbcl.lisp") #<FUNCTION SWANK:SWANK-DEBUGGER-HOOK> #<FUNC..
 18: (SWANK::CALL-WITH-BINDINGS ((*STANDARD-INPUT* . #<SWANK/GRAY::SLIME-INPUT-STREAM {10018609B3}>)) #<FUNCTION (LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD) {539F47DB}>)
 19: ((LAMBDA NIL :IN SWANK::SPAWN-WORKER-THREAD))
 20: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 21: ((FLET "WITHOUT-INTERRUPTS-BODY-174" :IN SB-THREAD::RUN))
 22: ((FLET SB-UNIX::BODY :IN SB-THREAD::RUN))
 23: ((FLET "WITHOUT-INTERRUPTS-BODY-167" :IN SB-THREAD::RUN))
 24: (SB-THREAD::RUN)
 25: ("foreign function: call_into_lisp_")
 26: ("foreign function: funcall1")

Solution

  • Maybe is it how you load everything. Let's start from scratch:

    (defpackage :feet-to-meter
      (:use :cl :nodgui))
    
    (in-package :feet-to-meter)
    
    (defun feet-to-meter ()
      (with-nodgui ()
        (wm-title *tk* "Feet to Metres")         ; 1
        (let ((content (make-instance 'frame)))  ; 2
          (configure content :padding "3 3 12 12") ; 3
          (grid content 0 0 :sticky "nsew")
          (grid-columnconfigure *tk* 0 :weight 1)
          (grid-rowconfigure *tk* 0 :weight 1)
    
          (let* ((feet-entry (make-instance 'entry :master content :width 7)) ; 4
                 (metres-label (make-instance 'label :master content :text "")))
            (flet ((calculate ()            ; 5
                     (let ((feet (read-from-string (text feet-entry))))
                       (setf (text metres-label)
                             (if (numberp feet)
                                 (/ (round (* 0.3048 feet 10000.0)) 10000.0)
                                 "")))))
                                            ; top row has the entry widget and explanatory label to its right
              (grid feet-entry 1 2 :sticky "we" :padx 5 :pady 5) ; 6
              (grid (make-instance 'label :master content :text "feet")
                    1 3 :sticky "w" :padx 5 :pady 5)
                                            ; middle row has three labels
              (grid (make-instance 'label :master content :text "is equivalent to")
                    2 1 :sticky "e" :padx 5 :pady 5)
              (grid metres-label 2 2 :sticky "we" :padx 5 :pady 5)
              (grid (make-instance 'label :master content :text "metres")
                    2 3 :sticky "w" :padx 5 :pady 5)
                                            ; last row has the button on right
              (grid (make-instance 'button :master content ; 7
                                           :text "Calculate"
                                           :command #'calculate)
                    3 3 :sticky "w" :padx 5 :pady 5)
    
              (focus feet-entry)            ; 8
              (bind *tk* "<Return>" (lambda (evt) (calculate))))))
        ))
    

    feet to meter, with the new default yaru theme