mirror of
https://github.com/cincheo/jsweet.git
synced 2025-12-15 07:19:22 +00:00
1339 lines
63 KiB
TeX
1339 lines
63 KiB
TeX
\documentclass[a4paper]{report}
|
|
|
|
\usepackage[a4paper, margin=3cm]{geometry}
|
|
\usepackage{times}
|
|
\usepackage{graphicx}
|
|
%\usepackage{color}
|
|
%\usepackage{multirow}
|
|
\usepackage{url}
|
|
\usepackage{verbatim}
|
|
\usepackage{hyperref}
|
|
\usepackage{wrapfig}
|
|
\usepackage{titling}
|
|
|
|
\usepackage{listings}
|
|
\usepackage{color}
|
|
\usepackage{titlesec}
|
|
\usepackage[htt]{hyphenat}
|
|
|
|
\definecolor{dkgreen}{rgb}{0,0.6,0}
|
|
\definecolor{gray}{rgb}{0.5,0.5,0.5}
|
|
\definecolor{lightgray}{rgb}{0.95,0.95,0.95}
|
|
\definecolor{mauve}{rgb}{0.58,0,0.82}
|
|
|
|
\definecolor{dkgreen}{rgb}{0,0.6,0}
|
|
\definecolor{gray}{rgb}{0.5,0.5,0.5}
|
|
\definecolor{lightgray}{rgb}{0.7,0.7,0.7}
|
|
\definecolor{lightlightgray}{rgb}{0.98,0.98,0.98}
|
|
\definecolor{mauve}{rgb}{0.58,0,0.82}
|
|
|
|
\lstset{
|
|
language=Java,
|
|
aboveskip=3mm,
|
|
belowskip=3mm,
|
|
showstringspaces=false,
|
|
columns=flexible,
|
|
basicstyle={\small\ttfamily},
|
|
numbers=none,
|
|
numberstyle=\tiny\color{gray},
|
|
keywordstyle=\color{blue},
|
|
commentstyle=\color{dkgreen},
|
|
stringstyle=\color{mauve},
|
|
breaklines=true,
|
|
breakatwhitespace=true,
|
|
tabsize=2,
|
|
backgroundcolor=\color{lightlightgray},
|
|
frame=single,
|
|
rulecolor=\color{lightgray},
|
|
morekeywords={assert}
|
|
}
|
|
|
|
\titleformat{\chapter}{\bfseries\LARGE}{\thechapter.}{1ex}{}[]
|
|
\titlespacing{\chapter}{0pt}{20pt}{16pt}
|
|
|
|
\pretitle{%
|
|
\begin{center}
|
|
\LARGE
|
|
\includegraphics[width=8cm]{logo}\\[\bigskipamount]
|
|
}
|
|
\posttitle{\end{center}}
|
|
|
|
\newcommand{\code}[1]{\texttt{\small #1}}
|
|
\newcommand{\api}[1]{\subsection*{\normalsize\texttt{#1}}}
|
|
|
|
\begin{document}
|
|
|
|
\title{JSweet Language Specifications\\{\large Version 1.1.0}}
|
|
\author{%
|
|
Renaud Pawlak\\
|
|
{\normalsize renaud.pawlak@jsweet.org}\\
|
|
{\normalsize http://www.jsweet.org}\\
|
|
}% author
|
|
\date{}
|
|
\maketitle
|
|
|
|
\tableofcontents
|
|
|
|
\chapter{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. Thus, most Java typing and syntactic constraints will apply at compile time, but some JavaScript semantics may apply at runtime. This document will mention when Java syntactic constructs and semantics are not legal (or differ) in JSweet.
|
|
|
|
\section{Core types and objects}
|
|
|
|
JSweet allows the use of primitive Java types, core Java objects (with some restrictions) and of core JavaScript objects, which are defined in the \texttt{jsweet.lang} package. Next, we describe the use of such core types and objects.
|
|
|
|
\subsection{Primitive Java types}
|
|
|
|
JSweet allows the use of Java primitive types (and associated literals).
|
|
|
|
\begin{itemize}
|
|
\item \texttt{int}, \texttt{byte}, \texttt{short}, \texttt{double}, \texttt{float} are all converted to JavaScript numbers (precision does not matter in JSweet).
|
|
\item \texttt{char} follows the Java typing rules but is converted to a JavaScript string by the transpiler.
|
|
\item \texttt{boolean} corresponds to the JavaScript boolean.
|
|
\item \texttt{java.lang.String} corresponds to the JavaScript \texttt{string}. (not per say a primitive type, but is immutable and used as the class of string literals in Java)
|
|
\end{itemize}
|
|
|
|
\noindent
|
|
Examples of valid statements:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// warning '==' behaves like the JavaScript one 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;
|
|
\end{lstlisting}
|
|
|
|
Note that in JSweet the \texttt{==} operator behaves like in JavaScript on primitive types, so that when comparing a string and an integer, it will try to match the two without taking the types in consideration. For instance, \texttt{"2" == 2} evaluates to \texttt{true}. In JavaScript, one can use the \texttt{===} operator to strictly compare the objects, so that \texttt{"2" === 2} evaluates to \texttt{false}. To use the \texttt{===} operator in JSweet, use the \texttt{jsweet.util.Globals.equalsStrict} utility method as follows.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.equalsStrict;
|
|
[...]
|
|
int i = 2;
|
|
assert i == 2;
|
|
assert "2" == i;
|
|
assert !(equalsStrict("2", i);
|
|
\end{lstlisting}
|
|
|
|
\subsection{Allowed Java objects}
|
|
|
|
Here follows the list of allowed Java classes in JSweet:
|
|
|
|
\begin{itemize}
|
|
\item \texttt{java.lang.Object}
|
|
\begin{itemize}
|
|
\item allowed methods: \texttt{toString()}
|
|
\end{itemize}
|
|
\item \texttt{java.lang.String}
|
|
\begin{itemize}
|
|
\item allowed methods:
|
|
\begin{itemize}
|
|
\item \texttt{charAt(int)}
|
|
\item \texttt{concat(java.lang.String)}
|
|
\item \texttt{indexOf(java.lang.String)}
|
|
\item \texttt{lastIndexOf(java.lang.String)}
|
|
\item \texttt{lastIndexOf(java.lang.String,int)}
|
|
\item \texttt{length()} (transpiles to \texttt{length})
|
|
\item \texttt{substring(int)}
|
|
\item \texttt{substring(int,int)} (with the JavaScript behavior)
|
|
\item \texttt{replace(java.lang.CharSequence,java.lang.CharSequence)}
|
|
\item \texttt{split(java.lang.String)}
|
|
\item \texttt{trim()}
|
|
\item \texttt{toLowerCase()}
|
|
\item \texttt{toUpperCase()}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Class}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Boolean}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Void}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Integer}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Double}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Number}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Float}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Byte}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Short}
|
|
\begin{itemize}
|
|
\item allowed methods: none
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Iterable}
|
|
\begin{itemize}
|
|
\item allowed methods: none (for using the \emph{foreach} loop on indexed objects)
|
|
\end{itemize}
|
|
\item \texttt{java.lang.Runnable}
|
|
\begin{itemize}
|
|
\item allowed methods: none (for declaring lambdas)
|
|
\end{itemize}
|
|
\item \texttt{java.util.function.*} (for declaring lambdas)
|
|
\begin{itemize}
|
|
\item prohibited method names:
|
|
\begin{itemize}
|
|
\item \texttt{and}
|
|
\item \texttt{negate}
|
|
\item \texttt{or}
|
|
\item \texttt{andThen}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
\end{itemize}
|
|
|
|
\noindent
|
|
Examples of valid statements:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// warning '==' behaves like the JavaScript one at runtime
|
|
Integer i = 2;
|
|
assert i == 2;
|
|
Double d = i + 4d;
|
|
assert d.toString() == "6";
|
|
assert (Object) d == "6";
|
|
BiFunction<String, Integer, String> f = (s, i) -> { return s.substring(i); };
|
|
assert "bc" == f.apply("abc", 1);
|
|
\end{lstlisting}
|
|
|
|
\subsection{Java arrays}
|
|
|
|
Arrays can be used in JSweet and are transpiled to JavaScript arrays. Array initialization, accesses and and iteration are all valid statements.
|
|
|
|
\begin{lstlisting}[language=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;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\subsection{Core JavaScript API}
|
|
|
|
The core JavaScript API is defined in \texttt{jsweet.lang} (the full documentation can be found at \url{http://www.jsweet.org/core-api-javadoc/}). Main JavaScript classes are:
|
|
|
|
\begin{itemize}
|
|
\item \texttt{jsweet.lang.Object}: JavaScript Object class. Common ancestor for JavaScript objects functions and properties.
|
|
\item \texttt{jsweet.lang.Boolean}: JavaScript Boolean class. A wrapper for boolean values.
|
|
\item \texttt{jsweet.lang.Number}: JavaScript Number class. A wrapper for numerical values.
|
|
\item \texttt{jsweet.lang.String}: JavaScript String class. A wrapper and constructor for strings.
|
|
\item \texttt{jsweet.lang.Function}: JavaScript Function class. A constructor for functions.
|
|
\item \texttt{jsweet.lang.Date}: JavaScript Date class, which enables basic storage and retrieval of dates and times.
|
|
\item \texttt{jsweet.lang.Array<T>}: JavaScript Array class. It is used in the construction of arrays, which are high-level, list-like objects.
|
|
\item \texttt{jsweet.lang.Error}: JavaScript Error class. This class implements \texttt{java.lang.RuntimeException} and can be thrown and caught with \texttt{try} ... \texttt{catch} statements.
|
|
\end{itemize}
|
|
|
|
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 \texttt{java.lang} package classes is recommended. For instance, the jQuery API declares \texttt{\$(java.lang.String)} instead of \texttt{\$(jsweet.\-lang.\-String)}. This allows the programmer to write expressions using literals, such as \texttt{\$($"$a$"$)} (for selecting all links in a document).
|
|
|
|
As a consequence, programmers need to be able to switch to the JavaScript API when coming from a Java object. The \texttt{jsweet.util.Globals} class defines convenient static methods to cast back and forth core Java objects to their corresponding JSweet objects. For instance the \texttt{string(...)} method will allow the programmer to switch from the Java to the JSweet strings and conversely.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.string;
|
|
String str = "This is a test string";
|
|
str.toLowerCase(); // valid: toLowerCase it defined both in Java and JavaScript
|
|
str.substr(1); // compile error: substr is not a Java method
|
|
string(str).substr(1); // valid: string(str) is a jsweet.lang.String.
|
|
\end{lstlisting}
|
|
|
|
Note: using the \texttt{jsweet.util.Globals} class to access the JavaScript API can be avoided in some cases when working in \emph{strict} mode (see Appendix 2).
|
|
|
|
\noindent
|
|
Here is another example that shows the use of the \texttt{array} method to access the \texttt{push} method available on JavaScript arrays.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.array;
|
|
String[] strings = { "a", "b", "c" };
|
|
array(strings).push("d");
|
|
assert strings[3] == "d";
|
|
\end{lstlisting}
|
|
|
|
\section{Classes}
|
|
|
|
Classes in JSweet are very similar to Java classes. For example:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class BankAccount {
|
|
public double balance = 0;
|
|
public double deposit(double credit) {
|
|
balance += credit;
|
|
return this.balance;
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\noindent
|
|
Which is transpiled to the following JavaScript code:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
var BankAccount = (function () {
|
|
function BankAccount() {
|
|
this.balance = 0;
|
|
}
|
|
BankAccount.prototype.deposit = function(credit) {
|
|
this.balance += credit;
|
|
return this.balance;
|
|
};
|
|
return BankAccount;
|
|
})();
|
|
\end{lstlisting}
|
|
|
|
Classes can define constructors, have super classes and be instantiated exactly like in Java. The only restriction compared to Java is that inner classes or anonymous classes are not allowed in JSweet (in the general case). For instance, the following code will raise an error.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class ContainerClass {
|
|
// error: inner classes are not allowed
|
|
public class InnerClass {
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Exceptions: inner classes annotated with \texttt{@ObjectType} or \texttt{@Erased} are allowed (see the part on Auxiliary Types).
|
|
|
|
\section{Testing the type of an object}
|
|
|
|
To test the type of a given object at runtime, one can use the \texttt{instanceof} Java operator. It is the advised and preferred way to test types at runtime. JSweet will transpile to a regular \texttt{instanceof} or to a \texttt{typeof} operator depending on the tested type (it will fallback in \texttt{typeof} for \texttt{number}, \texttt{string}, and \texttt{boolean} core types).
|
|
|
|
It is also possible to directly use the \texttt{typeof} operator from JSweet with the \texttt{jsweet.\-util.\-Globals.\-typeof} utility method. In general, it is not necessary to use it and the \texttt{instanceof} operator is preferred and more general.
|
|
|
|
Here are some examples of valid type tests:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.typeof;
|
|
import static jsweet.util.Globals.equalsStrict;
|
|
[...]
|
|
Number n1 = 2;
|
|
Object n2 = 2;
|
|
int n3 = 2;
|
|
Object s = "test";
|
|
MyClass c = new MyClass();
|
|
|
|
assert n1 instanceof Number; // transpiles to a typeof
|
|
assert n2 instanceof Number; // transpiles to a typeof
|
|
assert n2 instanceof Integer; // transpiles to a typeof
|
|
assert !(n2 instanceof String); // transpiles to a typeof
|
|
assert s instanceof String; // transpiles to a typeof
|
|
assert !(s instanceof Integer); // transpiles to a typeof
|
|
assert c instanceof MyClass;
|
|
assert typeof(n3) == "number";
|
|
assert equalsStrict(typeof(n3), "number");
|
|
\end{lstlisting}
|
|
|
|
Note: the \texttt{instanceof} operator is not allowed in interfaces, for reasons that will be explained in the following sections.
|
|
|
|
\section{Interfaces}
|
|
|
|
In JSweet, an interface (a.k.a. object type) can be seen as object signature, that is to say the accessible functions and properties of an object (without specifying any implementation). An interface is defined for typing only and has no runtime representation (no instances), however, they can be used to type objects.
|
|
|
|
JSweet interfaces can be defined as regular Java interfaces, but also as Java classes annotated with \texttt{@jsweet.lang.Interface}, so that is is possible to define properties as fields. Such classes impose many constraints, as shown in the following code.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
public class WrongConstructsInInterfaces {
|
|
native public void m1(); // OK
|
|
// error: field initializers are not allowed
|
|
public long l = 4;
|
|
// error: statics are not allowed
|
|
static String s1;
|
|
// error: private are not allowed
|
|
private String s2;
|
|
// error: constructors are not allowed
|
|
public WrongConstructsInInterfaces() {
|
|
l = 4;
|
|
}
|
|
// error: bodies are not allowed
|
|
public void m2() {
|
|
l = 4;
|
|
}
|
|
// error: statics are not allowed
|
|
native static void m3();
|
|
// error: initializers are not allowed
|
|
{
|
|
l = 4;
|
|
}
|
|
// error: static initializers are not allowed
|
|
static {
|
|
s1 = "";
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\subsection{Object typing}
|
|
|
|
In JSweet, typed objects can be constructed out of interfaces. If we take the following interface:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
public class Point {
|
|
public double x;
|
|
public double y;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\noindent
|
|
We can create an object typed after the interface. Note that the following code is not actually creating an instance of the \texttt{Point} interface, it is creating an object that conforms to the interface.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
Point p1 = new Point() {{ x=1; y=1; }};
|
|
\end{lstlisting}
|
|
|
|
\noindent
|
|
As a direct consequence, in JSweet it is not allowed to check an instance against an interface type.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
if (p1 instanceof Point) { ... } // compile error
|
|
\end{lstlisting}
|
|
|
|
\noindent
|
|
This may seems quite confusing for Java programmers, but you have to remember that, on contrary to Java where interfaces are available as special classes at runtime, in JSweet, interfaces have no reality at runtime. Think of generics, which are of the same kind in Java. As a consequence, the \texttt{instanceof} operator is applicable to classes, but not to interfaces at runtime (like it is not applicable on generics).
|
|
|
|
\subsection{Optional fields}
|
|
|
|
Interfaces can define \emph{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 \texttt{@jsweet.lang.Optional} annotations. For instance:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
public class Point {
|
|
public double x;
|
|
public double y;
|
|
@Optional
|
|
public double z = 0;
|
|
}
|
|
\end{lstlisting}
|
|
|
|
It is the JSweet compiler that will check that the fields are correctly initialized, when constructing an object.
|
|
|
|
\begin{lstlisting}[language=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; }};
|
|
\end{lstlisting}
|
|
|
|
\subsection{Special 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.
|
|
|
|
\begin{itemize}
|
|
\item \texttt{apply} is used to state that the object can be used as a function.
|
|
\item \texttt{\$new} is used to state that the object can be used as a constructor.
|
|
\end{itemize}
|
|
|
|
\section{Untyped objects (maps)}
|
|
|
|
In JavaScript, object can be seen as maps containing key-value pairs (key is often called \emph{index}, especially when it is a number). So, in JSweet, all objects define the special functions (defined on \texttt{jsweet.lang.Object}):
|
|
|
|
\begin{itemize}
|
|
\item \texttt{\$get(key)} accesses a value with the given key.
|
|
\item \texttt{\$set(key,value)} sets or replace a value for the given key.
|
|
\item \texttt{\$delete(key)} deletes the value for the given key.
|
|
\end{itemize}
|
|
|
|
\subsection{Reflective/untyped accesses}
|
|
|
|
The functions \texttt{\$get(key)}, \texttt{\$set(key,value)} and \texttt{\$delete(key)} can be seen as a simple reflective API to access object fields and state. Note also the static method \texttt{jsweet.lang.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 \texttt{o}.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
for(String key : jsweet.lang.Object.keys(o)) {
|
|
console.log("key=" + key + " value=" + o.$get(key));
|
|
});
|
|
\end{lstlisting}
|
|
|
|
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).
|
|
|
|
\subsection{Untyped objects initialization}
|
|
|
|
One can use the \texttt{\$set(key,value)} function to create new untyped object. For instance:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
Object point = new jsweet.lang.Object() {{ $set("x", 1); $set("y", 1); }};
|
|
\end{lstlisting}
|
|
|
|
As a shortcut, one can use the \texttt{jsweet.util.Global.\$map} function:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Global.$map;
|
|
[...]
|
|
Object point = $map("x", 1, "y", 1);
|
|
\end{lstlisting}
|
|
|
|
\subsection{Indexed objects}
|
|
|
|
The type of keys and values can be overloaded for every object. For example, the \texttt{Array<T>} class, will define keys as numbers and values as objects conforming to type \texttt{T}.
|
|
|
|
In the case of objects indexed with number keys, it is allowed to implement the \texttt{java.lang.Iterable} interface so that it is possible to use they in \emph{foreach} loops. For instance, the \texttt{NodeList} type (from the DOM) defines an indexed function:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
class NodeList implements java.lang.Iterable {
|
|
public double length;
|
|
public Node item(double index);
|
|
public Node $get(double index);
|
|
}
|
|
\end{lstlisting}
|
|
|
|
In JSweet, you can access the node list elements with the \texttt{\$get} function, and you can also iterate with the \emph{foreach} syntax. The following code generates fully valid JavaScript code.
|
|
|
|
\begin{lstlisting}[language=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;
|
|
[...]
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\section{Enums}
|
|
|
|
JSweet allows the definition of enums similarly to Java, but with some restrictions. The following code declares an enum with tree possible values (\texttt{A}, \texttt{B}, and \texttt{C}).
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
enum MyEnum {
|
|
A, B, C
|
|
}
|
|
\end{lstlisting}
|
|
|
|
The following statements are valid statements in JSweet.
|
|
|
|
\begin{lstlisting}[language=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;
|
|
\end{lstlisting}
|
|
|
|
On the other hand, unlike Java enums, other members than constants are not allowed, raising JSweet transpilation errors, as shown in the following code.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public enum WrongConstructsInEnums {
|
|
|
|
A, B, C;
|
|
|
|
// error: fields are not allowed
|
|
public long l = 4;
|
|
// error: constructors are not allowed
|
|
private WrongConstructsInEnums() {
|
|
l = 4;
|
|
}
|
|
// error: methods are not allowed
|
|
public void m2() {
|
|
l = 4;
|
|
}
|
|
// error: initializers are not allowed
|
|
{
|
|
l = 4;
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\section{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 \texttt{Globals} classes and \texttt{globals} packages. These have two purposes:
|
|
|
|
\begin{itemize}
|
|
\item Generate code that has global variables and functions (this is discouraged in Java)
|
|
\item Bind to existing JavaScript code that defines global variables and functions (as many JavaScript frameworks do)
|
|
\end{itemize}
|
|
|
|
In Globals classes, only static fields (global variables) and static methods (global functions) are allowed. Here are the main constraints applying to Globals classes:
|
|
|
|
\begin{itemize}
|
|
\item no non-static members
|
|
\item no super class
|
|
\item cannot be extended
|
|
\item cannot be used as types like regular classes
|
|
\item no public constructor (empty private constructor is OK)
|
|
\item cannot use \$get, \$set and \$delete within the methods
|
|
\end{itemize}
|
|
|
|
For instance, the following code snippets will raise transpilation errors.
|
|
|
|
\begin{lstlisting}[language=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");
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// error: Globals classes cannot be used as types
|
|
Globals myVariable = null;
|
|
\end{lstlisting}
|
|
|
|
One must remember that \texttt{Globals} classes and \texttt{global} packages are erased at runtime so that their members will be directly accessible. For instance \texttt{mypackage.Globals.m()} in a JSweet program corresponds to the \texttt{mypackage.m()} function in the generated code and in the JavaScript VM at runtime. Also, \texttt{mypackage.globals.Globals.m()} corresponds to \emph{m()}.
|
|
|
|
In order to erase packages in the generated code, programmers can also use the \texttt{@Root} annotation, which will be explained in Section \ref{packaging}.
|
|
|
|
\section{Optional parameters}
|
|
\label{optional-parameters}
|
|
|
|
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 supports overloading as long as it is for implementing optional parameters -- a very commonly used idiom. Here are some examples of valid and invalid overloading in JSweet:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
String m(String s, double n) { return s + n; }
|
|
// valid overloading (JSweet transpiles to optional parameter)
|
|
String m(String s) { return m(s, 0); }
|
|
// invalid overloading (JSweet error)
|
|
String m(String s) { return s; }
|
|
\end{lstlisting}
|
|
|
|
\chapter{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 (\url{http://www.jsweet.org/candies-releases/} and \url{http://www.jsweet.org/candies-snapshots/}), which are automatically generated from TypeScript's DefinitelyTyped. When the candy does not exist, or does not entirely cover what is needed, one can use the \texttt{@jsweet.lang.Ambient} annotation, which will make available to the programmers a class definition or an interface.
|
|
|
|
\section{Ambient declarations}
|
|
|
|
The following example shows the backbone store class made accessible to the JSweet programmer with a simple ambient declaration. This class is only for typing and will be erased during the JavaScript generation.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Ambient
|
|
class Store {
|
|
public Store(String dbName) {}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Note that ambient classes constructors must have an empty body. Also, ambient classes methods must be \texttt{abstract} or \texttt{native}. For instance:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Ambient
|
|
class MyExternalJavaScriptClass {
|
|
public native myExternalJavaScriptMethod();
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\section{Definitions}
|
|
|
|
By convention, putting the classes in a \texttt{def.libname} package defines a set of definitions for the \texttt{libname} external JavaScript library called \texttt{libname}. Definitions are by default all ambient declarations and do not need to be annotated with \texttt{@jsweet.lang.Ambient} annotations since they are implicit in \texttt{def.*} packages and sub-packages. Note that this mechanism is similar to the TypeScript \texttt{d.ts} definition files.
|
|
|
|
Candies (bridges to external JavaScript libraries) use definitions. For instance, the jQuery candy defines all the jQuery API in the \texttt{def.jquery} package.
|
|
|
|
\section{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 \texttt{JQuery} class. For example the jQuery timer plugin adds a \texttt{timer} field to the \texttt{JQuery} class. As a consequence, the \texttt{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 Java cannot dynamically enhance a given class.
|
|
|
|
\subsection{Untyped accesses}
|
|
|
|
Programmers can access the added element with \texttt{\$get} accessors and/or with brute-force casting.
|
|
|
|
Here is an example using \texttt{\$get} for the timer plugin case:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
((Timer)$("#myId").$get("timer")).pause();
|
|
\end{lstlisting}
|
|
|
|
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 \texttt{def.jqueryui.JQuery} instead of \texttt{def.jquery.JQuery} in order to access the \texttt{menu()} function, added by the UI plugin):
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import def.jqueryui.JQuery;
|
|
[...]
|
|
Object obj = $("#myMenu");
|
|
JQuery jq = (JQuery) obj;
|
|
jq.menu();
|
|
\end{lstlisting}
|
|
|
|
However, these solutions are not satisfying because clearly unsafe in terms of typing.
|
|
|
|
\subsection{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 \texttt{@Mixin} annotation. Here is the excerpt of the \texttt{def.jqueryui.JQuery} mixin:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
package def.jqueryui;
|
|
import jsweet.dom.MouseEvent;
|
|
import jsweet.lang.Function;
|
|
import jsweet.lang.Date;
|
|
import jsweet.lang.Array;
|
|
import jsweet.lang.RegExp;
|
|
import jsweet.dom.Element;
|
|
import def.jquery.JQueryEventObject;
|
|
@jsweet.lang.Interface
|
|
@jsweet.lang.Mixin(target=def.jquery.JQuery.class)
|
|
public abstract class JQuery extends jsweet.lang.Object {
|
|
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();
|
|
...
|
|
\end{lstlisting}
|
|
|
|
One can notice the \texttt{@jsweet.lang.Mixin(target=def.jquery.JQuery.class)} that states that this mixin will be merged to the \texttt{def.jquery.JQuery} so that users will be able to use all the UI plugin members directly and in a well-typed way.
|
|
|
|
\subsection{Implementation and how to use}
|
|
|
|
JSweet merges mixins using a bytecode manipulation tool called Javassist. It takes the mixin classes bytecode, copies all the members to the target classes, and writes the resulting merged classes bytecode to the \texttt{.jsweet/candies/processed} directory. As a consequence, in order to benefit the JSweet mixin mechanism, one must add the \texttt{.jsweet/candies/processed} directory to the compilation classpath. This directory should be placed before all the other classpath elements so that the mixined results override the original classes (for example the \texttt{def.jquery.JQuery} should be overridden and, as a consequence, \texttt{.jsweet/candies/processed/def/jquery/JQuery.class} must be found first in the classpath).
|
|
|
|
The JSweet transpiler automatically adds the \texttt{.jsweet/candies/processed} directory to the compilation classpath so that you do not have to do anything special when using JSweet with Maven. However, when using mixins within an IDE, you must force your project classpath to include this directory in order to ensure compilation of mixin-ed elements. When using the JSweet Eclipse plugin for instance, this is done automatically and transparently for the user. But when not using any plugins, this configuration must be done manually.
|
|
|
|
For example, with Eclipse (similar configuration can be made with other IDEs):
|
|
|
|
\begin{enumerate}
|
|
\item Right-click on the project \textgreater Build path \textgreater Configure build path... \textgreater Libraries (tab) \textgreater Add class folder (button). Then choose the \texttt{.jsweet/candies/processed} directory.
|
|
\item In the "order and export" tab of the build path dialog, make sure that the \texttt{.jsweet/candies/processed} directory appears at the top of the list (or at least before the Maven dependencies).
|
|
\end{enumerate}
|
|
|
|
NOTE: you do not have to configure anything if you are not using mixins or if you are using the Eclipse plugin.
|
|
|
|
Once this configuration is done, you can safely use mixins. For instance, if using the jQuery candy along with jQuery UI, you will be able to write statements such as:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
$("#myMenu").menu();
|
|
\end{lstlisting}
|
|
|
|
This is neat compared to the untyped access solution because it is checked by the Java compiler (and you will also have completion on mixin-ed elements).
|
|
|
|
\chapter{Auxiliary types}
|
|
|
|
JSweet uses most Java typing features (including functional types) but also extends the Java type system with so-called \emph{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 \emph{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).
|
|
|
|
\section{Functional types}
|
|
|
|
For functional types, JSweet reuses the \texttt{java.\-Runnable} and \texttt{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 \texttt{jsweet.\-util.\-function}, since it is a common case in JavaScript APIs.
|
|
|
|
Here is an example using the \texttt{Function} generic functional type:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import java.util.function.Function;
|
|
|
|
public class C {
|
|
|
|
String test(Function<String, String> f) {
|
|
f.apply("a");
|
|
}
|
|
|
|
public static void main(String[] args) {
|
|
String s = new C().test(p -> p);
|
|
assert s == "a";
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
We encourage programmers to use the generic functional interfaces defined in the \texttt{jsweet.\-util.\-function} and \texttt{java.\-util.\-function} (besides \texttt{java.\-lang.\-Runnable}). When requiring functions with more parameters, programmers can define their own generic functional types in \texttt{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:
|
|
|
|
\begin{lstlisting}[language=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
|
|
});
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Important warning: it is to be noted here that, on contrary to Java, the use of the \texttt{@FunctionInterface} annotation is mandatory.
|
|
|
|
Note also the possible use of the \texttt{apply} function, which is by convention always a functional definition on the target object (unless if \texttt{apply} is annotated with the \texttt{@Name} annotation). Defining/invoking \texttt{apply} can done on any class/object (because in JavaScript any object can become a functional object).
|
|
|
|
\section{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 \texttt{m} takes a parameter, which is an object containing an \texttt{index} field:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// TypeScript:
|
|
public class C {
|
|
public m(param : { index : number }) { ... }
|
|
}
|
|
\end{lstlisting}
|
|
|
|
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:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// TypeScript:
|
|
var c : C = ...;
|
|
c.m({ index : 2 });
|
|
\end{lstlisting}
|
|
|
|
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 \texttt{@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 \texttt{@ObjectType} annotated classes can be inner classes so that they are used locally.
|
|
|
|
Here is the JSweet version of the previous TypeScript program.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class C {
|
|
@ObjectType
|
|
public static class Indexed {
|
|
int index;
|
|
}
|
|
public void m(Indexed param) { ... }
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Using an object type is similar to using an interface:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
C c = ...;
|
|
c.m(new Indexed() {{ index = 2; }});
|
|
\end{lstlisting}
|
|
|
|
When object types are shared objects and represent a typing entity that can be used in several contexts, it is recommended to use the \texttt{@Interface} annotation instead of \texttt{@ObjectType}. Here is the interface-based version.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
public class Indexed {
|
|
int index;
|
|
}
|
|
|
|
public class C {
|
|
public m(Indexed param) { ... }
|
|
}
|
|
|
|
C c = ...;
|
|
c.m(new Indexed {{ index = 2; }});
|
|
\end{lstlisting}
|
|
|
|
\section{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:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// TypeScript:
|
|
interface Document {
|
|
[...]
|
|
getElementsByTagName(tagname: "a"): NodeListOf<HTMLAnchorElement>;
|
|
getElementsByTagName(tagname: "b"): NodeListOf<HTMLPhraseElement>;
|
|
getElementsByTagName(tagname: "body"): NodeListOf<HTMLBodyElement>;
|
|
getElementsByTagName(tagname: "button"): NodeListOf<HTMLButtonElement>;
|
|
[...]
|
|
}
|
|
\end{lstlisting}
|
|
|
|
In this code, the \texttt{getElementsByTagName} functions are all overloads that depend on the strings passed to the \texttt{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 \texttt{@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 \texttt{jsweet.\-util.\-String\-Types} class, so that it is easy for the programmers to find them. For instance, if a \texttt{$"$body$"$} string type needs to be defined, a Java interface called \texttt{body} and a static final field called \texttt{body} are defined in a \texttt{jsweet.\-util.\-String\-Types}.
|
|
|
|
Note that each candy may have its own string types defined in the \texttt{jsweet.\-util.\-String\-Types} 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 \texttt{jsweet.\-util.\-String\-Types} utility class. As a result, the JSweet DOM API will look like:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Interface
|
|
public class Document {
|
|
[...]
|
|
public native NodeListOf<HTMLAnchorElement> getElementsByTagName(a tagname);
|
|
public native NodeListOf<HTMLPhraseElement> getElementsByTagName(b tagname);
|
|
public native NodeListOf<HTMLBodyElement> getElementsByTagName(body tagname);
|
|
public native NodeListOf<HTMLButtonElement> getElementsByTagName(button tagname);
|
|
[...]
|
|
}
|
|
\end{lstlisting}
|
|
|
|
In this API, \texttt{a}, \texttt{b}, \texttt{body} and \texttt{button} are interfaces defined in the \texttt{jsweet.\-util.\-String\-Types} class. When using one the method of \texttt{Document}, the programmer just need to use the corresponding type instance (of the same name). For instance:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
Document doc = ...;
|
|
NodeListOf<HTMLAnchorElement> elts = doc.getElementsByTagName(StringTypes.a);
|
|
\end{lstlisting}
|
|
|
|
Note: if the string value is not a valid Java identifier (for instance \texttt{$"$2d$"$} or \texttt{$"$string-with-dashes$"$}), it is then translated to a valid one and annotated with \texttt{@Name($"$originalName$"$)}, so that the JSweet transpiler knows what actual string value must be used in the generated code. For instance, by default, \texttt{$"$2d$"$} and \texttt{$"$string-with-dashes$"$} will correspond to the interfaces \texttt{StringTypes.\_2d} and \texttt{StringTypes.string\_with\_dashes} with \texttt{@Name} annotations.
|
|
|
|
Programmers can define string types for their own needs, as shown below:
|
|
|
|
\begin{lstlisting}[language=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);
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Note the use of the \texttt{@Erased} annotation, which allows the declaration of the \texttt{abc} inner interface. This interface is used to type the string type field \texttt{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.
|
|
|
|
\section{Tuple types}
|
|
|
|
Tuple types represent JavaScript arrays with individually tracked element types. For tuple types, JSweet defines parameterized auxiliary classes \texttt{TupleN<T0, ... TN-1>}, which define \texttt{\$0}, \texttt{\$1}, ... \texttt{\$N-1} public fields to simulate typed array accessed (field \texttt{\$i} is typed with \texttt{Ti}).
|
|
|
|
For instance, given the following tuple of size 2:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
Tuple2<String, Integer> tuple = new Tuple2<String, Integer>("test", 10);
|
|
\end{lstlisting}
|
|
|
|
We can expect the following (well-typed) behavior:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
assert tuple.$0 == "test";
|
|
assert tuple.$1 == 10;
|
|
tuple.$0 = "ok";
|
|
tuple.$1--;
|
|
assert tuple.$0 == "ok";
|
|
assert tuple.$1 == 9;
|
|
\end{lstlisting}
|
|
|
|
Tuple types are all defined (and must be defined) in the \texttt{jsweet.\-util.\-tuple} package. By default classes \texttt{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 \texttt{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.
|
|
|
|
\section{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 \emph{method overloading} mechanism available in Java. For instance, the following \texttt{m} method accept a parameter \texttt{p}, which can be either a \texttt{String} or a \texttt{Integer}.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public void m(String p) {...}
|
|
public void m(Integer p) {...}
|
|
\end{lstlisting}
|
|
|
|
|
|
In the previous case, the use of explicit union types is not required. For more general cases, JSweet defines an auxiliary interface \texttt{Union<T1, T2>} (and \texttt{UnionN<T1, ... TN>}) in the \texttt{jsweet.\-util.\-union} package. By using this auxiliary type and a \texttt{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 \texttt{jsweet\-.util\-.Globals\-.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.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.union;
|
|
import jsweet.util.union.Union;
|
|
[...]
|
|
Union<String, Number> 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
|
|
\end{lstlisting}
|
|
|
|
The \texttt{union} helper can also be used the other way, to switch from a regular type back to a union type, when expected.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.util.Globals.union;
|
|
import jsweet.util.union.Union3;
|
|
[...]
|
|
public void m(Union3<String, Number, Date>> u) { ... }
|
|
[...]
|
|
// u can be a String, a Number or a Date
|
|
m(union("a string"));
|
|
// but nothing else
|
|
m(union(new RegExp(".*"))); // compile error
|
|
\end{lstlisting}
|
|
|
|
Note: the use of Java function overloading is preferred over union types when typing function parameters. For example:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
// with union types (discouraged)
|
|
native public void m(Union3<String, Number, Date>> u);
|
|
// with overloading (preferred way)
|
|
native public void m(String s);
|
|
native public void m(Number n);
|
|
native public void m(Date d);
|
|
\end{lstlisting}
|
|
|
|
\section{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, \texttt{A \& B} corresponds to a type that defines both \texttt{A} and \texttt{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, \texttt{A \& B} is thus defined as \texttt{Union<A, B>}, which means that the programmer can access both \texttt{A} and \texttt{B} members by using the \texttt{jsweet\-.util\-.Globals\-.union} helper method. It is of course less convenient than the TypeScript version, but it is still type safe.
|
|
|
|
\chapter{Semantics}
|
|
\label{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.
|
|
|
|
\section{Main methods}
|
|
|
|
Main methods are the program execution entry points and will be invoked globally when a class containing a \texttt{main} method is evaluated. For instance:
|
|
|
|
\begin{lstlisting}[language=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;
|
|
\end{lstlisting}
|
|
|
|
Main methods do not behave exactly like in Java and depend on the way the program is packaged and deployed.
|
|
|
|
\begin{itemize}
|
|
\item \textbf{Regular packaging (no modules)}. With regular packaging, one Java source file corresponds to one generated JavaScript file. In that case, when loading a file in the browser, all the main methods will be invoked, right after the file is evaluated.
|
|
\item \textbf{Module packaging}. With module packaging (module option), one Java package corresponds to one module. With modules, it is mandatory to have only one main method in the program, which will be the global entry point from which the module dependency graph will be calculated. The main module will use directly or transitively all the other modules.
|
|
\end{itemize}
|
|
|
|
Because of modules, it is good practice to have only one main method in an application.
|
|
|
|
\section{Initializers}
|
|
|
|
Initializers behave like in Java.
|
|
|
|
\noindent
|
|
For example:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class C1 {
|
|
int n;
|
|
{
|
|
n = 4;
|
|
}
|
|
}
|
|
assert new C1().n == 4;
|
|
\end{lstlisting}
|
|
|
|
\noindent
|
|
And similarly with static initializers:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class C2 {
|
|
static int n;
|
|
static {
|
|
n = 4;
|
|
}
|
|
}
|
|
assert C2.n == 4;
|
|
\end{lstlisting}
|
|
|
|
|
|
\section{Name clashes}
|
|
|
|
On contrary to Java, methods and fields of the same name are not allowed within the same class or within classes having a subclassing link. The reason behind this behavior is that in JavaScript, object variables and functions are stored within the same object map, which basically means that you cannot have the same key for several object members (this also explains that method overloading in the Java sense is not possible in JavaScript).
|
|
|
|
In order to avoid programming mistakes due to this JavaScript behavior, which is not necessarily known by Java programmers, JSweet adds a semantics check to avoid duplicate names in classes (this also takes into account members defined in parent classes). As an example:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
public class NameClashes {
|
|
|
|
// error: field name clashes with existing method name
|
|
public String a;
|
|
|
|
// error: method name clashes with existing field name
|
|
public void a() {
|
|
return a;
|
|
}
|
|
|
|
}
|
|
\end{lstlisting}
|
|
|
|
In general, it also not possible to have two methods with the same name but with different parameters (so-called overloads). An exception to this behavior is the use of method overloading for defining optional parameters. JSweet allows this idiom under the condition that it corresponds to the following template:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
String m(String s, double n) { return s + n; }
|
|
// valid overloading (JSweet transpiles to optional parameter)
|
|
String m(String s) { return m(s, 0); }
|
|
\end{lstlisting}
|
|
|
|
In that case, JSweet will generate JavaScript code with only one method having default values for the optional parameters, so that the behavior of the generated program corresponds to the original one. In this case:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
function m(s, n = 0) { return s + n; }
|
|
\end{lstlisting}
|
|
|
|
|
|
If the programmer tries to use overloading differently, for example by defining two different implementations for the same method name, JSweet will raise a compile error.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
String m(String s, double n) { return s + n; }
|
|
// invalid overloading (JSweet error)
|
|
String m(String s) { return s; }
|
|
\end{lstlisting}
|
|
|
|
Local variables can also clash with the use of a global method. For instance, using the \texttt{alert} global method from the DOM (\texttt{jsweet.dom.Globals.alert}) requires that no local variable hides it. For instance:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
import static jsweet.dom.Globals.alert;
|
|
|
|
[...]
|
|
|
|
public void m1(boolean alert) {
|
|
// JSweet compile error: name clash between parameter and method call
|
|
alert("test");
|
|
}
|
|
|
|
public void m2() {
|
|
// JSweet compile error: name clash between local variable and method call
|
|
String alert = "test";
|
|
alert(alert);
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Note that this problem also happens when using fully qualified names when calling the global methods (that because the qualification gets erased in TypeScript/JavaScript). In any case, JSweet will report sound errors when such problems happen so that programmers can adjust local variable names to avoid clashes with globals.
|
|
|
|
\section{Variable scoping in lambda expressions}
|
|
|
|
JavaScript variable scoping is known to pose some problems to the programmers, because it is possible to change the reference to a variable from outside of a lambda that would use this variable. As a consequence, a JavaScript programmer cannot rely on a variable declared outside of a lambda scope, because when the lambda is executed, the variable may have been modified somewhere else in the program. For instance, the following program shows a typical case:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
NodeList nodes = document.querySelectorAll(".control");
|
|
for (int i = 0; i < nodes.length; i++) {
|
|
HTMLElement element = (HTMLElement) nodes.$get(i); // final
|
|
element.addEventListener("keyup", (evt) -> {
|
|
// this element variable will not change here
|
|
element.classList.add("hit");
|
|
});
|
|
}
|
|
\end{lstlisting}
|
|
|
|
In JavaScript (note that EcmaScript 6 fixes this issue), such a program would fail its purpose because the \texttt{element} variable used in the event listener is modified by the for loop and does not hold the expected value. In JSweet, such problems are dealt with similarly to final Java variables. In our example, the \texttt{element} variable is re-scoped in the lambda expression so that the enclosing loop does not change its value and so that the program behaves like in Java (as expected by most programmers).
|
|
|
|
\section{Scope of \emph{this}}
|
|
|
|
On contrary to JavaScript and similarly to Java, using a method as a lambda will prevent loosing the reference to \texttt{this}. For instance, in the \texttt{action} method of the following program, \texttt{this} holds the right value, even when \texttt{action} was called as a lambda in the \texttt{main} method. Although this seem logical to Java programmers, it is not a given that the JavaScript semantics ensures this behavior.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
package example;
|
|
import static jsweet.dom.Globals.console;
|
|
|
|
public class Example {
|
|
private int i = 8;
|
|
public Runnable getAction() {
|
|
return this::action;
|
|
}
|
|
public void action() {
|
|
console.log(this.i); // this.i is 8
|
|
}
|
|
public static void main(String[] args) {
|
|
Example instance = new Example();
|
|
instance.getAction().run();
|
|
}
|
|
}
|
|
\end{lstlisting}
|
|
|
|
\chapter{Packaging}
|
|
\label{packaging}
|
|
|
|
Packaging is one of the complex point of JavaScript, especially when coming from Java. Complexity with JavaScript packaging boils down to the fact that JavaScript did not define any packaging natively. As a consequence, many \emph{de facto} solutions and quidelines came up along the years, making the understanding of packaging uneasy for regular Java programmers. In spite EcmaScript UMS is supposed to bring a standard for modules in Java, other \emph{de facto} standards remain and the notion of a namespace/package is still not handled by JavaScript, making the notion of a module and a namespace confusing for JavaScript and TypeScript developers themselves.
|
|
|
|
\section{Packages and modules}
|
|
|
|
Packages and modules are two similar concepts but for different contexts.
|
|
|
|
Java packages must be understood as compile-time \emph{namespaces}. They allow a compile-time structuration of the programs through name paths, with implicit or explicit visibility rules. Packages have usually not much impact on how the program is actually bundled and deployed.
|
|
|
|
Modules must be understood as deployment and runtime \emph{bundles}. The closest concept to a module in the Java world would probably be an OSGi bundle. A module defines imported and exported elements so that they create a strong runtime structure that can be used for deploying software components independently and thus avoiding name clashes. For instance, with modules, two different libraries may define a \texttt{util.List} class and be actually running and used on the same VM with no naming issues (as long as the libraries are bundled in different modules).
|
|
|
|
JSweet uses the Java package concept for namespaces. Modules are a deployment concept and should be created with some deployment scripts involving third party tools. However, for easy deployment, JSweet defines a \texttt{module} option that automatically creates a default module organization following the simple rule: one package = one module. With this rule, it is actually possible to run a JSweet program on Node.js without requiring extra work from the programmer. Also, using both the \texttt{bundle} and \texttt{module} options of JSweet creates a bundle file containing the application modules, and which can be deployed on a browser with no extra packaging.
|
|
|
|
\section{Root packages}
|
|
|
|
Root packages are a way to tune the generated code so that JSweet packages are erased in the generated code and thus at runtime. To set a root package, just define a package-info.java file and use the \emph{@Root} annotation on the package, as follows:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
@Root
|
|
package a.b.c;
|
|
\end{lstlisting}
|
|
|
|
The above declaration means that the \texttt{c} package is a root package, i.e. it will be erased in the generated code, as well as all its parent packages. Thus, if \texttt{c} contains a package \texttt{d}, and a class \texttt{C}, these will be top-level objects at runtime. In other words, \texttt{a.b.c.d} becomes \texttt{d}, and \texttt{a.b.c.C} becomes \texttt{C}.
|
|
|
|
Note that since that packaged placed before the \emph{@Root} package are erased, there cannot be any type defined before a \emph{@Root} package. In the previous example, the \emph{a} and \emph{b} packages are necessarily empty packages.
|
|
|
|
\subsection{Behavior when not using modules (default)}
|
|
|
|
By default, root packages do not change the folder hierarchy of the generated files. For instance, the \texttt{a.b.c.C} class will still be generated in the \texttt{<jsout>/a/b/c/C.js} file (relatively to the \texttt{<jsout>} output directory). However, switching on the \texttt{noRootDirectories} option will remove the root directories so that the \texttt{a.b.c.C} class gets generated to the \texttt{<jsout>/C.js} file.
|
|
|
|
When not using modules (default), it is possible to have several \emph{@Root} packages (but a \emph{@Root} package can never contain another \emph{@Root} package).
|
|
|
|
\subsection{Behavior when using modules}
|
|
|
|
When using modules (see the \emph{module} option), only one \emph{@Root} package is allowed, and when having one \emph{@Root} package, no other package or type can be outside of the scope of that \emph{@Root} package. The generated folder/file hierarchy then starts at the root package so that all the folders before it are actually erased.
|
|
|
|
\section{External modules}
|
|
|
|
When compiling JSweet programs with the \texttt{module} options, all external libraries and components must be required as external modules. JSweet can automatically require modules, simply by using the \texttt{@Module(name)} annotation. In JSweet, importing or using a class or a member annotated with \texttt{@Module(name)} will automatically require the corresponding module at runtime. Please not that it is true only when the code is generated with the \texttt{module} option. If the \texttt{module} option is off, the \texttt{@Module} annotations are ignored.
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
package def.jquery;
|
|
public final class Globals extends jsweet.lang.Object {
|
|
...
|
|
@jsweet.lang.Module("jquery")
|
|
native public static def.jquery.JQuery $(java.lang.String selector);
|
|
...
|
|
}
|
|
\end{lstlisting}
|
|
|
|
The above code shows an excerpt of the JSweet jQuery API. As we can notice, the \$ function is annotated with \texttt{@Module($"$jquery$"$)}. As a consequence, any call to this function will trigger the require of the \texttt{jquery} module.
|
|
|
|
Note: the notion of manual require of a module may be available in future releases. However, automatic require is sufficient for most programmers and hides the complexity of having to require modules explicitly. It also brings the advantage of having the same code whether modules are used or not.
|
|
|
|
\section{Packaging a JSweet jar (candy)}
|
|
|
|
When creating a program (especially a library or a component) with JSweet, one may want to package it in a JSweet jar (a.k.a. a candy) and deploy it on a Maven repository, so that it can be used by other JSweet programs.
|
|
|
|
Candies are regular Jars that can be generated with the Maven \texttt{package} goal. To be a valid candy and recognized as such by the JSweet transpiler, your jar file must contain two additional resources (to be placed in the resources directory of your Maven project so that they end up being packaged in your jar by Maven).
|
|
|
|
\begin{enumerate}
|
|
\item A \texttt{META-INF/candy-metadata.json} file that contains the expected target version of the transpiler (to be adapted to your target transpiler version).
|
|
\item The program's declarations in \texttt{d.ts} files, to be placed in the \texttt{src/typings} directory of the jar.
|
|
\end{enumerate}
|
|
|
|
Here is an example of the \texttt{META-INF/candy-metadata.json} file:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
{
|
|
"transpilerVersion": "1.0.0"
|
|
}
|
|
\end{lstlisting}
|
|
|
|
Typically, \texttt{d.ts} files shall be generated by the JSweet transpiler using the following options:
|
|
|
|
\begin{itemize}
|
|
\item \texttt{declaration}: turns on the generation of the \texttt{d.ts} files.
|
|
\item \texttt{dtsout}: tells where to put the generated \texttt{d.ts} files (for packaging, place them in \texttt{RESOURCES/src/typings}, where \texttt{RESOURCES} is your Maven project resources directory).
|
|
\end{itemize}
|
|
|
|
Note: this section only described how to package JSweet jars for compilation. For execution, the generated JavaScript must be accessible to the using project too. A way is to package the JavaScript following the WebJar conventions: \url{http://www.webjars.org/}.
|
|
|
|
\chapter*{Appendix 1: JSweet transpiler options}
|
|
|
|
\begin{verbatim}
|
|
[-h|--help]
|
|
|
|
[-v|--verbose]
|
|
Turn on all levels of logging.
|
|
|
|
[--encoding <encoding>]
|
|
Force the Java compiler to use a specific encoding (UTF-8, UTF-16, ...).
|
|
(default: UTF-8)
|
|
|
|
[--jdkHome <jdkHome>]
|
|
Set the JDK home directory to be used to find the Java compiler. If not
|
|
set, the transpiler will try to use the JAVA_HOME environment variable.
|
|
Note that the expected JDK version is greater or equals to version 8.
|
|
|
|
(-i|--input) <input>
|
|
An input dir containing Java files to be transpiled.
|
|
|
|
[--noRootDirectories]
|
|
Skip the root directories (i.e. packages annotated with
|
|
@jsweet.lang.Root) so that the generated file hierarchy starts at the
|
|
root directories rather than including the entire directory structure.
|
|
|
|
[--tsout <tsout>]
|
|
Specify where to place generated TypeScript files. (default: .ts)
|
|
|
|
[(-o|--jsout) <jsout>]
|
|
Specify where to place generated JavaScript files (ignored if jsFile is
|
|
specified). (default: js)
|
|
|
|
[--declaration]
|
|
Tells the transpiler to generate the d.ts files along with the js files,
|
|
so that other programs can use them to compile.
|
|
|
|
[--dtsout <dtsout>]
|
|
Specify where to place generated d.ts files when the declaration option
|
|
is set (by default, d.ts files are generated in the JavaScript output
|
|
directory - next to the corresponding js files).
|
|
|
|
[--classpath <classpath>]
|
|
The JSweet transpilation classpath (candy jars). This classpath should
|
|
at least contain the core candy.
|
|
|
|
[(-m|--module) <module>]
|
|
The module kind (none, commonjs, amd, system or umd). (default: none)
|
|
|
|
[-b|--bundle]
|
|
Bundle up the generated files and used modules to bundle files, which
|
|
can be used in the browser. Bundles contain all the dependencies and are
|
|
thus standalone. There is one bundle generated per entry (a Java 'main'
|
|
method) in the program. By default, bundles are generated in the entry
|
|
directory, but the output directory can be set by using the
|
|
--bundlesDirectory option. NOTE: bundles will be generated only when
|
|
choosing the commonjs module kind.
|
|
|
|
[--bundlesDirectory <bundlesDirectory>]
|
|
Generate all the bundles (see option --bundle) within the given
|
|
directory.
|
|
|
|
[--sourceMap]
|
|
Set the transpiler to generate source map files for the Java files, so
|
|
that it is possible to debug them in the browser. This feature is not
|
|
available yet when using the --module option. Currently, when this
|
|
option is on, the generated TypeScript file is not pretty printed in a
|
|
programmer-friendly way (disable it in order to generate readable
|
|
TypeScript code).
|
|
|
|
[--ignoreAssertions]
|
|
Set the transpiler to ignore 'assert' statements, i.e. no code is
|
|
generated for assertions.
|
|
\end{verbatim}
|
|
|
|
\chapter*{Appendix 2: JSweet strict mode}
|
|
|
|
For programmers developing JavaScript-only application (no Java at all), JSweet proposes an optional \emph{strict} mode. In strict mode, Java APIs are not accessible at all anymore and are substituted by the JavaScript APIs. This is possible through a technique invented by Peter Kriens consisting in replacing the core Java classes at compile-time. To enable strict mode, just add to your dependencies (in first position) the \texttt{jsweet-core-strict} artifact (group \texttt{org.jsweet}).
|
|
|
|
The advantage of using the strict mode is that Java core objects become JavaScript object directly and expose the JavaScript API, so that programmers do not need to switch from Java to JSweet API anymore (through the \texttt{jsweet.util.Globals} utilities). This means for instance that the \texttt{\$get}, \texttt{\$set} and \texttt{\$delete} functions are directly accessible on all objects.
|
|
|
|
Here is an example with a native Java string:
|
|
|
|
\begin{lstlisting}[language=Java]
|
|
String str = "This is a test string";
|
|
// compile error in non strict mode: substr is not a Java method
|
|
// but OK with strict mode!
|
|
str.substr(1);
|
|
\end{lstlisting}
|
|
|
|
The main benefit in using strict mode is when manipulating objects and strings. However, it has limitations. For instance, Java arrays still need to be cast to JSweet arrays to access the JavaScript API. Moreover, programmers have to be aware that using strict mode within an IDE will prevent from having JSweet and Java code mixed within the same project (they may be in different projects though). Here is a list of tips about using strict mode.
|
|
|
|
\begin{itemize}
|
|
\item You can use strict mode on full JavaScript projects, for instance pure client-side applications or full-stack applications with a Node.js server.
|
|
\item You can use strict mode on small pure JavaScript components with very few interactions with the outside world (almost no data exchanged).
|
|
\item Avoid using strict mode when wanting to share some data between JavaScript and some Java tiers (typically trough DTOs).
|
|
\item Avoid using strict mode when you feel that one day, your code may collaborate closer with a Java application (typically a Java server).
|
|
\end{itemize}
|
|
|
|
\end{document}
|