Skip to content
Next Next commit
Update documentation to reflect (anticipated) v0.5.0
  • Loading branch information
gzm0 committed Jun 13, 2014
commit a9d80fc1c7ef1fa3220a513791f7d46a48f6b60a
76 changes: 44 additions & 32 deletions doc/calling-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,30 +25,37 @@ types.
The core type hierarchy is as follows:

js.Any
+- js.Number
+- js.Boolean
+- js.String
+- js.Undefined
+- js.Object
+- js.Date
+- js.RegExp
+- js.Array[A]
+- js.Function
+- js.Function0[+R]
+- js.Function1[-T1, +R]
+- ...
+- js.Function22[-T1, ..., -T22, +R]
+- js.ThisFunction
+- js.ThisFunction0[-T0, +R]
+- js.ThisFunction1[-T0, -T1, +R]
+- ...
+- js.ThisFunction21[-T0, ..., -T21, +R]

A value of any of these types is encoded as is in JavaScript, without boxing.
| +- js.Date
| +- js.RegExp
| +- js.Array[A]
| +- js.Dictionary[A]
| +- js.Function
| +- js.Function0[+R]
| +- js.Function1[-T1, +R]
| +- ...
| +- js.Function22[-T1, ..., -T22, +R]
| +- js.ThisFunction
| +- js.ThisFunction0[-T0, +R]
| +- js.ThisFunction1[-T0, -T1, +R]
| +- ...
| +- js.ThisFunction21[-T0, ..., -T21, +R]
+- js.prim.Number
+- js.prim.Boolean
+- js.prim.String
+- js.prim.Undefined


Note that the types in the `prim` package should not directly be used,
since they have a direct correspondance in Scala (see the
[interoperability](./js-interoperability.html) page). The reason they
exist is that for example a `scala.Double` can be stored in a variable
of type `js.Any` (through implicit conversion to `js.prim.Number`).

A value of any of these types is encoded as is in JavaScript, without wrapping.
Even when such a value is assigned to a `val` of type `scala.Any` or of a
generic type, there is no boxing. E.g., a `js.Array[js.Number]` is a JavaScript
`Array` which contains JavaScript `number`'s at runtime (not some boxing of
`number`'s).
generic type, there is no boxing. E.g., a `js.Array[js.Date]` is a JavaScript
`Array` which contains JavaScript `Date`'s at runtime.

These types have all the fields and methods available in the JavaScript API.

Expand All @@ -59,11 +66,11 @@ There are implicit conversions from corresponding Scala types and back:
<tr><th>Scala type</th><th>JavaScript type</th></tr>
</thead>
<tbody>
<tr><td>Byte<br/>Short<br/>Int<br/>Long<br/>Float<br/>Double</td><td>js.Number</td></tr>
<tr><td colspan="2">(from js.Number to Double only)</td></tr>
<tr><td>Boolean</td><td>js.Boolean</td></tr>
<tr><td>java.lang.String</td><td>js.String</td></tr>
<tr><td>Unit</td><td>js.Undefined</td></tr>
<tr><td>Byte<br/>Short<br/>Int<br/>Long<br/>Float<br/>Double</td><td>js.prim.Number</td></tr>
<tr><td colspan="2">(from js.prim.Number to Double only)</td></tr>
<tr><td>Boolean</td><td>js.prim.Boolean</td></tr>
<tr><td>java.lang.String</td><td>js.prim.String</td></tr>
<tr><td>Unit</td><td>js.prim.Undefined</td></tr>
<tr><td>Array[A]</td><td>js.Array[A]</td></tr>
<tr><td rowspan="2">FunctionN[T1, ..., TN, R]</td><td>js.FunctionN[T1, ..., TN, R]</td></tr>
<tr> <td>js.ThisFunction{N-1}[T1, ..., TN, R]</td></tr>
Expand All @@ -75,13 +82,15 @@ There are implicit conversions from corresponding Scala types and back:
There is no type `js.Null`, because `scala.Null` can be used in its stead with
the appropriate semantics.

`isInstanceOf[T]` for `T` being `js.Number`, `js.Boolean`, `js.String`, or
`js.Undefined`, is supported and is implemented with a `typeof` test.

`isInstanceOf[T]` is supported for _classes_ inheriting from `js.Object`, e.g.,
`js.Date`, `js.Array[_]`, `js.Object` itself, and is implemented with an
`instanceof` test.

`isInstanceOf[T]` for `T` being `js.prim.Number`, `js.prim.Boolean`,
`js.prim.String`, or `js.prim.Undefined`, is supported and is
implemented with a `typeof` test. However, it should be avoided in
preference of `T` being `Double`, `Boolean`, `String` or `Unit`.

`isInstanceOf[T]` is not supported for any other `T` (i.e., traits) inheriting
from `js.Any`.
Consequently, pattern matching for such types is not supported either.
Expand Down Expand Up @@ -224,8 +233,11 @@ if the result will always be the same (e.g., `document`), and `def` when
subsequent accesses to the field might return a different value (e.g.,
`innerWidth`).

Use `Unit` instead of `js.Undefined` as result type of methods that do not
return any value.
Use Scala primitive types instead of types in `js.prim._`. Instead of
`js.prim.Number`, use `Int` where applicable (integral value, not
`NaN`, in signed 32-bit integer range). Otherwise `Double` should be
used (note that `Long` is opaque to JavaScript and therefore cannot be
used).

Calls to the `apply` method of an object `x` map to calling `x`, i.e., `x(...)`
instead of `x.apply(...)`.
Expand Down
41 changes: 31 additions & 10 deletions doc/export-to-javascript.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,13 @@ title: Export Scala.js APIs to JavaScript
---
{% include JB/setup %}

**New in Scala.js v0.4**

By default, Scala.js classes, objects, methods and properties are not available
to JavaScript. Entities that have to be accessed from JavaScript must be
annotated explicitly as *exported*. The `@JSExport` annotation is the main way
to do this.

## A simple example

You have probably already seen two uses of `@JSExport` in the `Main` class of
the bootstrapping skeleton (or any other template of Scala.js application):

{% highlight scala %}
package example

Expand All @@ -39,9 +34,34 @@ HelloWorld().main();

Note the `()` when accessing the object, `HelloWorld` is a function.

This simple pair of `@JSExport` should be sufficient for most application, i.e.,
in cases you only want to get into the entry point of your app, and then live
in the Scala.js world.
You have probably already used an `@JSExport` without knowing it
through the `JSApp` trait in the `Main` class of the bootstrapping
skeleton (or any other template of Scala.js application). In fact, any
Scala.js application must export at least a class or an object and a
method in order to be invokable at all.

Most of the time, however, it is sufficient to just extend the `JSApp`
trait:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"In general" -> "Most of the time"? I believe the former means more "always" than "most of the time".


{% highlight scala %}
package example

import scala.scalajs.js
import js.annotation.JSExport

object HelloWorld extends js.JSApp {
def main(): Unit = {
println("Hello world!")
}
}
{% endhighlight %}

And call like this (see documentation about
`@JSExportDescendentObjects` below for internal workings):

{% highlight javascript %}
example.HelloWorld().main();
{% endhighlight %}

## Exporting top-level objects

Expand Down Expand Up @@ -249,8 +269,9 @@ objects of a given trait or class. You can use the
objects to be exported to their fully qualified name.

This feature is especially useful in conjunction with exported
abstract methods and is used by the test libraries of Scala.js. The
following is just an example, how the feature can be used:
abstract methods and is used by the test libraries of Scala.js and the
`scala.scalajs.js.JSApp` trait. The following is just an example, how
the feature can be used:

{% highlight scala %}
package foo.test
Expand Down
38 changes: 38 additions & 0 deletions doc/js-interoperability.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,41 @@ called from JavaScript code.

* [Call JavaScript APIs from Scala.js](calling-javascript.html)
* [Export Scala.js APIs to JavaScript](export-to-javascript.html)

## <a name="type-correspondance"></a> Type Correspondance
Some Scala types are directly mapped to corresponding underlying
JavaScript types. These correspondances can be used when calling
Scala.js code from JavaScript and when defining typed interfaces for
JavaScript code.

<table class="table table-bordered">
<thead>
<tr><th>Scala type</th><th>JavaScript type</th><th>Restrictions</th></tr>
</thead>
<tbody>
<tr><td>java.lang.String</td><td>string</td><td></tr></tr>
<tr><td>scala.Boolean</td><td>boolean</td><td></td></tr>
<tr><td>scala.Char</td><td><i>opaque</i></td><td></td></tr>
<tr><td>scala.Byte</td><td>number</td><td>integer, range (-128, 127)</td></tr>
<tr><td>scala.Short</td><td>number</td><td>integer, range (-32768, 32767)</td></tr>
<tr><td>scala.Int</td><td>number</td><td>integer, range (-2147483648, 2147483647)</td></tr>
<tr><td>scala.Long</td><td><i>opaque</i></td><td></td></tr>
<tr><td>scala.Float</td><td>number</td><td></td></tr>
<tr><td>scala.Double</td><td>number</td><td></td></tr>
<tr><td>scala.Unit</td><td>undefined</td><td></td></tr>
<tr><td>scala.Null</td><td>null</td><td></td></tr>
<tr><td>subtypes of js.Object</td><td><i>corresponding JavaScript
type</i></td><td>see <a href="calling-javascript.html">calling JavaScript guide</a></td></tr>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line or another line should say something about all the other types extending js.Object (not necessarily in the js package).

<tr>
<td>
other Scala classes<br />
<small>including value classes</small>
</td>
<td>
<i>opaque, except for exported methods</i><br />
<small>Note: <code>toString()</code> is always exported</small>
</td>
<td>see <a href="export-to-javascript.html">exporting Scala.js APIs to JavaScript</a></td>
</tr>
</tbody>
</table>
68 changes: 52 additions & 16 deletions doc/semantics.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,16 @@ a few language semantics differences exist.

## Numbers and characters

Except `Long`, all primitive number types of Scala.js, as well as the `Char`
type, are mapped to JavaScript `Number`'s, i.e., `Double`'s, and no overflow
detection is performed.
Numbers and characters have the same semantics as on the JVM
(including overflow and full 64-bit Longs) with the following three
exceptions. For information about how Scala numeric types map to
JavaScript numeric types, have a look at the
[interoparability guide](./js-interoperability.html).

This means that operations on numbers that would overflow their range do not
wrap, but instead take on bigger values.

Integer division does follow the expected semantics, though, i.e., it always
return an integer.

Binary operations (`&`, `|`, etc.) are always performed on signed 32-bit
integers, just as in JavaScript.

`Long`s are 64-bits and follow the same semantics as on the JVM.
### Floats behave like Doubles
Since JavaScript doesn't have a native float type, we represent them
using doubles/numbers, rather than manually implementing float
arithmetic.

Note that float literals are still truncated to their (binary)
precision. However, output does not truncate to that precision. This
Expand All @@ -36,6 +32,33 @@ println(13.345f)
// Scala.js: 13.345000267028809
{% endhighlight %}

### Integer division by 0 is undefined
Unlike the JVM where dividing an integer type by 0 throws an
exception, in Scala.js integer division by 0 is undefined.
This allows for efficient implementation of division. Dividing a
`Double` or `Float` by 0 yields positive or negative infinity as
expected.

### isInstanceOf tests are based on value
Instance tests (and consequently pattern matching) on any of `Byte`,
`Short`, `Int`, `Float`, `Double` are based on the value and not the
type they were created with. The following are examples:

- 1 matches `Byte`, `Short`, `Int`, `Float`, `Double`
- 128 (`> Byte.MaxValue`) matches `Short`, `Int`, `Float`, `Double`
- 32768 (`> Short.MaxValue`) matches `Int`, `Float`, `Double`
- 2147483648 (`> Int.MaxValue`) matches `Float`, `Double`
- 1.2 matches `Float`, `Double`

As a consequence, the following apparent subtyping relationship holds:

Byte <:< Short <:< Int <:< Float =:= Double

## Unit
`scala.Unit` is represented using JavaScript's `undefined`. Therefore,
calling `toString()` on `Unit` will return `undefined` rather than
`()`.

## Strings

JavaScript uses UCS-2 for encoding strings and does not support
Expand Down Expand Up @@ -102,7 +125,7 @@ val <ident> = Value
val <ident> = Value(<num>)
{% endhighlight %}

are statically rewritten to
are statically rewritten to (a slightly more complicated version of):

{% highlight scala %}
val <ident> = Value("<ident>")
Expand All @@ -115,10 +138,23 @@ val A,B,C,D = Value
{% endhighlight %}
since they are desugared into separate <code>val</code> definitions.
</li>
<li>Calls to either of these two methods which could not be rewritten
will issue a warning.</li>
<li>Calls to either of these two methods which could not be rewritten,
or calls to constructors of the protected <code>Val</code> class without an
explicit name as parameter, will issue a warning.</li>
</ol>

Note that the name rewriting honors the `nextName`
iterator. Therefore, the full rewrite is:

{% highlight scala %}
val <ident> = Value(
if (nextName != null && nextName.hasNext)
nextName.next()
else
"<ident>"
)
{% endhighlight %}

We believe that this covers most use cases of
`scala.Enumeration`. Please let us know if another (generalized)
rewrite would make your life easier.