Language Versioning
Jonathan Marler
johnnymarler at gmail.com
Thu Apr 4 12:38:01 UTC 2019
This is an informal proposal to add a versioning scheme to the D
Language. If you'd like to take the time to read, please let
everyone know your thoughts and suggestions for the idea. To
Walter and Andrei, please let me know your thoughts, if you think
the idea has merit and if so what the next steps should be (i.e.
DIP/PR/More Resarch Discussion Needed).
As I've been thinking about various proposals and additions to
the D language, it occurred to me that I'd like to be able to
declare inside my code that it requires a certain version or
certain features of the D language in order to work properly.
For example, when I look at the changelog for DMD version 2.085,
I see that support for Objective-C classes was added. However, I
would be hesitant to use that feature until a certain amount of
time has passed. This is because using it would make my
libraries/applications only work with a small percentage of
compilers in the world, those who have recently updated their
compiler, and the error messages people would get could make it
difficult to know that they just need to update their compiler
for it to work with my code. Currently the only way to solve
this problem is to wait a certain amount of time until I feel its
reasonable that enough people will have updated their compiler.
I think we can do better.
My current idea is to implement a list of versions and feature
names. Such a list could be dumped with something like:
> dmd --list-versions
2018_02_03 StaticForeach
2018_02_20 NoGCExceptions
2018_03_10 ObjectiveCClasses
Implemented StaticForeach
Implemented NamedParameters
NotImplemented CopyConstructor
NotImplemented ExpressionBasedContracts
The idea here is that once a feature has been implemented and has
been enabled by default, the version would be updated and that
particular feature would be assigned to that version. Also note
that the version number represents a date, which allows the
compiler to know when that version was implemented so it can know
how "out-of-date" it is (i.e. 2 years, 1 month etc). You'll also
notice that some features were not assigned a version number but
were either assigned an "Implemented" or "NotImplmeented" tag.
This indicates whether or the feature can be enabled, where
"Implemented" means it can. Once a feature has been implemented
and enabled by default, then it will be assigned a version number
representing the date it was enabled by default.
Then we can add ways for modules to declare version/feature
requirements, such as:
pragma(dlangVersionAtLeast, 2017_11_25);
pragma(dlangVersionUpTo, 2018_09_02);
pragma(requireFeature, ObjectiveCClasses);
The way the compiler handles these pragmas can allow the compiler
to print nice error messages when it can't satisfy the
version/feature requirements of the module. For example, if a
module declares `pragma(dlangVersionAtLeast, 2019_01_02)`, but it
only support up to version 2018_05_06, then it can print an error
message like:
Error: module 'x' requires dlang version '2019_01_02' but you're
at version '2018_05_06'. Your compiler is 7 months too old to
compile this code.
Notice that since the version has the date encoded into it, the
compiler knows how old it is compared to the compiler version it
needs to compile this module.
Since each version is also tied to a feature name, this would
also allow modules to enable features even when they aren't
turned on by default, i.e.
pragma(requireFeature, NoGCExceptions);
If possible, this could have the same affect as specifying
`-dip1008` on the command-line. In some cases, there may be
features that can't be enabled once you've already started
compilation of modules, and in this cases you could get a nice
error message like:
Error: module 'x' requires the 'NoGCExceptions' feature. Please
provide the '-dip1008' option to compile this code.
Of course, if this versioning is enabled, each version could use
a general command-line syntax such as
`--enable-feature=NoGCExceptions`.
Along with these pragmas, another feature would be to allow code
to obtain the version and/or check whether certain features can
be enabled at compile time to work with multiple version of the
lanaguage. So adding a couple traits like
__traits(tryEnableFeature, NoGCExceptions)
And could be used like:
static if (__traits(tryEnableFeature, NoGCExceptions))
{
@nogc:
}
As D matures, these versioning mechanisms could alleviate some of
the pain in introducing new features to the language by allowing
the compilers of today to be aware of the timeline and feature
names of features that are yet to be implemented. It also allows
the code to declare what features it can work with and even allow
it to work adapt based on the version of the compiler you are
using. Furthermore, it provides the opportunity to support a
consistent command-line syntax that will always work when a new
feature is introduced.
More information about the Digitalmars-d
mailing list