Final classes and platform-specific vocabularies
Wednesday, February 24, 2010
Final classes
I added final classes, in the Java sense. Attempting to inherit from a final class raises an error. To declare a class as final, suffix the definition with “final”, in the same manner that words can be declared “inline” or “foldable”:
TUPLE: point x y z ; final
The motivation for final classes was not obvious. There are three main reasons I added this feature.
Unboxed tuple arrays used to have the caveat that if you store an instance of a subclass into a tuple array of a superclass, then the slots of the subclass would be “sliced off”:
TUPLE: point-2d x y ;
TUPLE-ARRAY: point-2d
TUPLE: point-3d < point-2d z ;
SYMBOL: my-array
1 my-array set
1 2 3 point-3d boa my-array get set-first
my-array get first .
=> T{ point-2d { x 1 } { y 2 } }
This warranted a paragraph in the documentation, and vigilance on the part of the programmer. Now, tuple arrays simply enforce that the element class is final, and if it is not, an error is raised. This removes a potential source of confusion; it is always nice when written warnings in the documentation can be replaced by language features.
Joe Groff’s
typed library
has a similar problem. This library has a feature where input and output
parameters which are read-only tuples are passed by value to improve
performance. This could cause the same “slicing problem” as above. Now,
typed
only passes final read-only tuples by value.
Finally, there was a previous mechanism for prohibiting subclassing, but it wasn’t exposed as part of the syntax. It was used by the implementation of struct classes to prevent subclassing of structs. The struct class implementation now simply declares struct classes as final.
Typed words can now be declared foldable and flushable
Factor has a pretty unique feature; the user can declare words foldable (which makes them eligible for constant folding at compile time if the inputs are all literal) or flushable (which makes them eligible for dead code elimination if the output results are not used). These declarations now work with typed words.
Platform-specific vocabularies
I added a facility to declare what operating systems a vocabulary runs
on. Loading a vocabulary on an unsupported platform raises an error,
with a restart if you know what you’re doing. The load-all
word skips
vocabularies which are not supported by the current platform.
If a platforms.txt
file exists in the vocabulary’s directory, this
file is interpreted as a newline-separated list of operating system
names from the system
vocabulary. This
complements the existing vocabulary
metadata
for authors, tags, and summary.
This feature helps the build farm avoid loading code for the wrong
platform. It used to be that vocabularies with the “unportable” tag set
would be skipped by load-all
, however this was too coarse-grained. For
example, both the curses and DirectX bindings were tagged as unportable,
and so the build farm was not loading or testing them on any platform.
However, curses is available on Unix systems, and DirectX is available
on Windows systems. With the new approach, there is a
extra/curses/platforms.txt
file listing unix
as a supported
platform, and the various DirectX vocabulary directories have
platforms.txt
files listing windows
.