Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kjellwinblad/1bba90134379a76b70fc0b367b7c50b4 to your computer and use it in GitHub Desktop.
Save kjellwinblad/1bba90134379a76b70fc0b367b7c50b4 to your computer and use it in GitHub Desktop.
Erlang Experimental Feature Support Investigation Report

Erlang Experimental Language Features Investigation Report

Erlang currently does not support selectively using experimental language features that are not officially part of the Erlang language. Having support for doing so can help users try out and experiment with a potential extension to the language without adding this extension to the main language. This report looks into how support for selectively including experimental language features looks in other languages and how such support might look in Erlang.

Support for Selectively Enabling Experimental Language Features in Other Languages

Python

Pyhton has support for making language extensions or changes optional before they become mandatory. The Python module __future__ defines several feature names like this:

FeatureName = _Feature(OptionalRelease, MandatoryRelease, CompilerFlag)
  • OptionalRelease is the release in which one could first optionally enable the feature
  • MandatoryRelease is the release when the feature became/"is planned to be" mandatory
  • CompilerFlag is the compiler flags that need to be passed to the compile module function to enable the feature

Python has a special statement that needs to be placed near the top of a python module to enable a language feature in a specific module. Statements to enable features that have already become mandatory have no effect.

In Python, feature names are never removed from the __future__ module, which means that the __future__ module contains a history of language changes.

Some of the benefits of Pythons future import statement and future module are:

  • Users can start migrating code module by module before using a release in which a potential backward incompatible change is made mandatory.
  • Users can start to experiment with language extensions before they are enabled by default
  • A problem with a language extension can be found and fixed (or the language extension can be removed) before it is made mandatory
  • A programmatically accessible history of language changes is accessible through the __future__ module. Tools can use this history, for example, to remove from __future__ import x-statements that are no longer necessary.

Ruby

Ruby does not have special support for experimental features (experimental features are just documented as experimental in the documentation). See this issue that proposes using command line flags to enable experimental features for more information.

Rust

Rust has a special syntax for activating experimental language features. Here is one example:

#![feature(box_syntax)]

fn main() {
    let five = box 5;
}

Such features are called unstable in Rust's terminology. They might change or disappear at any time.

One activates the feature for the current compilation unit (crate).

Haskell

Haskell makes it possible to activate certain language features with a pragma in the file header:

{-# LANGUAGE TemplateHaskell #-}

Java

Java lets users test features that are planned for a later release. This needs to be enabled by passing compiling flags to the compiler when compiling the Java file:

javac --enable-preview --release 12 # other flags

The line above can enable language features planned for Java version 12 in earlier Java versions before Java version 12 is released. To limit the use of preview features, one also has to pass -enable-preview when running a Java program compiled using the -enable-preview flag. A warning message is always printed when a preview feature is used.

When one enables preview features for a specific release in java, one gets all preview features from that release. It is not possible to select a single feature.

Features are not released as a preview feature unless they are considered good enough to be included without modifications. Therefore, changes to preview features are relatively rare but can happen.

See here for more details.

Suggestion for Erlang

The following methods may be used to activate an experimental feature:

  • -compile(). directive inside a file,
  • an option passed to one of the compile functions in the compile module or,
  • a compilation flag passed to erlc.

The option/flag to enable an experimental feature can have a prefix and the experimental future's name:

Examples:

-compile([{enable_experimental, pinning_operator}]).

compile:file(File, [{enable_experimental,pinning_operator}])

erlc -enable_experimental_pinning_operator

In the above examples, enable_experimental is the prefix and pinning_operator is the experimental feature's name.

All experimental features currently existing and that have existed in the past can be "documented" in a special module (similar to Pyhton). Let us assume that this module is called experimental_features. This module can be public to allow external tools to use the module or internal only if we want to be able to make changes to its API.

The experimental_features module has functions that can be used to obtain information about experimental features:

list_experimental_features() -> [atom()].

This function returns a list of all experimental features that are currently existing and that have existed.

get_experimental_feature_info(FeatureName) -> Result where
FeatureName :: atom(),
description :: string(),
Type :: extension | backwords_incompatible_change,
Result :: missing | FeatureInfoMap,
FeatureInfoMap :: #{optional_release := ReleaseNr, 
                    status := experimental | %% May be removed or changed
                              {remove_planned, ReleaseNr, AdditionalInfo :: string()} |
                              {inclusion_planned, ReleaseNr} |
                              {removed, ReleaseNr, AdditionalInfo :: string()},
                              {included, ReleaseNr}
                    compiler_options := list() %% list of compiler options that needs to be given to activate this feature
                                               %% (this can be useful, for example, when one experimental feature depend on another)
                   },
ReleaseNr : {Major :: integer(), Minor :: integer(), Patch :: integer(), Label :: string()}.

This function returns information associated with a given feature name.

External and internal tools may use the information that one can get from the experimental_features module to:

  • Warn about the usage of something that will be removed
  • Give error if something that has got removed is used
  • Tell the compiler which options it should use to activate a certain experimental feature
  • Automatically remove {enable_experimental,x} tuples from -compile() directives when they are no longer necessary.
  • Automatically give information about which features become mandatory between two releases (which can give the user information about what needs to be changed before an upgrade is made)

Preventing that Experimental Features are used too Much in Production Code

Similar to Java we can emit information that an experimental feature is used in the compiled module. The VM can use this information to print a warning message when running a module that contains an experimental feature. We can also force usage of a special flag when running code that are compiled with an experimental feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment