Deprecation warnings in Jaunt
08 Mar 2016This week I’m working on getting Jaunt’s 1.9.0 release nearer the door, on which note I’m happy to properly demo one the features of this first release: deprecation warnings.
A bare REPL will do for these demos.
$ cd $(mktemp -d)
$ wget https://clojars.org/repo/org/jaunt-lang/jaunt/1.9.0-RC4/jaunt-1.9.0-RC4.jar
$ java -jar jaunt-1.9-RC4.jar
Jaunt #2 (not my best ticket ever in terms of hygiene) was the first work I did on what became Jaunt and was really pretty critical for getting my teeth into the project and validating that there were tractable incremental improvements to be made over Clojure.
This change introduced four new switches to the Jaunt compiler, the most interesting of which is
:warn-on-deprecated
which enables or disables compiler warnings in support the use of
^:deprecated
metadata on functions and namespaces. :warn-on-deprecated
is on (true
) by
default, although it can be disabled globally with the JVM system property
clojure.compiler.warn-on-deprecated=false
, or by set!
ing clojure.core/*compiler-options*
say
to have (set! *compiler-options* (dissoc *compiler-options* :warn-on-deprecated))
in a namespace
where you want these checks to be disabled.
The semantics of deprecation are simple:
- A namespace is deprecated if and only if it has the
^:deprecated
metadata. - A definition (Var) is deprecated if either it occurs within a
^:deprecated
namespace, or is itself marked^:deprecated
.
Vars and namespaces may become deprecated in any SemVer minor version or major version, but may only legally be deleted only on a major version.
Deprecation warnings are only emitted when a deprecated namespace or definition is accessed from a context which is not deprecated. Deprecated contexts are namespaces which are deprecated, and the bodies of deprecated definitions.
So for instance, in the following code:
The definition of bad-idea
itself is innocuous. Simply evaluating deprecated definitions is
fine. Warning that also-bad-idea
uses bad-idea
would be superfluous, because that fact is
innocuous so long as neither is used. Suppressing warnings in this case allows Jaunt to load
arbitrarily much deprecated code without drowning a user with false positive warnings.
Users should only have to care about deprecation at the edge between current code and deprecated
code. Thus compiling almost-better-idea
will emit a warning that it makes use of bad-idea
, since
almost-better-idea
is not itself deprecated. Likewise at the repl invoking either deprecated
function would also generate a warning.
As to namespaces, similar principles apply. Consider the two namespaces and trace:
As the whole com.proj.code
namespace is deprecated, merely referencing it and requiring that it be
loaded is cause for a warning. Should that namespace ever be removed, the require would break
regardless of whether anything from the required namespace is used or not.
If symbols which are deprecated are referred into a namespace which is not deprecated, each one of
those will generate a warning as well for the same reason. However Jaunt tries to be smart about
this, suppressing such warnings if a (require ' [... :refer :all])
or a (use ...)
directive has
been issued which constitutes an indefinite referral.
The symbol com.proj.code/some-const
, is deprecated by dint of being defined in a deprecated
namespace. Consequently a warning is emitted when it is used outside of a deprecated context, here
in the definition of com.proj.new-code/h
.
One last demo, disabling warnings!
There’s more than just this coming down the line in Jaunt, so if you’re interested check out the
1.9 CHANGELOG, watch
the repo or stay tuned here for more demos. Issues, ideas and
especially pull requests are welcome :D
^d