Sempiler provides the usual distinctions for type declarations.

Classes

Use the normal source language construct for declaring a class. Sempiler only supports single inheritance as that is a common constraint across programming languages.

Public

Class members are currently public by default, which may be contrary to the semantics of your target platform. Sempiler’s origins are in TypeScript whereby members are public unless a contrary access modifier is explicitly provided.

A design goal of the project is to preserve the comfort of writing code in your favourite source language. In TypeScript we inherently rely on default public access that to oppose this might induce an unnecessary level of friction to developers (and add to transpile times and complexity).

However, it is perfectly possible to enforce the default member access semantics of a given target platform if it proves to be a priority for the community.

Destructors, Move & Copy

At present there is no official support for such operations. One draft plan is to introduce more fakeywords that can be used to designate destructors, as well as move and copy constructors.

However, the more suitable approach may be to reserve destructor, move and copy member names to follow the existing constructor or init convention in many source languages. Hence we recommend you avoid using these identifiers for methods to avoid future breaking changes.

Structs

Given the similarities of their semantics, you define structs exactly the same way as you would define a class in your source language except for the addition of the @struct decorator:

Symbol Usage Notes
@struct Placed before class keyword to designate struct Not all target platforms support structs

Inheritance

The inheritance model will depend on the semantics of the target platform NOT the source language.

For example, in TypeScript (JavaScript) the class keyword is syntactic sugar for prototype inheritance. This means inherited members will be shadowed if the derived class declares a member of the same name.

However, Sempiler has a custom resolver for call signatures which allows for proper inheritance:

The above example code is subject to the inheritance semantics of the target platform, not the source language.

Overloads

Check out the dedicated overloads documentation for how to write overloaded methods and constructors in Sempiler.

Enums

Enums are supported, but their semantics will depend on the target platform when it comes to the types of values members may have.

Aliases

Sempiler allows type aliasing provided the semantics of the target platform supports it. Please use the syntax designated by your source language for such declarations.

Union & Intersection

At present you may NOT alias a type to a complex anonymous type such as a union or intersection. This is a future advancement, but once it lands you may still only use such declarations for target platforms that support them.

Namespaces

Namespaces are not supported by all targets, such as Swift.

In TypeScript as a source language we can leverage the module keyword to model the std C++ namespace as:

Casting

Sempiler makes a distinction between conditional type assertions and forced type assertions.

Conditional

A conditional cast is one that we know may not succeed, but if it fails the result will be null rather than triggering an exception/error.

Commonly this is expressed using the as keyword, which we can see if we use TypeScript for our source language:

NOTE Not all source languages support inherent conditonal casting. TypeScript, Swift and C#, but C++ and Java do not.

Forced

A forced cast is one that we assert to be valid, and it will trigger an exception/error if it fails.

This is the standard casting semantics based on C-like type assertions often expressed with parentheses or angled brackets.

Given TypeScript as our source language we can write: