Skip to content

On Printing

Ashok Khanna edited this page Aug 16, 2021 · 1 revision

Some sample code

;; Define Chair Class

(defclass chair ()
  ((color :accessor chair-color
	  :initarg :color)
   (material :accessor chair-material
	     :initarg :material)))

(defparameter *example* (make-instance 'chair
				       :color "Gray"
				       :material "Steel"))

(print *example*)

;; Output >> #<CHAIR {10037C8CD3}>

(defmethod print-object ((obj chair) stream)
  (declare (special *print-method*))
  (if (boundp '*print-method*)
      (print-unreadable-object (obj stream :type t)
	(format stream "Color: ~a~%" (chair-color obj))
	(format stream "Material: ~a" (chair-material obj)))
      (print "This is a cool chair")))

;; Output >> "This is a cool chair"

(defun print-new-chair (color material)
  (let ((*print-method* t))
    (declare (special *print-method*))
    (print (make-instance 'chair :color color
			  :material material))
    nil))


(print-new-chair "Red" "Leather")

;; Output >> #<CHAIR Color: Red
;;           Material: Leather>

;; _death: another issue with your print-object method is that it uses the readers, which may signal errors, e.g., when the slots are not bound.. it often makes sense to only print the slot values if they're bound, i.e. use slot-boundp and slot-value

How often do you like to use free variables in your code? lisp123 I am finding I am using them more and more. For example, for print-object, I can create different versions, based on a global setting (which is a free variable in the print-object method) hayley You mean, special variables? lisp123 I can see libraries doing similar things reasonably frequently, but it does seem a bit going away from a functinal style 15:06 voltron has left IRC (Remote host closed the connection) lisp123 hayley - I'm not sure if its exactly the same hayley There is something like special variables in Haskell. Implicit parameters? 15:07 lisp123 a free variable is one that is not bound in the form and relies on functions called up higher (if my wording is correct), usually referring to global / special variables but not necessarily hayley Right. lisp123 for example I could define -my-free-variable- within a LET lisp123 and then any lets within that let, could refer to that -my-free-variable- --> so in this case, its not a special variable lisp123 just a free one lisp123 That way, I am not worried about other parts of the program changing its value Qwnavery has joined (~Qwnavery@user/qwnavery) lisp123 Let me do an example voltron has joined (~[email protected]) derelict has left IRC (Ping timeout: 272 seconds) lisp123 https://pastebin.com/83y6K3wM _death gin: even better is not to quit once the function returns, i.e. not using --script.. instead you can use, say, --load gin death: yes, tried sbcl --load too and it did not help since systemctl redirects stdin to /dev/null. So even with --load, sbcl quits as soon as it hits the last line of my top-level code. lisp123 Color is a free variable within the inner let in this function - this is a trivial example, but I am frequently starting to use this paradigm for control flow // and other computations. Not sure if I am going down a dark path.. death gin: there's an old tool called detachtty (I use it on my server) lisp-newbie has joined (~[email protected]) derelict has joined (~derelict@user/derelict) salvatore has joined ([email protected]) salvatore has left IRC (Remote host closed the connection) lisp123 Is there an equivalent for boundp for lexical bindings? lisp123 I guess I could use a combination of symbol-value & ignore-errors lisp123 Wonder if there was another way kuler has joined (~kulernil@gateway/tor-sasl/kuler) akater[m] lisp123: “If it were possible, the compiler would be very limited in the kinds of optimizations it could do.” — beach . The question seems to be popular. lisp123 akater[m]: Is this in relation to boundp & lexical bindings? lisp123 symbol-value also seems to only work for global variables, I am investigating it further hayley The set of lexical bindings could be determined at compile time, but I don't see why you want it. lisp123 I am trying to create print-object, which will first read print-method and then determine which print configuration to use Cymew has joined (~[email protected]) hayley clhs symbol-value specbot http://www.lispworks.com/reference/HyperSpec/Body/f_symb_5.htm lisp123 However, I would like to protect against unbound values hayley "symbol-value cannot access the value of a lexical variable." akater[m] lisp123: No need to. You can not intrespect lexical scope. hayley Why would you create unbound variables? lisp123 print-method will be a free variable within print-object lisp123 which I will then set within various programs, but on occasion I may forget, I want it to take the default value hayley That is not a lexical variable, based on the naming convention. lisp123 For that I want to know if its unbound. The easy solution is just to create a global variable for it to cover that case lisp-newbie has left IRC (Quit: This computer has gone to sleep) mfiano There are no global variables hayley Just use something like (defvar print-method :the-default-one) and you will have a default value. lisp-newbie has joined (~[email protected]) lisp123 hayley: Yes :) I want to see if there is a way to avoid that hayley A "global variable" is just a special variable with a sensible default value. hayley Any way to avoid it would be categorically worse. lisp123 akater[m]: Thanks for the confirmation lisp123 hayley: Thanks. Now I am aware its not feasible (or desirable in most cases) hayley As you have a special variable, you could handle it being unbound, but I am not going to tell you how, because it would be a bad idea. lisp123 It's not guaranteed to be a special variable (despite the use of *) lisp123 its just a symbol within print-object hayley Well, it won't be any use as a "free variable" if it is not a special variable. mfiano Lots of bad ideas around here lisp123 mfiano: lol beach If it's a lexical variable it is always bound. hhdave has joined (~[email protected]) lisp123 https://pastebin.com/83y6K3wM lisp123 Imagine if the second inner let was its own function hhdave has left IRC (Ping timeout: 268 seconds) hhdave is now known as hhdave beach lisp123: Please indent your code correctly. mfiano Mixing tabs and spaces is also a bad idea lisp123 Sorry that was the copy/paste, one second mfiano It looks indented correctly, but your editor is misconfigured. hayley tries to count the characters for CL-USER> but finds a tab. mfiano So it won't to everyone else, including web paste services. mfiano also tell lisp123 about FORMAT beach lisp123: If the inner LET were a function, how would it then bind a variable? lisp123 beach: you are right, I just got that error while trying to re-create the formatted code mfiano points to COmmon Lisp Recipes again mfiano err lisp123 https://pastebin.com/Scnvk93g mfiano Practical Common Lisp beach lisp123: In BAR, the variable COLOR is unbound, unless of course it has been declared SPECIAL. lisp123 beach: yes beach So what's the problem? mfiano It's still mis-indented due to your use of tab characters, which leads me to believe your swank client is not properly connected. lisp123 https://pastebin.com/ijmy3Pke beach So what's the problem? lisp123 So I have added in a special declaration to make it work _death you need another special declaration at the point of reference beach lisp123: What _death said. You now have a lexical COLOR in BAR and a special one in FOO. mfiano This is why defvar/defparameter special declaration with conventional earmuffs is a good idea. lisp123 Do I need (locally (declare (special color)) color) within bar? beach And your lack of earmuffs means you are violating the naming convention. lisp123 beach: So looks like you guys solved my problem. lisp123 Despite all the confusion I created lisp123 My original question earlier was to get boundp to refer to lexical bindings lisp123 But as the variables need to be special anyway, that question has disappeared beach You can't and you don't have to, because lexical variables are always bound. beach There is no way to create an unbound lexical variable. lisp123 beach: Thanks yes, I realise that now (but not at the start of this conversation) lisp123 _death: can you expand on "you need another special declaration at the point of reference"? _death lisp123: such use of specials is not usual.. often there are better ways to solve the actual problems lisp123 _death: I am trying to customise print-object mfiano Yes. It seems like you are trying to make things hard on yourself intentionally. igemnace has joined (~ian@user/igemnace) mfiano Learn about special variables and FORMAT in PCL then? lisp123 If print-method is unbound, then do default printing, otherwise follow whichever print method is selected _death lisp123: expand in what way? seems you got it with the locally form, or you can declare it wherever else declarations are allowed lisp123 _death: Okay, so my last example was fine? lisp123 mfiano: This is for setting the defaults for printing classes mfiano I know lisp123 via the defmethod print-object _death lisp123: if you're talking about your paste, you had a declaration at the point of binding (in FOO) but not at the point of refernece (in BAR).. so you'd also need (declare (special color)) in BAR lisp123 Since I can't pass in a variable for print-method, it has to receive the value from somewhere lisp123 _death: Thanks, I will do that lisp123 (is there a particular reason why?) _death lisp123: but why do you need a "print-method" variable, and if you do need it, why not use defvar to say that it's special _death lisp123: the reason is that CL is lexical by default, and it's considered a good thing for a compiler to warn you when it sees a free variable lisp-newbie has left IRC (Quit: This computer has gone to sleep) lisp123 (just writing up an example) silasfox has joined (~[email protected]) lisp-newbie has joined ([email protected]) tyson2 has left IRC (Quit: ERC (IRC client for Emacs 27.2)) lisp123 https://pastebin.com/c31NLZh6 lisp123 mfiano: sorry, I think the tabs is due to paredit perhaps lisp123 _death: so the difference here vs. declaring print-method via a defvar, is that here print-method "loses" its value automatically once all the forms are evaluated, whereas with defvar, one would have to remember to reset it to whatever the default value is _death it's possible that you're trying to use print-object for something that it's not intended to be used for lisp123 The main purpose of print-method is to later put in various cases (e.g. info, extra-info, debug, etc.) so that it prints with the level of detail required hayley This doesn't sound like a good use of PRINT-OBJECT. _death print-object is for printing objects concisely, for development/debugging purposes or for naive serialization when print-readably is true lisp123 _death: Sometimes I want a detailed print object, sometimes I want a very basic one, so I wanted to add that customizablity hayley That said, there is print-pretty\ which is a special variable which customizes printing in a way. hayley fails to appease Markdown yet again. beach lisp123: What does it mean that one has to remember to reset it? _death for more intensive printing, there's describe-object.. you can also have your own functions, and you can also make use the pretty printer mfiano lisp123: It seems you want to use a special variable for a flag then, not the object to be printed. mfiano All of the logic related to printing can be contained within print-object or auxilliary functions hayley And you can use LET to temporarily bind a special variable, so there is no need for "resetting" or whatever. beach Yes, that's why I am asking. lisp123 beach: say I have (defparameter print-method nil), then within a function I set it to 'debug. If I don't reset it back to nil, then future calls to print-object will refer to 'debug hayley Don't set it. Just re-bind it. beach lisp123: Don't set it then, bind it. mfiano You should read about how dynamic binding works lisp123 Ah yes, that makes sense lisp123 So you guys don't like this approach to custom printing? lisp123 I though it was cool hayley I don't think it is a great use of PRINT-OBJECT, no. mfiano Alkso parewdit is not responsible for your misconfigured Emacs that doesnt convert tabs to spaces. You need to setq-default the right Emacs variable, that slipped my mind, but I remember beach knows mfiano Also* lisp-newbie hi, is there an inspect or describe equivalent that instead of printing will just return a string? or with the stream, how to turn it into a string in a variable? mfiano These are 2 unrelated questions lisp123 mfiano: Thanks, let me look at that. Was easier just to blame paredit ;) mfiano FORMAT, and INTERN hayley Well, inspect won't do you much good. hayley clhs with-output-to-string specbot http://www.lispworks.com/reference/HyperSpec/Body/m_w_out_.htm lisp-newbie ok, just want to solve my issue _death another issue with your print-object method is that it uses the readers, which may signal errors, e.g., when the slots are not bound.. it often makes sense to only print the slot values if they're bound, i.e. use slot-boundp and slot-value lisp-newbie hayley thanks hayley I would have to check the lambda list of DESCRIBE, but if it takes a stream parameter to write to, you are basically set. lisp123 _death: thanks, that's a good pickup lisp-newbie hayley it does lisp-newbie thanks! lisp-newbie hayley, great! it works! thanks! :D

Clone this wiki locally