Lisp HUG Maillist Archive

Adjust + and - reader macros

HI lispworks HUG,

Apologies if this is more of a general Lisp question, but I’m having a hard time Googling for it, and at the moment the project I’ve inherited only runs in lispworks.

The code is full of read time includes such as:

#+lispworks (do-stuff)
#+win32 (windows stuff)
#+macosx (mac stuff)
#-(or win32 macosx) (linux amiga os400 stuff stuff stuff)

For the sake of testing and debugging some stuff I’m wondering how I adjust the items that will show up or not show up from the list of items that are tested for these macros.

For instance if I wanted to add “opengl” from the list of positives, or maybe even remove “lispworks”.  Is there some type of global variable that holds all the environment items for these?

Thanks much,
Steve

_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Adjust + and - reader macros



On 1 Sep 2019, at 01:21, Steven Githens <steve@githens.org> wrote:

HI lispworks HUG,

Apologies if this is more of a general Lisp question, but I’m having a hard time Googling for it, and at the moment the project I’ve inherited only runs in lispworks.

It is indeed a general Common Lisp questions.  #+ and #- are dispatching reader macros explained in Chapter 2 of the Hyperspec.
http://www.lispworks.com/documentation/HyperSpec/Body/02_.htm
http://www.lispworks.com/documentation/HyperSpec/Body/02_dhq.htm
http://www.lispworks.com/documentation/HyperSpec/Body/02_dhr.htm

The expression following the #+ or #- dispatching reader macros are called feature expressions.
http://www.lispworks.com/documentation/HyperSpec/Body/24_aba.htm

Feature expressions are evaluated by #+ or #- using a special rule, and the contents of the list bound to the *features* variable.
http://www.lispworks.com/documentation/HyperSpec/Body/v_featur.htm#STfeaturesST


The code is full of read time includes such as:

#+lispworks (do-stuff)
#+win32 (windows stuff)
#+macosx (mac stuff)
#-(or win32 macosx) (linux amiga os400 stuff stuff stuff)

For the sake of testing and debugging some stuff I’m wondering how I adjust the items that will show up or not show up from the list of items that are tested for these macros.

You can mutate the *features* variable, binding it to a new list of symbols.

However, I wouldn’t advise to remove symbols provided by the implementation. 
I would expect a lot of code to break if you removed :lispworks from the *features* when running on lispworks.
That said, *features* is normally only used at read-time by #+ and #-, so the code that has already been read (either by load or compile-file), should not break if you mutate *features*.
However, it is possible that some function explicitely tests at run-time *features*…


For instance if I wanted to add “opengl” from the list of positives, or maybe even remove “lispworks”.  Is there some type of global variable that holds all the environment items for these?

You wouldn’t add symbols to *features* gratuituously.  The code that will test those features will expect that corresponding systems have been loaded and packages exist.

Notably, keywords being global resources, putting them on *features* should follow some global convention. Unfortunately, there’s no registry or such global convention existing.
There’s a list of the de-facto keywords used at https://cliki.net/features
But this list only collects the symbols put there by implementations. (and it’s incomplete and probably outdated).
A more complete list would include the feature symbols used by the various libraries, with their specific meaning in each case.

For example, ASDF version 3 puts :asdf3 there…


When I add features for my own usage, I use symbols interned in my own packages, so there’s no risk of collision.

(eval-when (:compile-toplevel :load-toplevel :execute)
   (pushnew 'com.informatimago.pjb:testing *features*))

#+com.informatimago.pjb:testing (print ‘(hi! starting tests))


Alternatively, if I have to use a keyword, I would name it with a unique prefix:

(eval-when (:compile-toplevel :load-toplevel :execute)
   (pushnew :com.informatimago.pjb.testing *features*))

#+com.informatimago.pjb.testing (print ‘(hi! starting tests))


Another example, would be patchwork, in which I use features to select compilation-time options, including debugging options.  
This should be prominently documented in the build instructions, which is not exactly the case unfornately,

(setf *features* (set-difference *features*
                                 '(:debug-application
                                   :debug-event
                                   :debug-focused-view
                                   :debug-graphics
                                   :debug-objc
                                   :debug-streams
                                   :debug-text
                                   :debug-trace
                                   :debug-views
                                   :debug-views-colors
                                   :debug-views-instance
                                   :debug-wrapper
                                   patchwork.builder::no-cocoa
                                   patchwork.builder::use-apple-events
                                   patchwork.builder::cocoa-midi-player
                                   patchwork.builder::use-midishare
                                   patchwork.builder::use-cl-midi)))

;; (pushnew :debug-application    *features*)
;; (pushnew :debug-event          *features*)
;; (pushnew :debug-focused-view   *features*)
;; (pushnew :debug-graphics       *features*)
;; (pushnew :debug-objc           *features*)
;; (pushnew :debug-streams        *features*)
;; (pushnew :debug-text           *features*)
;; (pushnew :debug-trace          *features*)
;; (pushnew :debug-views          *features*)
;; (pushnew :debug-views-colors   *features*)
;; (pushnew :debug-views-instance *features*)
;; (pushnew :debug-wrapper        *features*)

;; (pushnew 'patchwork.builder::no-cocoa          *features*)
;; (pushnew 'patchwork.builder::use-apple-events  *features*)
;; (pushnew 'patchwork.builder::cocoa-midi-player *features*)
;; (pushnew 'patchwork.builder::use-midishare     *features*)
   (pushnew 'patchwork.builder::use-cl-midi       *features*)


-- 
__Pascal J. Bourguignon__




Re: Adjust + and - reader macros

Keep in mind that, if you want some form of conditional compilation, you don’t need to use #+ or #-. You can also use reader macros with the #. syntax. For example:

#.(when *debug* ‘(print 42))

This allows you to use your own global variables.

However, also keep in mind that in many cases, just evaluating things at runtime is perfectly fine:

(when *debug* (print 42))

I can’t imagine a lot of reasons why you would want to turn something like this into a conditionally compiled form, unless you have highly performance-critical code, or you want to be sure the decision is fixed at compile time and can’t be changed at runtime anymore for some other reason.

Pascal

--
Pascal Costanza



_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Re: Adjust + and - reader macros

Hi all,

Thanks much for all these helpful responses.  It’s good to see the solution, but also hear the background material around the macro.  My plan isn’t to permanently remove the #+lispworks or related items, but I’m really just trying to get a grapple on this project I’ve taken over, which has been around for quite a while, and with all of these conditionals reminds me quite a lot of an operating system C library with all the architecture conditions!  They go all the back to #+lispm, #+symbolics #+dec3100 and many many others!

Cheers,
Steve

> On Sep 1, 2019, at 11:24 AM, Pascal Costanza <pc@p-cos.net> wrote:
> 
> Keep in mind that, if you want some form of conditional compilation, you don’t need to use #+ or #-. You can also use reader macros with the #. syntax. For example:
> 
> #.(when *debug* ‘(print 42))
> 
> This allows you to use your own global variables.
> 
> However, also keep in mind that in many cases, just evaluating things at runtime is perfectly fine:
> 
> (when *debug* (print 42))
> 
> I can’t imagine a lot of reasons why you would want to turn something like this into a conditionally compiled form, unless you have highly performance-critical code, or you want to be sure the decision is fixed at compile time and can’t be changed at runtime anymore for some other reason.
> 
> Pascal
> 
> --
> Pascal Costanza
> 
> 


_______________________________________________
Lisp Hug - the mailing list for LispWorks users
lisp-hug@lispworks.com
http://www.lispworks.com/support/lisp-hug.html

Updated at: 2020-12-10 08:29 UTC