Conditional parsing

#1

Common Lisp has a concept of conditional parsing. The feature allows us to specify certain forms in the source code to be skipped by the parser depending on simple conditions, which are usually feature queries. Conditional parsing is useful when writing code which compiles on different targeted architectures, or different lisp vendors, or which should compile differently in debug mode, or super-optimized mode.

I wonder whether the concept even makes sense to talk about in Scala? I suspect that perhaps it does, as sometimes you need to write code differently depending on whether you’re writing for 2.12 or 2.13 or 3.0, and also when targeting JVM or JS.

Do Scala programmers ever want to write code that compiles differently on Mac vs Unix, or for JVM vs JS, or debug vs optimized modes?

On the other hand, the idea might be extremely problematic since the scala code is compiled into a scala class which no longer remembers the parse time conditionals. It is probably problematic in Scala as well because as I understand the application programmer has no hook into the parser. Lisp has a general concept of parser-macro, called reader-macro.

Here is a simple example. If the code is being compiled using the sbcl Common Lisp compiler then the #+sbcl indicates to read the expression (sb-ext:process-kill process signal) however if the compiler is not sbcl, then the parser parses the expression and simply discards it as if it were a comment. Similar for the second expression which will be parsed and discarded if the compiler is not the Allegro Common Lisp compiler.

(defun process-kill (process signal)
  "Kill a process started by RUN-PROGRAM, if it was started with (run-program ... :wait t)"
  #+sbcl (sb-ext:process-kill process signal)
  #+allegro (progn (excl.osi:kill process signal)
                   (sys:reap-os-subprocess :pid process)))

One advantage of this over simple run-time conditions is that the function 'sys:reap-os-subprocesswon't even be defined sbcl andsb-ext:process-kill` won’t be defined in allegro.

The feature list is provided by the system, but is extensible at load time and at run-time. There are many other features which can be used with the #+ and dually #- syntax. For example, there is #+os-macosx for running on MAC, and I assume something similar for windows, solaris etc.

There is also an API available at parse time for systems/files/packages being loaded to add features to the feature list which can then be queried by #+. This means that certain code can be made completely invisible to the compiler depending on whether other code packages have been loaded or not.

1 Like
#2

This is currently being discussed at https://github.com/scala/scala-dev/issues/640.

1 Like
#3

Thanks I’ve added my comments to that issue.

#4

I’ve created a similar macro here: