Target languages#
Temper translates to other programming languages through backends, one per target language. Each backend:
- translates Temper to the target language's source,
- writes source files, source maps where the language has them, and
package files (a
.csproj, apom.xml, apackage.json, …) undertemper.out/BACKEND/LIBRARY/, and - runs the translated tests with the language's own tools.
Each backend has an ID, which the -b (--backend) flag of
temper build and temper test takes (the command line).
By default, temper build builds C#, Java, JavaScript, Lua, Python,
and Rust; C++ is built when asked for (-b cpp).
| Language | ID | Targets | Package | Tests run with |
|---|---|---|---|---|
| C++ | cpp |
C++14 (C++20 for co_await) |
a CMake project | its own test program |
| C# | csharp |
.NET 6 (net6.0) |
a .csproj |
MSTest |
| Java | java |
Java 17 | a Maven pom.xml |
JUnit 5 |
| JavaScript | js |
ES modules, with JSDoc types for TypeScript | a package.json |
Mocha |
| Lua | lua |
Lua 5.1 and later, and LuaJIT | a rockspec | LuaUnit |
| Python | py |
Python 3.11 and later | a pyproject.toml |
unittest |
| Rust | rust |
Rust 1.71.1 and later, edition 2021 | a crate | cargo test |
How each backend is built, and what it chooses for failure, null, naming, and order of evaluation, is in how tempest works: backends and its per-backend table. Getting started with each language is in the getting started guide.
Note: Temper's first compiler also has
java8,mypyc, anddatabackends, and an experimentalcppv; tempest doesn't have them yet (inconsistencies).
C++ (cpp)#
Translates Temper to C++14: a header and a source file per module
(LIBRARY/init.hpp and init.cpp), a main.cpp that runs the
library, and a CMake project. Objects are std::shared_ptrs, and a
library's namespace is its name.
Generated code compiles without warnings under -Wall -Wextra -Wpedantic -Werror, and is tested under AddressSanitizer, UBSan, and
TSan. C++ leaves the order of evaluation of arguments open, so the
backend keeps Temper's left-to-right order wherever it would show.
C++20 code can co_await a Temper promise.
Note: Temper's older docs list C++ as "coming soon", and leave it out of this list; tempest's C++ backend passes every functional test (inconsistencies).
C# (csharp)#
Translates Temper to C#. Targets .NET 6.0; .NET Framework 4.8 might be supported in the future.
Translation notes#
Temper function types, such as fn (Int): Int, translate to
Func delegates, or Action delegates for a
Void result. These have an upper limit of 16 parameters, which isn't
accounted for yet. If demand arises, Temper will likely generate new
delegate types for more parameters.
Temper nullable types, such as A?, translate to nullable
value types or nullable reference types. Nullable reference types need
newer versions of C#, so .NET Framework 4.8 support would need to
represent these as ordinary reference types.
To show intent clearly, Temper collection types translate to .NET
generic interfaces, including "ReadOnly" variants as appropriate. For
example, Temper Listed<T> and List<T> both translate to
IReadOnlyList<T>, whereas ListBuilder<T>
translates to IList<T>. Similar rules apply to Temper's
Mapped types and .NET Dictionary types, except that
maps created in Temper always keep insertion order. .NET's IList
doesn't subtype IReadOnlyList, even though its List
implements both, and likewise for Dictionary, so Temper generates
overloads of functions taking a Listed that accept any of List,
IList, or IReadOnlyList, and likewise for Mapped.
Each Temper library is translated to a .NET project
and assembly, and each module to a
.NET namespace, with a subdirectory for each
subnamespace. Each type defined in Temper gets its own C# file, and a
module's top level goes in a static …Global class. Parameter names
are part of a C# API, so they're never renamed.
Temper's logging console translates to the
Microsoft.Extensions.Logging framework on modern .NET.
That framework usually creates loggers by dependency
injection, which doesn't suit static classes and static
initialization, so Temper generates static methods to give a library
its ILogger. Without one, generated libraries log through
System.Diagnostics.Trace.
Tooling notes#
Each Temper library gets a .csproj file, so each builds
to its own .NET assembly.
The only .NET naming setting in config.temper.md today is
csharpRootNamespace. It sets the project's root namespace, the
assembly's name, and the presumed NuGet package ID.
Microsoft has advice on choosing a namespace.
Temper test blocks translate to the
MSTest framework: a test class per module, and a test
method per test. Temper provides soft assertions within tests.
Java (java)#
Translates Temper to Java 17 source, and a Maven project
(Java 17). A module's top level goes in a …Global class, with a
…Main class to run it, and each type gets its own file. Classes also
get a Builder, since Java has no named arguments.
Still to write up: how function types translate to single-method
interfaces, how nullable types translate, primitive and boxed types,
overloads for optional arguments, picking a Java package and Maven
identifiers (javaName, javaPackage), and the generated POM.
JavaScript (js)#
Translates Temper to JavaScript ES modules, with types in JSDoc comments
for TypeScript, checked with tsc --strict.
Translation notes#
Temper interface types translate to names that work with JavaScript's
instanceof operator. Your JavaScript code may use
InterfaceType.implementedBy to make classes
that implement Temper interfaces.
temper.out/js has a source map for each generated file, so a
JavaScript debugger shows the Temper code it came from.
Tooling notes#
Tests translate to Mocha tests, and a package.json
makes npm test run them.
Note: Temper's older docs say the JavaScript backend targets ES2018, and its getting started guide says Node 14 or later, while a 0.x release note requires Node 18 (inconsistencies).
Lua (lua)#
Translates Temper to Lua: an init.lua per library, a rockspec, and
LuaCATS type annotations, checked with LuaLS. Generated code is
declared for Lua 5.1 and later; it's tested on Lua 5.4 and LuaJIT.
Note: a few features need Lua 5.3 or later, such as some string and integer operations; Lua 5.1 itself isn't tested (inconsistencies).
Python (py)#
Translates Temper to Python 3 with type annotations, checked with mypy and pyright in strict mode. Targets Python 3.11 and later; for best support, use CPython.
Translation notes#
Temper's Void type translates to
returning Python's None.
Temper default expressions are evaluated as needed, so they don't suffer the singly evaluated default expression pitfall.
Names translate to Python's conventions: snake_case for functions,
methods, and properties, and a leading _ for what isn't exported.
Rust (rust)#
Translates Temper to a Rust crate (edition 2021, rust-version
1.71.1). Classes are reference-counted handles (Arc), strings are
Arc<String>, failure is a Result, and module state is safe across
threads. Generated code passes clippy.