Search code examples
common-lispexecutablesbcl

Why do executables have different behavior that the repl behavior?


My Setup

I develop common lisp with emacs + slime. My machine is a mac pro M1. And, I use the kitty terminal emulator.

The Situation

When I run my app (see code at the end) in the repl, it works fine.

When I create and run the executable, it's as if the order of the program is different.

For example, I have 5 questions which asks for user input...


(defpackage custom-sender
  ;; import the exactly the symbols I need from a package
  (:import-from :cl-json :encode-json-to-string)
  (:use :cl)
  (:export :main))

(in-package custom-sender)

(defun main()
  (asking-questions))


(defun asking-questions ()
  (let ((firstname (prompt-read "What is the firstname of the contact?"))
        (email (prompt-read "What is their email?"))
        (job (prompt-read "What is the job?"))
        (first-line (prompt-read "what is the first line of their address?"))
        (sending-account (prompt-read "Which email account do you want to send from? (e2, e3 etc)")))

    (status-update "some text ~a" email);; <-- this function is executed BEFORE the "sending-account" question is asked

... ) ;;<-- end of let block

  )

(defun status-update (message value)
  (format *query-io* (concatenate 'string message "~C~C") value  #\linefeed #\linefeed)
  (force-output *query-io*))

(defun prompt-read (question)
  (format *query-io* "~a:  " question)
  (read-line *query-io*)
  (force-output *query-io*))


The Problem

When running the executable, there are two issues:

  1. The first function (status-update...) is executed before the final prompt read. In the terminal, the question comes up but immediately exits. So I cannot enter anything.
  2. Also... (status-update...) gets the value of email which is NIL. Even though I entered a value inside the terminal.

This entire process runs perfectly in the repl.

Note - I am building the executable with the ASD MAKE process.


Solution

  • (defun prompt-read (question)
      (format *query-io* "~a:  " question)
      (read-line *query-io*)
      (force-output *query-io*))
    

    change it to something like this:

    (defun prompt-read (question)
      (format *query-io* "~a:  " question)
      (force-output *query-io*)
      (read-line *query-io*)
      (force-output *query-io*))
    

    Otherwise the prompt may not be visible when the function is waiting for input..., due to a buffering output stream.

    Streams may or may not buffer output. For portable programs you'd need to add operations to clear or force output.