JSweet Language Specifications
==============================
Version: 2.x (snapshot)
Author : Renaud Pawlak
Author assistant: Louis Grignon
JSweet JavaDoc API: http://www.jsweet.org/core-api-javadoc/
Note: this markdown is automatically generated from the Latex source file. Do not modify directly.
Content
-------
- [Basic concepts](#basic-concepts)
- [Core types and objects](#core-types-and-objects)
- [Classes](#classes)
- [Interfaces](#interfaces)
- [Untyped objects (maps)](#untyped-objects-maps)
- [Enums](#enums)
- [Globals](#globals)
- [Optional parameters and
overloading](#optional-parameters-and-overloading)
- [Bridging to external JavaScript
elements](#bridging-to-external-javascript-elements)
- [Examples](#examples)
- [Rules for writing definitions (a.k.a.
bridges)](#rules-for-writing-definitions-a.k.a.-bridges)
- [Untyped accesses](#untyped-accesses)
- [Mixins](#mixins)
- [Generating JSweet candies from existing TypeScript
definitions](#generating-jsweet-candies-from-existing-typescript-definitions)
- [Auxiliary types](#auxiliary-types)
- [Functional types](#functional-types)
- [Object types](#object-types)
- [String types](#string-types)
- [Tuple types](#tuple-types)
- [Union types](#union-types)
- [Intersection types](#intersection-types)
- [Semantics](#semantics)
- [Main methods](#main-methods)
- [Initializers](#initializers)
- [Arrays initialization and
allocation](#arrays-initialization-and-allocation)
- [Asynchronous programming](#asynchronous-programming)
- [Name clashes](#name-clashes)
- [Testing the type of an object](#testing-the-type-of-an-object)
- [Variable scoping in lambda
expressions](#variable-scoping-in-lambda-expressions)
- [Scope of *this*](#scope-of-this)
- [Packaging](#packaging)
- [Use your files without any
packaging](#use-your-files-without-any-packaging)
- [Creating a bundle for a
browser](#creating-a-bundle-for-a-browser)
- [Packaging with modules](#packaging-with-modules)
- [Root packages](#root-packages)
- [Packaging a JSweet jar (candy)](#packaging-a-jsweet-jar-candy)
- [Extending the transpiler](#extending-the-transpiler)
- [Core annotations](#core-annotations)
- [Centralizing annotations in
`jsweetconfig.json`](#centralizing-annotations-in-jsweetconfig.json)
- [Programmatic tuning with
adapters](#programmatic-tuning-with-adapters)
- [Extension examples](#extension-examples)
- [Appendix 1: JSweet transpiler
options](#appendix-1-jsweet-transpiler-options)
- [Appendix 2: packaging and static
behavior](#appendix-2-packaging-and-static-behavior)
- [When main methods are invoked](#when-main-methods-are-invoked)
- [Static and inheritance
dependencies](#static-and-inheritance-dependencies)
Basic concepts
--------------
This section presents the JSweet language basic concepts. One must keep
in mind that JSweet, as a Java-to-JavaScript transpiler, is an extension
of Java at compile-time, and executes as JavaScript at runtime. JSweet
aims at being a trade-off between Java and JavaScript, by respecting as
much as possible the Java semantics, but without loosing
interoperability with JavaScript. So, in a way, JSweet can be seen as a
fusion between Java and JavaScript, trying to get the best of both
worlds in one unique and consistent language. In some cases, it is hard
to get the best of both worlds and JSweet makes convenient and practical
choices.
Because JSweet is an open JavaScript transpiler, the user can tune the
JavaScript generation without much efforts, thus making other choices
than default ones to map Java to JavaScript. For example, if the way
JSweet implements Java maps does not suit your context or use case, you
can program a JSweet extension to override the default strategy.
Programming and activating a JSweet extension is fully explained in
Section
6.
### Core types and objects
JSweet allows the use of primitive Java types, core Java objects
(defined in `java.lang`, many JDK classes (especially `java.util` but
not only), and of core JavaScript objects, which are defined in the
`def.js` package. Next, we describe the use of such core types and
objects.
#### Primitive Java types
JSweet allows the use of Java primitive types (and associated literals).
- `int`, `byte`, `short`, `double`, `float` are all converted to
JavaScript numbers (TypeScript `number` type). Precision usually
does not matter in JSweet, however, casting to `int`, `byte`, or
`short` forces the number to be rounded to the right-length integer.
- `char` follows the Java typing rules but is converted to a
JavaScript `string` by the transpiler.
- `boolean` corresponds to the JavaScript `boolean`.
- `java.lang.String` corresponds to the JavaScript `string`. (not per
say a primitive type, but is immutable and used as the class of
string literals in Java)
A direct consequence of that conversion is that it is not always
possible in JSweet to safely overload methods with numbers or
chars/strings. For instance, the methods `pow(int, int)` and
`pow(double, double)` may raise overloading issues. With a JSweet
context, the transpiler will be able to select the right method, but the
JavaScript interoperability may be a problem. In short, since there is
no difference between `n instanceof Integer` and `n instanceof Double`
(it both means `typeof n === ’number’`) calling `pow(number, number)`
from JavaScript will randomly select one implementation or the other.
This should not be always a problem, but in some particular cases, it
can raise subtle errors. Note that in these cases, the programmers will
be able to tune the JavaScript generation, as it is fully explained in
Section
6.
Examples of valid statements:
``` java
// warning '==' behaves like JavaScript '===' at runtime
int i = 2;
assert i == 2;
double d = i + 4;
assert d == 6;
String s = "string" + '0' + i;
assert s == "string02";
boolean b = false;
assert !b;
```
The `==` operator behaves like the JavaScript strict equals operator
`===` so that it is close to the Java semantics. Similarly, `!=` is
mapped to `!==`. There is an exception to that behavior which is when
comparing an object to a `null` literal. In that case, JSweet translates
to the loose equality operators so that the programmers see no
distinction between `null` and `undefined` (which are different in
JavaScript but it may be confusing to Java programmers). To control
whether JSweet generates strict or loose operators, you can use the
following helper methods: `jsweet.util.Lang.$strict` and
`jsweet.util.Lang.$loose`. Wrapping a comparison operator in such a
macro will force JSweet to generate a strict or loose operator. For
example:
``` java
import static jsweet.util.Lang.$loose;
[...]
int i = 2;
assert i == 2; // generates i === 2
assert !((Object)"2" == i);
assert $loose((Object)"2" == i); // generates "2" == i
```
#### Allowed Java objects
By default, JSweet maps core Java objects and methods to JavaScript
through the use of built-in macros. It means that the Java code is
directly substituted with a valid JavaScript code that implements
similar behavior. A default mapping is implemented for most useful core
Java classes (`java.lang`, `java.util`). When possible (and when it
makes sense), some partial mapping is implemented for other JDK classes
such as input and output streams, locales, calendars, reflection, etc.
With the default behavior, we can point the following limitations:
- Extending a JDK class is in general not possible, except for some
particular contexts. If extending a JDK class is required, should
should consider to refactor your program, or use a JavaScript
runtime (such as J4TS), which would allow it.
- The Java reflection API (`java.lang.reflect`) is limited to very
basic operations. It is possible to access the classes and the
members, but it is not possible to access types. A more complete
support of Java reflection would be possible, but it would require a
JSweet extension.
- Java 8 streams are not supported yet, but it would be simple to
support them partially (contributions are welcome).
Examples of valid statements:
``` java
Integer i = 2;
assert i == 2;
Double d = i + 4d;
assert d.toString() == "6";
assert !((Object) d == "6");
BiFunction f = (s, i) -> { return s.substring(i); };
assert "bc" == f.apply("abc", 1);
```
#### Getting more Java APIs
With JSweet, it is possible to add a runtime that implements Java APIs
in JavaScript, so that programmers can access more Java APIs and thus
share the same code between Java and JavaScript. The core project for
implementing Java APIs for JSweet is J4TS
() and contains a quite complete
implementation of `java.util.*` classes and other core package. J4TS is
based on a fork of the GWT’s JRE emulation, but it is adapted to be
compiled with JSweet. Programmers can use J4TS as a regular JavaScript
library available in our Maven repository.
Although J4TS cannot directly implement the Java core types that
conflict with JavaScript ones (`Boolean`, `Byte`, `Short`, `Integer`,
`Long`, `Float`, `Double`, `Character`, `String`), J4TS contributes to
supporting the static part of them by providing helpers for each class
(`javaemul.internal.BooleanHelper`, `javaemul.internal.ByteHelper`,
...). When the JSweet transpiler meets a static Java method on a type
`java.lang.T` that is not supported as a built-in macro, it delegates to
`javaemul.internal.THelper`, which can provide a JavaScript
implementation for the given static method. That way, by using J4TS,
programmers can use even more of the core JRE API.
#### Java arrays
Arrays can be used in JSweet and are transpiled to JavaScript arrays.
Array initialization, accesses and and iteration are all valid
statements.
``` java
int[] arrayOfInts = { 1, 2, 3, 4};
assert arrayOfInts.length == 4;
assert arrayOfInts[0] == 1;
int i = 0;
for (int intItem : arrayOfInts) {
assert arrayOfInts[i++] == intItem;
}
```
#### Core JavaScript API
The core JavaScript API is defined in `def.js` (the full documentation
can be found at ). Main
JavaScript classes are:
- `def.js.Object`: JavaScript Object class. Common ancestor for
JavaScript objects functions and properties.
- `def.js.Boolean`: JavaScript Boolean class. A wrapper for boolean
values.
- `def.js.Number`: JavaScript Number class. A wrapper for numerical
values.
- `def.js.String`: JavaScript String class. A wrapper and constructor
for strings.
- `def.js.Function`: JavaScript Function class. A constructor for
functions.
- `def.js.Date`: JavaScript Date class, which enables basic storage
and retrieval of dates and times.
- `def.js.Array`: JavaScript Array class. It is used in the
construction of arrays, which are high-level, list-like objects.
- `def.js.Error`: JavaScript Error class. This class implements
`java.lang.RuntimeException` and can be thrown and caught with `try`
... `catch` statements.
When using JavaScript frameworks, programmers should use this API most
of the time, which is HTML5 compatible and follows the JavaScript latest
supported versions. However, for objects that need to be used with Java
literals (numbers, booleans, and strings), the use of the `java.lang`
package classes is recommended. For instance, the jQuery API declares
`$(java.lang.String)` instead of `$(def.js.String)`. This allows the
programmer to write expressions using literals, such as `$("a")` (for
selecting all links in a document).
With JSweet, programmers can easily switch from the Java to JavaScript
API (and conversely) depending on their needs. The `jsweet.util.Lang`
class defines convenient static methods to cast back and forth core Java
objects to their corresponding JavaScript objects. For instance the
`string(...)` method will allow the programmer to switch from the Java
to the JavaScript strings and conversely.
``` java
import static jsweet.util.Lang.string;
// str is a Java string, but is actually a JavaScript string at runtime
String str = "This is a test string";
// str is exactly the same string object, but shown through the JS API
def.js.String str2 = string(str);
// valid: toLowerCase it defined both in Java and JavaScript
str.toLowerCase();
// this method is not JS-compatible, so a macro generates the JS code
str.equalsIgnoreCase("abc");
// direct call to the JS substr method on the JavaScript string
string(str).substr(1);
// or
str2.substr(1);
```
Note: for code sharing between a JavaScript client and a Java server for
instance, it is better to use Java APIs only and avoid JavaScript ones.
JavaScript API will compile valid Java bytecode but trying to execute
them on a JVM will raise unsatisfied link errors.
Here is another example that shows the use of the `array` method to
access the `push` method available on JavaScript arrays.
``` java
import static jsweet.util.Lang.array;
String[] strings = { "a", "b", "c" };
array(strings).push("d");
assert strings[3] == "d";
```
### Classes
Classes in JSweet fully support all types of Java classes declarations.
For example:
``` java
public class BankAccount {
public double balance = 0;
public double deposit(double credit) {
balance += credit;
return this.balance;
}
}
```
Which is transpiled to the following JavaScript code:
``` java
var BankAccount = (function () {
function BankAccount() {
this.balance = 0;
}
BankAccount.prototype.deposit = function(credit) {
this.balance += credit;
return this.balance;
};
return BankAccount;
})();
```
Classes can define constructors, have super classes and be instantiated
exactly like in Java. Similarly to Java, inner classes and anonymous
classes are allowed in JSweet (since version 1.1.0). JSweet supports
both static and regular inner/anonymous classes, which can share state
with enclosing classes. Still like in Java, anonymous classes can access
final variables declared in their scope. For example, the following
declarations are valid in JSweet and will mimic the Java semantics at
runtime so that Java programmers can benefit all the features of the
Java language.
``` java
abstract class C {
public abstract int m();
}
public class ContainerClass {
// inner class
public class InnerClass {
public I aMethod(final int i) {
// anonymous class
return new C() {
@Override
public int m() {
// access to final variable i
return i;
}
}
}
}
}
```
### Interfaces
In JSweet, an interface can be use like in Java. However, on contrary to
Java, there is no associated class available as runtime. When using
interfaces, JSweet generates code to emulate specific Java behaviors
(such as `instanceof` on interfaces).
JSweet supports Java 8 static and default methods. However default
methods are experimental so far and you should use them at your own
risks.
In JSweet, interfaces are more similar to interfaces in TypeScript than
in Java. It means that they must be seen as object signatures, which can
specify functions, but also properties. In order to allow using fields
as properties when defining interfaces, JSweet allows the use of regular
classes annotated with `@jsweet.lang.Interface`. For example, the
following interface types an object `Point` with 2 properties.
``` java
@Interface
public class Point {
public double x;
public double y;
}
```
To Java programmers, this may look like a very odd way to define an
object, but you must remember that it is not a class, but a type for a
JavaScript object. As such, it does not go against the OOP principles.
We can create a JavaScript object typed after the interface. Note that
the following code is not actually creating an instance of the `Point`
interface, it is creating an object that conforms to the interface.
``` java
Point p1 = new Point() {{ x=1; y=1; }};
```
This object creation mechanism is a TypeScript/JavaScript mechanism and
shall not be confused with anonymous classes, which is a Java-like
construction. Because `Point` is annotated with `@Interface`, the
transpiled JavaScript code will be similar to:
``` java
var p1 = Object.defineProperty({ x:1, y:1 }, "_interfaces", ["Point"]);
```
Note that, for each object, JSweet keeps track of which interface it was
created from and of all the potential interfaces implemented by its
class. This interface tracking system is implemented as a special object
property called `__interfaces`. Using that property, JSweet allows the
use of the `instanceof` operator on interfaces like in Java.
#### Optional fields in interfaces
Interfaces can define *optional fields*, which are used to report errors
when the programmer forgets to initialize a mandatory field in an
object. Supporting optional fields in JSweet is done through the use of
`@jsweet.lang.Optional` annotations. For instance:
``` java
@Interface
public class Point {
public double x;
public double y;
@Optional
public double z = 0;
}
```
It is the JSweet compiler that will check that the fields are correctly
initialized, when constructing an object from an interface.
``` java
// no errors (z is optional)
Point p1 = new Point() {{ x=1; y=1; }};
// JSweet reports a compile error since y is not optional
Point p2 = new Point() {{ x=1; z=1; }};
```
#### Special JavaScript functions in interfaces
In JavaScript, objects can have properties and functions, but can also
(not exclusively), be used as constructors and functions themselves.
This is not possible in Java, so JSweet defines special functions for
handling these cases.
- `$apply` is used to state that the object can be used as a function.
- `$new` is used to state that the object can be used as a
constructor.
For instance, if an object `o` is of interface `O` that defines
`$apply()`, writing:
``` java
o.$apply();
```
Will transpile to:
``` java
o();
```
Similarly, if `O` defines `$new()`:
``` java
o.$new();
```
Will transpile to:
``` java
new o();
```
Yes, it does not make sense in Java, but in JavaScript it does!
### Untyped objects (maps)
In JavaScript, object can be seen as maps containing key-value pairs
(key is often called *index*, especially when it is a number). So, in
JSweet, all objects define the special functions (defined on
`def.js.Object`):
- `$get(key)` accesses a value with the given key.
- `$set(key,value)` sets or replace a value for the given key.
- `$delete(key)` deletes the value for the given key.
#### Reflective/untyped accesses
The functions `$get(key)`, `$set(key,value)` and `$delete(key)` can be
seen as a simple reflective API to access object fields and state. Note
also the static method `def.js.Object.keys(object)`, which returns all
the keys defined on a given object.
The following code uses this API to introspect the state of an object
`o`.
``` java
for(String key : def.js.Object.keys(o)) {
console.log("key=" + key + " value=" + o.$get(key));
});
```
When not having the typed API of a given object, this API can be useful
to manipulate the object in an untyped way (of course it should be
avoided as much as possible).
#### Untyped objects initialization
One can use the `$set(key,value)` function to create new untyped object.
For instance:
``` java
Object point = new def.js.Object() {{ $set("x", 1); $set("y", 1); }};
```
It transpiles also to:
``` java
var point = { "x": 1, "y": 1};
```
As a shortcut, one can use the `jsweet.util.Lang.$map` function, which
transpiles to the exact same JavaScript code:
``` java
import static jsweet.util.Lang.$map;
[...]
Object point = $map("x", 1, "y", 1);
```
#### Indexed objects
The type of keys and values can be overloaded for every object. For
example, the `Array` class, will define keys as numbers and values as
objects conforming to type `T`.
In the case of objects indexed with number keys, it is allowed to
implement the `java.lang.Iterable` interface so that it is possible to
use they in *foreach* loops. For instance, the `NodeList` type (from the
DOM) defines an indexed function:
``` java
@Interface
class NodeList implements java.lang.Iterable {
public double length;
public Node item(double index);
public Node $get(double index);
}
```
In JSweet, you can access the node list elements with the `$get`
function, and you can also iterate with the *foreach* syntax. The
following code generates fully valid JavaScript code.
``` java
NodeList nodes = ...
for (int i = 0; i < nodes.length; i++) {
HTMLElement element = (HTMLElement) nodes.$get(i);
[...]
}
// same as:
NodeList nodes = ...
for (Node node : nodes) {
HTMLElement element = (HTMLElement) node;
[...]
}
```
### Enums
JSweet allows the definition of enums similarly to Java. The following
code declares an enum with tree possible values (`A`, `B`, and `C`).
``` java
enum MyEnum {
A, B, C
}
```
The following statements are valid statements in JSweet.
``` java
MyEnum e = MyEnum.A;
assert MyEnum.A == e;
assert e.name() == "A";
assert e.ordinal() == 0;
assert MyEnum.valueOf("A") == e;
assert array(MyEnum.values()).indexOf(MyEnum.valueOf("C")) == 2;
```
Like Java enums, additional methods, constructors and fields can be
added to enums.
``` java
enum ScreenRatio {
FREE_RATIO(null),
RATIO_4_3(4f / 3),
RATIO_3_2(1.5f),
RATIO_16_9(16f / 9),
RATIO_2_1(2f / 1f),
SQUARE_RATIO(1f);
private final Float value;
private MyComplexEnum(Float value) {
this.value = value;
}
public Float getValue() {
return value;
}
}
```
#### Enums portability notes
Simple enums are translated to regular TypeScript enums, that is to say
numbers. In JavaScript, at runtime, an enum instance is simple encode as
its ordinal. So, JSweet enums are easy to share with TypeScript enums
and a JSweet program can interoperate with a TypeScript program even
when using enums.
Enums with additional members are also mapped to TypeScript enums, but
an additional class is generated to store the additional information.
When interoperating with TypeScript, the ordinal will remain, but the
additional information will be lost. The programmers wanting to share
enums with TypeScript should be aware of that behavior.
### Globals
In Java, on contrary to JavaScript, there is no such thing as global
variables or functions (there are only static members, but even those
must belong to a class). Thus, JSweet introduces reserved `Globals`
classes and `globals` packages. These have two purposes:
- Generate code that has global variables and functions (this is
discouraged in Java)
- Bind to existing JavaScript code that defines global variables and
functions (as many JavaScript frameworks do)
In Globals classes, only static fields (global variables) and static
methods (global functions) are allowed. Here are the main constraints
applying to Globals classes:
- no non-static members
- no super class
- cannot be extended
- cannot be used as types like regular classes
- no public constructor (empty private constructor is OK)
- cannot use $get, $set and $delete within the methods
For instance, the following code snippets will raise transpilation
errors.
``` java
class Globals {
public int a;
// error: public constructors are not allowed
public Globals() {
this.a = 3;
}
public static void test() {
// error: no instance is available
$delete("key");
}
}
```
``` java
// error: Globals classes cannot be used as types
Globals myVariable = null;
```
One must remember that `Globals` classes and `global` packages are
erased at runtime so that their members will be directly accessible. For
instance `mypackage.Globals.m()` in a JSweet program corresponds to the
`mypackage.m()` function in the generated code and in the JavaScript VM
at runtime. Also, `mypackage.globals.Globals.m()` corresponds to *m()*.
In order to erase packages in the generated code, programmers can also
use the `@Root` annotation, which will be explained in Section
5.
### Optional parameters and overloading
In JavaScript, parameters can be optional, in the sense that a parameter
value does not need to be provided when calling a function. Except for
varargs, which are fully supported in JSweet, the general concept of an
optional parameter does not exist in Java. To simulate optional
parameters, JSweet programmers can use method overloading, which is
supported in Java. Here are some examples of supported overloads in
JSweet:
``` java
String m(String s, double n) { return s + n; }
// simple overloading (JSweet transpiles to optional parameter)
String m(String s) { return m(s, 0); }
// complex overloading (JSweet generates more complex code to mimic the Java behavior)
String m(String s) { return s; }
```
Bridging to external JavaScript elements
----------------------------------------
It can be the case that programmers need to use existing libraries from
JSweet. In most cases, one should look up in the available candies,
a.k.a. bridges at . When the
candy does not exist, or does not entirely cover what is needed, one can
create new definitions in the program just by placing them in the
`def.libname` package. Definitions only specify the types of external
libraries, but no implementations. Definitions are similar to
TypeScript’s `*.d.ts` definition files (actually JSweet generates
intermediate TypeScript definition files for compilation purposes).
Definitions can also be seen as similar to `*.h` C/C++ header files.
### Examples
The following example shows the backbone store class made accessible to
the JSweet programmer with a simple definition. This class is only for
typing and will be generated as a TypeScript definition, and erased
during the JavaScript generation.
``` java
package def.backbone;
class Store {
public Store(String dbName) {}
}
```
Note that definition classes constructors must have an empty body. Also,
definition classes methods must be `native`. For instance:
``` java
package def.mylib;
class MyExternalJavaScriptClass {
public native myExternalJavaScriptMethod();
}
```
It is possible to define properties in definitions, however, these
properties cannot be initialized.
### Rules for writing definitions (a.k.a. bridges)
By convention, putting the classes in a `def.libname` package defines a
set of definitions for the `libname` external JavaScript library called
`libname`. Note that this mechanism is similar to the TypeScript `d.ts`
definition files.
Candies (bridges to external JavaScript libraries) use definitions. For
instance, the jQuery candy defines all the jQuery API in the
`def.jquery` package.
Here is a list of rules and constraints that need to be followed when
writing definitions.
- Interfaces are preferred over classes, because interfaces can be
merged and classes can be instantiated. Classes should be used only
if the API defines an explicit constructor (objects can be created
with `new`). To define an interface in JSweet, just annotate a class
with `@jsweet.lang.Interface`.
- Top-level functions and variables must be defined as `public static`
members in a `Globals` class.
- All classes, interfaces and packages, should be documented with
comments following the Javadoc standard.
- When several types are possible for a function parameter, method
overloading should be preferred over using union types. When method
overloading is not possible, it can be more convenient to simply use
the `Object` type. It is less strongly typed but it is easier to
use.
- One can use string types to provide function overloading depending
on a string parameter value.
- In a method signature, optional parameters can be defined with the
`@jsweet.lang.Optional` annotation.
- In an interface, optional fields can be defined with the
`@jsweet.lang.Optional` annotation.
Definitions can be embedded directly in a JSweet project to access an
external library in a typed way.
Definitions can also be packaged in a candy (a Maven artifact), so that
they can be shared by other projects. See the *Packaging* section for
full details on how to create a candy. Note that you do not need to
write definitions when a library is written with JSweet because the Java
API is directly accessible and the TypeScript definitions can be
automatically generated by JSweet using the `declaration` option.
### Untyped accesses
Sometimes, definitions are not available or are not correct, and just a
small patch is required to access a functionality. Programmers have to
keep in mind that JSweet is just a syntactic layer and that it is always
possible to bypass typing in order to access a field or a function that
is not explicitly specified in an API.
Although, having a well-typed API is the preferred and advised way, when
such an API is not available, the use of `def.js.Object.$get` allows
reflective access to methods and properties that can then be cast to the
right type. For accessing functions in an untyped way, one can cast to
`def.js.Function` and call the generic and untyped method `$apply` on
it. For example, here is how to invoke the jQuery `$` method when the
jQuery API is not available :
``` java
import def.dom.Globals.window;
[...]
Function $ = (Function)window.$get("$");
$.$apply("aCssSelector"):
```
The `$get` function is available on instances of `def.js.Object` (or
subclasses). For a `def.js.Object`, you can cast it using the
`jsweet.util.Lang.object` helper method. For example:
``` java
import static jsweet.dom.Lang.object;
[...]
object(anyObject).$get("$");
```
In last resort, the `jsweet.util.Lang.$insert` helper method allows the
user to insert any TypeScript expression within the program. Invalid
expressions will raise a TypeScript compilation error, but it is however
not recommended to use this technique.
``` java
import static jsweet.dom.Lang.$get;
import static jsweet.dom.Lang.$apply;
[...]
// generate anyObject["prop"]("param");
$apply($get(anyObject, "prop"), "param");
```
Finally, note also the use of the `jsweet.util.Lang.any` helper method,
which can be extremely useful to erase typing. Since the `any` method
generates a cast to the `any` type in TypeScript, it is more radical
than a cast to `Object` for instance. The following example shows how to
use the `any` method to cast an `Int32Array` to a Java `int[]` (and then
allow direct indexed accesses to it.
``` java
ArrayBuffer arb = new ArrayBuffer(2 * 2 * 4);
int[] array = any(new Int32Array(arb));
int whatever = array[0];
```
### Mixins
In JavaScript, it is common practice to enhance an existing class with
news elements (field and methods). It is an extension mechanism used
when a framework defines plugins for instance. Typically, jQuery plugins
add new elements to the `JQuery` class. For example the jQuery timer
plugin adds a `timer` field to the `JQuery` class. As a consequence, the
`JQuery` class does not have the same prototype if you are using jQuery
alone, or jQuery enhanced with its timer plugin.
In Java, this extension mechanism is problematic because the Java
language does not support mixins or any extension of that kind by
default.
#### Untyped accesses to mixins
Programmers can access the added element with `$get` accessors and/or
with brute-force casting.
Here is an example using `$get` for the timer plugin case:
``` java
((Timer)$("#myId").$get("timer")).pause();
```
Here is an other way to do it exampled through the use of the jQuery UI
plugin (note that this solution forces the use of `def.jqueryui.JQuery`
instead of `def.jquery.JQuery` in order to access the `menu()` function,
added by the UI plugin):
``` java
import def.jqueryui.JQuery;
[...]
Object obj = $("#myMenu");
JQuery jq = (JQuery) obj;
jq.menu();
```
However, these solutions are not fully satisfying because clearly unsafe
in terms of typing.
#### Typed accesses with mixins
When cross-candy dynamic extension is needed, JSweet defines the notion
of a mixin. A mixin is a class that defines members that will end up
being directly accessible within a target class (mixin-ed class). Mixins
are defined with a `@Mixin` annotation. Here is the excerpt of the
`def.jqueryui.JQuery` mixin:
``` java
package def.jqueryui;
import def.dom.MouseEvent;
import def.js.Function;
import def.js.Date;
import def.js.Array;
import def.js.RegExp;
import def.dom.Element;
import def.jquery.JQueryEventObject;
@jsweet.lang.Interface
@jsweet.lang.Mixin(target=def.jquery.JQuery.class)
public abstract class JQuery extends def.jquery.JQuery {
native public JQuery accordion();
native public void accordion(jsweet.util.StringTypes.destroy methodName);
native public void accordion(jsweet.util.StringTypes.disable methodName);
native public void accordion(jsweet.util.StringTypes.enable methodName);
native public void accordion(jsweet.util.StringTypes.refresh methodName);
...
native public def.jqueryui.JQuery menu();
...
```
One can notice the `@jsweet.lang.Mixin(target=def.jquery.JQuery.class)`
that states that this mixin will be merged to the `def.jquery.JQuery` so
that users will be able to use all the UI plugin members directly and in
a well-typed way.
#### How to use
TBD.
### Generating JSweet candies from existing TypeScript definitions
TBD.
Auxiliary types
---------------
JSweet uses most Java typing features (including functional types) but
also extends the Java type system with so-called *auxiliary types*. The
idea behind auxiliary types is to create classes or interfaces that can
hold the typing information through the use of type parameters (a.k.a
*generics*), so that the JSweet transpiler can cover more typing
scenarios. These types have been mapped from TypeScript type system,
which is much richer than the Java one (mostly because JavaScript is a
dynamic language and requires more typing scenarios than Java).
### Functional types
For functional types, JSweet reuses the `java.Runnable` and
`java.util.function` functional interfaces of Java 8. These interfaces
are generic but only support up to 2-parameter functions. Thus, JSweet
adds some support for more parameters in `jsweet.util.function`, since
it is a common case in JavaScript APIs.
Here is an example using the `Function` generic functional type:
``` java
import java.util.function.Function;
public class C {
String test(Function f) {
f.apply("a");
}
public static void main(String[] args) {
String s = new C().test(p -> p);
assert s == "a";
}
}
```
We encourage programmers to use the generic functional interfaces
defined in the `jsweet.util.function` and `java.util.function` (besides
`java.lang.Runnable`). When requiring functions with more parameters,
programmers can define their own generic functional types in
`jsweet.util.function` by following the same template as the existing
ones.
In some cases, programmers will prefer defining their own specific
functional interfaces. This is supported by JSweet. For example:
``` java
@FunctionalInterface
interface MyFunction {
void run(int i, String s);
}
public class C {
void m(MyFunction f) {
f.run(1, "test");
}
public static void main(String[] args) {
new C().m((i, s) -> {
// do something with i and s
});
}
}
```
Important warning: it is to be noted here that, on contrary to Java, the
use of the `@FunctionInterface` annotation is mandatory.
Note also the possible use of the `apply` function, which is by
convention always a functional definition on the target object (unless
if `apply` is annotated with the `@Name` annotation). Defining/invoking
`apply` can done on any class/object (because in JavaScript any object
can become a functional object).
### Object types
Object types are similar to interfaces: they define a set of fields and
methods that are applicable to an object (but remember that it is a
compile-time contract). In TypeScript, object types are inlined and
anonymous. For instance, in TypeScript, the following method `m` takes a
parameter, which is an object containing an `index` field:
``` java
// TypeScript:
public class C {
public m(param : { index : number }) { ... }
}
```
Object types are a convenient way to write shorter code. One can pass an
object that is correctly typed by constructing an object on the fly:
``` java
// TypeScript:
var c : C = ...;
c.m({ index : 2 });
```
Obviously, object types are a way to make the typing of JavaScript
programs very easy to programmers, which is one of the main goals of
TypeScript. It makes the typing concise, intuitive and straightforward
to JavaScript programmers. In Java/JSweet, no similar inlined types
exist and Java programmers are used to defining classes or interfaces
for such cases. So, in JSweet, programmers have to define auxiliary
classes annotated with `@ObjectType` for object types. This may seem
more complicated, but it has the advantage to force the programmers to
name all the types, which, in the end, can lead to more readable and
maintenable code depending on the context. Note that similarily to
interfaces, object types are erased at runtime. Also `@ObjectType`
annotated classes can be inner classes so that they are used locally.
Here is the JSweet version of the previous TypeScript program.
``` java
public class C {
@ObjectType
public static class Indexed {
int index;
}
public void m(Indexed param) { ... }
}
```
Using an object type is similar to using an interface:
``` java
C c = ...;
c.m(new Indexed() {{ index = 2; }});
```
When object types are shared objects and represent a typing entity that
can be used in several contexts, it is recommended to use the
`@Interface` annotation instead of `@ObjectType`. Here is the
interface-based version.
``` java
@Interface
public class Indexed {
int index;
}
public class C {
public m(Indexed param) { ... }
}
C c = ...;
c.m(new Indexed {{ index = 2; }});
```
### String types
In TypeScript, string types are a way to simulate function overloading
depending on the value of a string parameter. For instance, here is a
simplified excerpt of the DOM TypeScript definition file:
``` java
// TypeScript:
interface Document {
[...]
getElementsByTagName(tagname: "a"): NodeListOf;
getElementsByTagName(tagname: "b"): NodeListOf;
getElementsByTagName(tagname: "body"): NodeListOf;
getElementsByTagName(tagname: "button"): NodeListOf;
[...]
}
```
In this code, the `getElementsByTagName` functions are all overloads
that depend on the strings passed to the `tagname` parameter. Not only
string types allow function overloading (which is in general not allowed
in TypeScript/JavaScript), but they also constrain the string values
(similarly to an enumeration), so that the compiler can automatically
detect typos in string values and raise errors.
This feature being useful for code quality, JSweet provides a mechanism
to simulate string types with the same level of type safety. A string
type is a public static field annotated with `@StringType`. It must be
typed with an interface of the same name declared in the same container
type.
For JSweet translated libraries (candies), all string types are declared
in a the `jsweet.util.StringTypes` class, so that it is easy for the
programmers to find them. For instance, if a `"body"` string type needs
to be defined, a Java interface called `body` and a static final field
called `body` are defined in a `jsweet.util.StringTypes`.
Note that each candy may have its own string types defined in the
`jsweet.util.StringTypes` class. The JSweet transpiler merges all these
classes at the bytecode level so that all the string types of all
candies are available in the same `jsweet.util.StringTypes` utility
class. As a result, the JSweet DOM API will look like:
``` java
@Interface
public class Document {
[...]
public native NodeListOf getElementsByTagName(a tagname);
public native NodeListOf getElementsByTagName(b tagname);
public native NodeListOf getElementsByTagName(body tagname);
public native NodeListOf getElementsByTagName(button tagname);
[...]
}
```
In this API, `a`, `b`, `body` and `button` are interfaces defined in the
`jsweet.util.StringTypes` class. When using one the method of
`Document`, the programmer just need to use the corresponding type
instance (of the same name). For instance:
``` java
Document doc = ...;
NodeListOf elts = doc.getElementsByTagName(StringTypes.a);
```
Note: if the string value is not a valid Java identifier (for instance
`"2d"` or `"string-with-dashes"`), it is then translated to a valid one
and annotated with `@Name("originalName")`, so that the JSweet
transpiler knows what actual string value must be used in the generated
code. For instance, by default, `"2d"` and `"string-with-dashes"` will
correspond to the interfaces `StringTypes._2d` and
`StringTypes.string_with_dashes` with `@Name` annotations.
Programmers can define string types for their own needs, as shown below:
``` java
import jsweet.lang.Erased;
import jsweet.lang.StringType;
public class CustomStringTypes {
@Erased
public interface abc {}
@StringType
public static final abc abc = null;
// This method takes a string type parameter
void m2(abc arg) {
}
public static void main(String[] args) {
new CustomStringTypes().m2(abc);
}
}
```
Note the use of the `@Erased` annotation, which allows the declaration
of the `abc` inner interface. This interface is used to type the string
type field `abc`. In general, we advise the programmer to group all the
string types of a program in the same utility class so that it is easy
to find them.
### Tuple types
Tuple types represent JavaScript arrays with individually tracked
element types. For tuple types, JSweet defines parameterized auxiliary
classes `TupleN`, which define `$0`, `$1`, ... `$N-1`
public fields to simulate typed array accessed (field `$i` is typed with
`Ti`).
For instance, given the following tuple of size 2:
``` java
Tuple2 tuple = new Tuple2("test", 10);
```
We can expect the following (well-typed) behavior:
``` java
assert tuple.$0 == "test";
assert tuple.$1 == 10;
tuple.$0 = "ok";
tuple.$1--;
assert tuple.$0 == "ok";
assert tuple.$1 == 9;
```
Tuple types are all defined (and must be defined) in the
`jsweet.util.tuple` package. By default classes `Tuple[2..6]` are
defined. Other tuples ( > 6) are automatically generated when
encountered in the candy APIs. Of course, when requiring larger tuples
that cannot be found in the `jsweet.util.tuple` package, programmers can
add their own tuples in that package depending on their needs, just by
following the same template as existing tuples.
### Union types
Union types represent values that may have one of several distinct
representations. When such a case happens within a method signature (for
instance a method allowing several types for a given parameter), JSweet
takes advantage of the *method overloading* mechanism available in Java.
For instance, the following `m` method accept a parameter `p`, which can
be either a `String` or a `Integer`.
``` java
public void m(String p) {...}
public void m(Integer p) {...}
```
In the previous case, the use of explicit union types is not required.
For more general cases, JSweet defines an auxiliary interface
`Union` (and `UnionN`) in the `jsweet.util.union`
package. By using this auxiliary type and a `union` utility method,
programmers can cast back and forth between union types and union-ed
type, so that JSweet can ensure similar properties as TypeScript union
types.
The following code shows a typical use of union types in JSweet. It
simply declares a variable as a union between a string and a number,
which means that the variable can actually be of one of that types (but
of no other types). The switch from a union type to a regular type is
done through the `jsweet.util.Lang.union` helper method. This helper
method is completely untyped, allowing from a Java perspective any union
to be transformed to another type. It is actually the JSweet transpiler
that checks that the union type is consistently used.
``` java
import static jsweet.util.Lang.union;
import jsweet.util.union.Union;
[...]
Union u = ...;
// u can be used as a String
String s = union(u);
// or a number
Number n = union(u);
// but nothing else
Date d = union(u); // JSweet error
```
The `union` helper can also be used the other way, to switch from a
regular type back to a union type, when expected.
``` java
import static jsweet.util.Lang.union;
import jsweet.util.union.Union3;
[...]
public void m(Union3> u) { ... }
[...]
// u can be a String, a Number or a Date
m(union("a string"));
// but nothing else
m(union(new RegExp(".*"))); // compile error
```
Note: the use of Java function overloading is preferred over union types
when typing function parameters. For example:
``` java
// with union types (discouraged)
native public void m(Union3> u);
// with overloading (preferred way)
native public void m(String s);
native public void m(Number n);
native public void m(Date d);
```
### Intersection types
TypeScript defines the notion of type intersection. When types are
intersected, it means that the resulting type is a larger type, which is
the sum of all the intersected types. For instance, in TypeScript,
`A & B` corresponds to a type that defines both `A` and `B` members.
Intersection types in Java cannot be implemented easily for many
reasons. So, the practical choice being made here is to use union types
in place of intersection types. In JSweet, `A & B` is thus defined as
`Union`, which means that the programmer can access both `A` and
`B` members by using the `jsweet.util.Lang.union` helper method. It is
of course less convenient than the TypeScript version, but it is still
type safe.
Semantics
---------
Semantics designate how a given program behaves when executed. Although
JSweet relies on the Java syntax, programs are transpiled to JavaScript
and do not run in a JRE. As a consequence, the JavaScript semantics will
impact the final semantics of a JSweet program compared to a Java
program. In this section, we discuss the semantics by focusing on
differences or commonalities between Java/JavaSript and JSweet.
### Main methods
Main methods are the program execution entry points and will be invoked
globally when a class containing a `main` method is evaluated. For
instance:
``` java
public class C {
private int n;
public static C instance;
public static void main(String[] args) {
instance = new C();
instance.n = 4;
}
public int getN() {
return n;
}
}
// when the source file containing C has been evaluated:
assert C.instance != null;
assert C.instance.getN() == 4;
```
The way main methods are globally invoked depends on how the program is
packaged. See the appendixes for more details.
### Initializers
Initializers behave like in Java.
For example:
``` java
public class C1 {
int n;
{
n = 4;
}
}
assert new C1().n == 4;
```
And similarly with static initializers:
``` java
public class C2 {
static int n;
static {
n = 4;
}
}
assert C2.n == 4;
```
While regular initializers are evaluated when the class is instantiated,
static initializers are lazily evaluated in order to avoid
forward-dependency issues, and mimic the Java behavior for initializers.
With JSweet, it is possible for a programmer to define a static field or
a static intializer that relies on a static field that has not yet been
initialized.
More details on this behavior can be found in the appendixes.
### Arrays initialization and allocation
Arrays can be used like in Java.
``` java
String[] strings = { "a", "b", "c" };
assert strings[1] == "b";
```
When specifying dimensions, arrays are pre-allocated (like in Java), so
that they are initialized with the right length, and with the right
sub-arrays in case of multiple-dimensions arrays.
``` java
String[][] strings = new String[2][2];
assert strings.length == 2;
assert strings[0].length == 2;
strings[0][0] = "a";
assert strings[0][0] == "a";
```
The JavaScript API can be used on an array by casting to a
`def.js.Array` with `jsweet.util.Lang.array`.
``` java
import static jsweet.util.Lang.array;
[...]
String[] strings = { "a", "b", "c" };
assert strings.length == 3;
array(strings).push("d");
assert strings.length == 4;
assert strings[3] == "d";
```
In some cases it is preferable to use the `def.js.Array` class directly.
``` java
Array strings = new Array("a", "b", "c");
// same as: Array strings = array(new String[] { "a", "b", "c" });
// same as: Array strings = new Array(); strings.push("a", "b", "c");
assert strings.length == 3;
strings.push("d");
assert strings.length == 4;
assert strings.$get(3) == "d";
```
### Asynchronous programming
JSweet supports advanced asynchronous programming beyond the basic
callback concepts with the help of the ES2015+ Promise API.
#### Promises
It is very simple to define an asynchronous method by declaring a
`Promise` return type. The following method’s `Promise` will be
*fulfilled* when millis milliseconds elapsed.
``` java
Promise delay(int millis) {
return new Promise((Consumer resolve, Consumer