Semantics of Scala.js and how they differ from Scala
Because the target platform of Scala.js is quite different from that of Scala, a few language semantics differences exist.
Numbers and characters
Floats may behave like Doubles
The choice of how to represent floats is up to the implementation. You may not rely on floats providing 64-bit floating point precision.
Float literals are truncated to their (binary) precision. However, output does not truncate to that precision. This can lead to the following behavior (this works as expected when using doubles):
println(13.345f) // Scala: 13.345 // Scala.js: 13.345000267028809
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
Float by 0 yields positive or negative infinity as
isInstanceOf tests are based on value
Instance tests (and consequently pattern matching) on any of
Double are based on the value and not the
type they were created with. The following are examples:
- 1 matches
- 128 (
> Byte.MaxValue) matches
- 32768 (
> Short.MaxValue) matches
- 2147483648 (
> Int.MaxValue) matches
- 1.2 matches
As a consequence, the following apparent subtyping relationship holds:
Byte <:< Short <:< Int <:< Float =:= Double
toString for integral Floats and Doubles
toString on a Float or a Double that holds an integral
value, will not append ".0" to that value:
println(1.0) // Scala: 1.0 // Scala.js: 1
This is due to how numeric values are represented at runtime in Scala.js. Use a formatting interpolator if you always want to show decimals:
val x = 1.0 println(f"$x%.1f") // Scala: 1.0 // Scala.js: 1.0
Unit will return
undefined rather than
conversion to or from other character sets. As a result,
Byte arrays are not supported by Scala.js.
Java reflection and, a fortiori, Scala reflection, are not supported. There is
limited support for
obj.getClass.getName will work
In general, Scala.js supports exceptions, including catching them based on their type. However, exceptions that are typically triggered by the JVM have flaky semantics, in particular:
ArrayIndexOutOfBoundsExceptionis never thrown.
This sometimes has an impact on functions in the Scala library that use regular expressions themselves. A list of known functions that are affected is given here:
StringLike.split(x: Array[Char])(see issue #105)
scala.Symbol is supported, but is a potential source of memory leaks
in applications that make heavy use of symbols. The main reason is that
by Scala.js tow remain in memory throughout the lifetime of the application.
Value(i: Int) on
reflection to retrieve a string representation of the member name and
are therefore -- in principle -- unsupported. However, since
Enumerations are an integral part of the Scala library, Scala.js adds
limited support for these two methods:
- Calls to either of these two methods of the forms:
are statically rewritten to (a slightly more complicated version of):
val <ident> = Value val <ident> = Value(<num>)Note that this also includes calls like
val <ident> = Value("<ident>") val <ident> = Value(<num>,"<ident>")since they are desugared into separate
val A,B,C,D = Value
- Calls to either of these two methods which could not be rewritten,
or calls to constructors of the protected
Valclass without an explicit name as parameter, will issue a warning.
Note that the name rewriting honors the
iterator. Therefore, the full rewrite is:
val <ident> = Value( if (nextName != null && nextName.hasNext) nextName.next() else "<ident>" )
We believe that this covers most use cases of
scala.Enumeration. Please let us know if another (generalized)
rewrite would make your life easier.