Tag Archives: obscure commands

The less-familiar parts of Lisp for beginners — stream-external-format

Our next obscure function is stream-external-format.  This is entirely an implementation-dependent function.  Some implementations may have different on-disc formats for data, and using a different external format may result in different bytes being delivered to the disc.  All return values from this function have implementation-dependent meanings, so the programmer must be aware of this fact when writing code intended to be portable.

To provide a specific example, SBCL allows the user to open a character stream for writing with any of several external formats.  For instance, one can write in UTF-8, UTF-16BE, UTF-32LE, ISO-8859-5, EBCDIC-US, to name just a few.  Each of these has a different external format keyword, which stream-external-format will return.

The less-familiar parts of Lisp for beginners — stream-element-type

Moving on to the stream-element-type function.  We should first describe streams and their element types.  A stream in Lisp looks a little like an iostream in C++.  It is an opaque object that defines an interaction between the program and what a UNIX system would call a character device (as opposed to a block device).  A stream may take special action to distinguish between text and binary data, and has equivalents to tellp and seekp.

A Lisp stream has an associated element type which must be a subtype of character or of integer.  If it’s a subtype of character, it can be used with functions like format, read, and others.  If it’s a subtype of integer, it can be used with functions like read-byte, write-byte, read-sequence, and write-sequence.

The stream-element-type function allows the programmer to detect at runtime whether a stream is a character stream or an integer stream.  Appropriate behaviour can then take place based on the compatibility with that particular stream.

One thing I will note.  While I was testing behaviour in SBCL 1.1.14, I was a bit surprised to see that the write-byte and read-byte functions, while defined in the CLHS as writing individual bytes, actually write and read one entry from the stream.  If the stream element type is (integer 0 65535), the entries are 16 bits long, and read-byte reads a 16-bit word from the stream, not a single byte.  I was unable to find anything in the CLHS among the clarifying notes that would tell me whether this is required, allowed, or a bug.  If anybody knows, please pass on your knowledge in the comments.

The less-familiar parts of Lisp for beginners — special-operator-p

In Common Lisp there are several operators that are referred to as “special”.  A special operator is one which has different behaviour in terms of bindings or flow control.  The list can be found, for instance, here.  The programmer cannot create their own special operators, there is no way to create a new entity for which special-operator-p returns non-nil.

Some examples will, perhaps, clarify what this means.  The Common Lisp if special operator takes two or three arguments.  The first is the condition, the second is evaluated only if the condition evaluates to non-nil, and the optional third argument is evaluated only if the condition evaluates to nil.  Hidden within the if form, there is a flow control that decides whether or not to evaluate certain arguments.

In the context of bindings, catch sets up a dynamic binding that becomes important if code below it invokes throw.  The labels special operator sets up a lexical binding within its scope.

The special-operator-p function returns non-nil if the symbol passed as its argument corresponds to a special operator.  Now, when might the programmer need to use this?  Most obviously in a code walker, something that reads and analyses Lisp code.  I have never seen it used other than in informational contexts, to label a particular piece of code as containing a special operator, or by the implementation to forbid the redefinition of such operators.  I haven’t seen a context in which complex actions are initiated by special-operator-p returning non-nil, only messages, errors, or skipping over a block while analysing code.

The less-familiar parts of Lisp for beginners — special

We’ve hinted a few times at special variables, but I’ll put it here in one spot to make it easier to find.  The special declaration is used, for instance in declaim or declare, to indicate that a variable should have dynamic binding.

The most important thing to realize about a dynamic variable is that it behaves as if implemented by a push-down stack.  Declaring a new local variable with the same name, for instance with let, creates a new dynamic extent that is visible in any called functions.  Modifications to the value of the variable are visible until the dynamic extent is exited, at which point the next enclosing extent becomes the current one.

It is a common convention that special variables have variable names that begin and end in an asterisk, but this is not typically enforced by the implementation.  Variables created with defvar or defparameter are always dynamic.

Here’s some simple code to demonstrate the behaviour:
special.lisp

(defparameter *myvar* 10)

(defun printvar ()
  (format t "*myvar*= ~D~%" *myvar*))

(defun incvar ()
  (incf *myvar*))

(defun demonstrate ()
  (format t "Outermost dynamic extent:~%")
  (printvar)
  (format t "Incrementing the value~%")
  (incvar)
  (printvar)
  (format t "Creating a new dynamic extent with value 15:~%")
  (let ((*myvar* 15))
    (printvar)
    (format t "Incrementing the value~%")
    (incvar)
    (printvar))
  (format t "Exiting this new dynamic extent~%")
  (printvar))
          

with output:
*slime-repl sbcl*
CL-USER> (demonstrate)
Outermost dynamic extent:
*myvar*= 10
Incrementing the value
*myvar*= 11
Creating a new dynamic extent with value 15:
*myvar*= 15
Incrementing the value
*myvar*= 16
Exiting this new dynamic extent
*myvar*= 11
NIL

The less-familiar parts of Lisp for beginners — slot-value

At this point in our walk through less commonly seen features of Lisp we come to the slot-value function.  This is a good place to reiterate some of the differences between the way C++ and Lisp objects are handled.

In C++, a class will typically have private and public methods.  The public methods form the user-facing API, while the private methods are used for internal implementation, and cannot be used by non-friend classes or functions.  The same goes for private and public members, other classes or functions don’t have access to private member objects.  Friends of a class are declared in the class definition, as are the public/private modifiers, so it is not possible for another function or class to manipulate the private members or methods of a class without changing the class definition itself.

In Lisp, the private/public distinction is still present, but it is not as strictly enforced.  Where C++ has public and private methods on a class, Lisp has external and internal symbols on a package.  In C++ one typically writes methods referred to as “getters” and “setters” for a member in a class, while a class in Lisp can have :reader, :writer, or :accessor methods for individual members.

So, I mentioned that Lisp does not enforce the private/public distinction as strictly as C++.  In Lisp, it is possible to use the internal symbols of a package, one has merely to use a double colon between the package name and the symbol name, rather than the usual single colon used for external symbols.  This makes it immediately obvious that the code is using symbols that are not part of the API, but means that the programmer does not have to modify the other package to cause it to export that symbol.  The equivalent for accessors is slot-value.  This function allows the programmer to read or modify (with setf), any named slot in an instance of a class, regardless of whether or not there are accessors associated with it.

When a programmer finds him or herself using internal symbols from packages, or most uses of slot-value, it’s a sign that some examination of the context may be required.  The maintainer of the package probably feels free to modify the internal symbols of his or her package without worrying about backward compatibility, as it’s not part of the API, so other code that makes use of those internal symbols may break if the package is upgraded.  Further, unlike C++, where the friends of the class are listed in the class definition, Lisp provides no similar method for the programmer changing the package to know where some code somewhere might be making use of internal symbols.

Similarly, manipulation of slots of an instance through slot-value often indicates that the programmer did not think such manipulation wise, perhaps because changes to it must accompany other changes for consistency, so a naive poking about in the innards may have unexpected results.

There are, however, some common use cases for slot-value that are expected and not suggestive of problems.  The first is exactly in the case mentioned at the end of the previous paragraph.  When a method changes two or more slots together, you do not want :writer methods that allow the manipulation of those slots individually.  You might create :reader methods, and then use slot-value with setf to change the slots together in a single method.  A second case is in setting what a C++ programmer would call a const member object.  Once more, the programmer doesn’t want to create a :writer or :accessor method for the slot, to discourage others from changing it, but that slot does have to be set during instance creation.  There, the use of slot-value is natural and preferred.