From 48ec678d637948d6be09c92c01e1e349964b930e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Fri, 28 Aug 2015 22:03:55 +0200 Subject: [PATCH] Update the docs for 0.6.5 and announce its release. --- _config.yml | 2 +- .../2015-08-31-announcing-scalajs-0.6.5.md | 231 +++++++++++++++ doc/calling-javascript.md | 30 +- doc/index.md | 10 + doc/js-interoperability.md | 1 + doc/sjs-defined-js-classes.md | 278 ++++++++++++++++++ downloads.md | 6 + index.md | 1 + 8 files changed, 552 insertions(+), 7 deletions(-) create mode 100644 _posts/news/2015-08-31-announcing-scalajs-0.6.5.md create mode 100644 doc/sjs-defined-js-classes.md diff --git a/_config.yml b/_config.yml index 220f286a..6feaf028 100644 --- a/_config.yml +++ b/_config.yml @@ -18,7 +18,7 @@ author : twitter : sjrdoeraene feedburner : feedname -scalaJSVersion: 0.6.4 +scalaJSVersion: 0.6.5 scalaJSBinaryVersion: 0.6 # The production_url is only used when full-domain names are needed diff --git a/_posts/news/2015-08-31-announcing-scalajs-0.6.5.md b/_posts/news/2015-08-31-announcing-scalajs-0.6.5.md new file mode 100644 index 00000000..1f60cf56 --- /dev/null +++ b/_posts/news/2015-08-31-announcing-scalajs-0.6.5.md @@ -0,0 +1,231 @@ +--- +layout: post +title: Announcing Scala.js 0.6.5 +category: news +tags: [releases] +--- +{% include JB/setup %} + +We are thrilled to announce the release of Scala.js 0.6.5! + +This is probably *the most important release since Scala.js 0.5.0*! +It brings significant advances to interoperability with JavaScript: + +* You can now implement subclasses of JavaScript classes and traits in Scala.js! +* Using the same semantics, you can now define object literals with `new js.Object { val x = 5 }` +* There is a new unboxed pseudo-union type `A | B` to more accurately type your JavaScript facades +* You can statically typecheck that the `@JSExport`s of a Scala class comply with a JavaScript facade trait with `js.use(x).as[T]` + +## Getting started + +If you are new to Scala.js, head over to +[the tutorial]({{ BASE_PATH }}/doc/tutorial.html). + +## Release notes + +For changes in the 0.6.x series compared to 0.5.x, read [the announcement of 0.6.0]({{ BASE_PATH }}/news/2015/02/05/announcing-scalajs-0.6.0/). + +As a minor release, 0.6.5 is backward source and binary compatible with previous releases in the 0.6.x series. +Libraries compiled with earlier versions can be used with 0.6.5 without change. +However, it is not forward compatible: libraries compiled with 0.6.5 cannot be used by projects using 0.6.{0-4}. + +Please report any issues [on GitHub](https://github.com/scala-js/scala-js/issues). + +## Important new warnings + +When upgrading from 0.6.{0-4}, you will get new warnings on the declarations of your facade types, i.e., traits, classes and objects extending `js.Any`. +For example: + +{% highlight scala %} +import scala.scalajs.js + +class Foo extends js.Object { + def bar(x: Int): Int = js.native +} +{% endhighlight %} + +will have the following warning: + + Foo.scala:3: warning: Classes, traits and objects inheriting from js.Any should be annotated + with @js.native, unless they have @ScalaJSDefined. + The default will switch to Scala.js-defined in the next major version of Scala.js. + class Foo extends js.Object + ^ + +As the text says, you should simply add the `@js.native` annotation to the declaration of `Foo` to silence the warning: + +{% highlight scala %} +import scala.scalajs.js + +@js.native +class Foo extends js.Object { + def bar(x: Int): Int = js.native +} +{% endhighlight %} + +Addressing these warnings is important to make your source code forward compatible with the next major version of Scala.js. +An unannotated declaration extending `js.Any` will by default be Scala.js-defined (see next section) in the next version. + +## Improvements + +### Scala.js-defined JS classes, objects, and traits + +Scala.js 0.6.5 introduces a major language improvement: the ability to define, in Scala.js, a subclass of a native JavaScript class (or implementing a JavaScript trait/interface). +We call such classes *Scala.js-defined JS classes*, because they are effectively JavaScript classes, but written in Scala.js; whereas classes that you typically write are Scala classes, not JavaScript classes. + +{% highlight scala %} +import scala.scalajs.js +import scala.scalajs.js.annotation._ + +@ScalaJSDefined +class Foo extends js.Object { + def bar(x: Int): Int = x + 1 +} +{% endhighlight %} + +Note that the body of `bar()` is implemented in Scala.js, instead of being `= js.native`. + +A Scala.js-defined JS class is not a facade type to a JavaScript library. +Instead, it is fully implemented in Scala.js. +Unlike Scala classes, which require exports, all members of Scala.js-defined JS classes are automatically visible from JavaScript code. +The class itself is not automatically visible; if you want it to be, you can `@JSExport` it. +You can also use [`js.constructorOf[C]`]({{ site.production_url }}/api/scalajs-library/0.6.5/#scala.scalajs.js.package@constructorOf[T<:scala.scalajs.js.Any]:scala.scalajs.js.Dynamic) to obtain the JS constructor function and pass it to a JavaScript library. + +Scala.js-defined JS classes have JavaScript semantics instead of Scala semantics. +You can read more about that in [the documentation]({{ BASE_PATH }}/doc/sjs-defined-js-classes.html). +Most importantly, that means overloading dispatch is done at run-time instead of compile-time. + +You can also declare Scala.js-defined JS `object`s as singletons, just like `object`s in Scala. + +#### Traits + +Scala.js-defined JS traits are restricted: they cannot declare any concrete term member, i.e., all their `val`s, `var`s and `def`s must be abstract. + +{% highlight scala %} +import scala.scalajs.js +import scala.scalajs.js.annotation._ + +@ScalaJSDefined +trait Foo extends js.Object { + val x: Int // ok + val y: Int = 5 // illegal + + def foo(x: Int): Int // ok + def bar(x: Int): Int = x + 1 // illegal +} +{% endhighlight %} + +Scala.js-defined JS classes, objects and traits cannot directly extend native JS traits (i.e., non-Scala.js-defined JS traits). + +#### Anonymous classes and object literals + +Anonymous classes extending a JS class and/or trait are automatically Scala.js-defined. +Combined with Scala.js-defined JS traits, this is very useful to write typechecked object literals with Scala syntax: + +{% highlight scala %} +import scala.scalajs.js +import scala.scalajs.js.annotation._ + +@ScalaJSDefined +trait Position extends js.Object { + val x: Int + val y: Int +} + +val obj = new Position { + val x = 5 + val y = 10 +} +{% endhighlight %} + +In previous versions, `obj` would have been written with a non-typechecked `js.Dynamic.literal`: + +{% highlight scala %} +import scala.scalajs.js + +val obj = js.Dynamic.literal( + x = 5, + y = 10 +).asInstanceOf[Position] +{% endhighlight %} + +### Pseudo-union type `A | B` + +Many JavaScript libraries have APIs with parameters or values that accept different types of values. +To be able to accurately type those libraries, Scala.js 0.6.5 features an unboxed, facade-friendly pseudo-union type [`A | B`]({{ site.production_url }}/api/scalajs-library/0.6.5/#scala.scalajs.js.$bar). +Here are a couple of examples of what it can do: + +{% highlight scala %} +import scala.scalajs.js.| + +val a: Int | String = 5 +val b: Int | String = "hello" +val c: String | Int = a +val d: Int | Boolean | String = true +val e: Int | Boolean | String = c +val f: AnyVal | String = e +val g: Any = f.merge + +// the following examples do not compile +val x: Int | String = 3.4 +val y: Int | Boolean = d +{% endhighlight %} + +See [the complete test cases](https://github.com/scala-js/scala-js/tree/v0.6.5/test-suite/src/test/scala/org/scalajs/testsuite/library/UnionTypeTest.scala) to get the complete picture. + +### `js.use(x).as[T]`: statically typecheck your exports + +Sometimes, you `@JSExport` members of your Scala classes so that they comply with some JavaScript interface, for example to pass it to a JavaScript library expecting some fields and methods on your object. +In 0.6.4 and before, you needed to take care yourself of exporting everything that was required, and then probably do a hard-cast: + +{% highlight scala %} +import scala.scalajs.js + +trait SomeInterface extends js.Object { + val x: Int = js.native + def foo(x: Int): Int = js.native +} + +object SomeLibrary extends js.Object { + def doSomething(obj: SomeInterface): Unit = js.native +} + +class InterfaceImpl { + @JSExport val x: Int = 4 + @JSExport def foo(x: Int): Int = x + 1 +} + +SomeLibrary.doSomething(new InterfaceImpl().asInstanceOf[SomeInterface]) +{% endhighlight %} + +If you mess up your exports, you will have trouble at run-time. + +In 0.6.5, you can write the following instead: + +{% highlight scala %} +SomeLibrary.doSomething(js.use(new InterfaceImpl()).as[SomeInterface]) +{% endhighlight %} + +Unlike `x.asInstanceOf[T]`, the `js.use(x).as[T]` idiom *statically typechecks* that you have all the exports required to comply to the JavaScript interface. + +### Java library additions + +* The complete set of `Character.isXYZ` methods (to test Unicode properties of characters) +* `java.lang.Math.rint(Double)` +* `java.util.concurrent.ThreadLocalRandom` +* `java.util.TreeSet` and `java.util.NavigableSet` + +## Bug fixes + +Among others, the following bugs have been fixed: + +* [#1818](https://github.com/scala-js/scala-js/issues/1818) Performance bottleneck in one of the steps of the linker (fast- and fullOptJS) +* [#1759](https://github.com/scala-js/scala-js/issues/1759) `new Int8Array(n).toArray` throws `TypeError` (second run) +* [#1790](https://github.com/scala-js/scala-js/issues/1790) Compiler crash with a dash in a parameter of a lambda +* [#1799](https://github.com/scala-js/scala-js/issues/1799) `java.lang.Iterable` is incorrectly in `java.util` +* [#1819](https://github.com/scala-js/scala-js/issues/1819) `Double` doesn't match `Float` even with non-strict floats +* [#1836](https://github.com/scala-js/scala-js/issues/1836) `BigInteger.ONE.gcd(x)` loops forever +* [#1857](https://github.com/scala-js/scala-js/issues/1857) `j.l.Math.{abs,min,max}` do not handle correctly `-0.0` +* [#1777](https://github.com/scala-js/scala-js/issues/1777) Bug with `java.util.LinkedList.size` when larger than `Int.MaxValue`. + +You can find the full list [on GitHub](https://github.com/scala-js/scala-js/issues?q=is%3Aissue+milestone%3Av0.6.5+is%3Aclosed). diff --git a/doc/calling-javascript.md b/doc/calling-javascript.md index 4ca90b37..abcbce8d 100644 --- a/doc/calling-javascript.md +++ b/doc/calling-javascript.md @@ -176,6 +176,8 @@ or as js.Dynamic.literal("foo" -> 42, "bar" -> "foobar") {% endhighlight %} +Alternatively, you can use anonymous classes extending `js.Object` or a [Scala.js-defined JS trait](./sjs-defined-js-classes.html). + ## Defining JavaScript interfaces with traits Most JavaScript APIs work with interfaces that are defined structurally. In @@ -186,12 +188,17 @@ from `js.Any` (usually from `js.Object`). JS traits can contain `val`, `var` and `def` definitions, and the latter can be overloaded. -All definitions must have `js.native` as body. -Any other body (including omitting the `=` altogether) will be handled as if -it were `js.native`, and a warning will be emitted. +By default, types extending `js.Any` are native JS types. +There also exist [Scala.js-defined JS types](./sjs-defined-js-classes.html). +Native JS types should be annotated with `@js.native` for forward source compatibility with Scala.js 1.0.0. + +**Pre 0.6.5 note**: Before Scala.js 0.6.5, the `@js.native` annotation did not exist, so you will find old code that does not yet use it to annotate native JS types. + +In native JS types, all concrete definitions must have `= js.native` as body. +Any other body will be handled as if it were `= js.native`, and a warning will be emitted. (In Scala.js 1.0.0, this will become an error.) -**0.5.x note**: In Scala.js 0.5.x, `js.native` did not exist. The recommended +**0.5.x note**: In Scala.js 0.5.x, `= js.native` did not exist either. The recommended best practice was to put `???` as body, but this was not enforced by the compiler. This has been changed to improve intuition and remove warts. @@ -199,6 +206,7 @@ Here is an example giving types to a small portion of the API of `Window` objects in browsers. {% highlight scala %} +@js.native trait Window extends js.Object { val document: HTMLDocument = js.native var location: String = js.native @@ -234,6 +242,8 @@ However, the actual value is irrelevant and never used. Instead, the parameter is omitted entirely (or set to `undefined`). The value is only indicative, as implicit documentation. +Fields, parameters, or result types that can have different, unrelated types, can be accurately typed with the [pseudo-union type `A | B`]({{ site.production_url }}/api/scalajs-library/{{ site.scalaJSVersion }}/#scala.scalajs.js.$bar). + Methods can be overloaded. This is useful to type accurately some APIs that behave differently depending on the number or types of arguments. @@ -303,9 +313,9 @@ The Scala method names are irrelevant for the translation to JavaScript. The duo `apply`/`update` is often a sensible choice, because it gives array-like access on Scala's side as well, but it is not required to use these names. -## JavaScript classes +## Native JavaScript classes -It is also possible to define JavaScript *classes* as Scala classes inheriting, +It is also possible to define native JavaScript *classes* as Scala classes inheriting, directly or indirectly, from `js.Any` (like traits, usually from `js.Object`). The main difference compared to traits is that classes have constructors, hence they also provide instantiation of objects with the `new` keyword. @@ -321,6 +331,7 @@ to specify the JavaScript name: {% highlight scala %} @JSName("THREE.Scene") +@js.native class Scene extends js.Object {% endhighlight %} @@ -348,6 +359,7 @@ These can be declared in Scala.js with `object`'s inheriting directly or indirectly from `js.Any` (again, often `js.Object`). {% highlight scala %} +@js.native object JSON extends js.Object { def parse(text: String): js.Any = js.native @@ -363,11 +375,15 @@ Similarly to classes, the JavaScript name can be specified with `@JSName`, e.g., {% highlight scala %} @JSName("jQuery") +@js.native object JQuery extends js.Object { def apply(x: String): JQuery = js.native } {% endhighlight %} +Unlike classes and traits, native JS objects can have inner native JS classes, traits and objects. +Inner classes and objects will be looked up as fields of the enclosing JS object. + ## Variables and functions in the global scope Besides object-like top-level definitions, JavaScript also defines variables @@ -377,6 +393,7 @@ indirectly from `js.GlobalScope` (which itself extends `js.Object`) are considered to represent the global scope. {% highlight scala %} +@js.native object DOMGlobalScope extends js.GlobalScope { val document: HTMLDocument = js.native @@ -411,6 +428,7 @@ The implicit conversion is implemented with a hard cast, since in effect we just want to extend the API, not actually change the value. {% highlight scala %} +@js.native trait JQueryGreenify extends JQuery { def greenify(): this.type = ??? } diff --git a/doc/index.md b/doc/index.md index 20af01cc..d1b3f37c 100644 --- a/doc/index.md +++ b/doc/index.md @@ -28,6 +28,16 @@ Generated Scaladocs are available here: ### Scala.js +#### Scala.js 0.6.5 +* [0.6.5 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.5/#scala.scalajs.js.package) +* [0.6.5 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.5/) +* [0.6.5 scalajs-stubs]({{ site.production_url }}/api/scalajs-stubs/0.6.5/) +* [0.6.5 scalajs-ir]({{ site.production_url }}/api/scalajs-ir/0.6.5/#org.scalajs.core.ir.package) +* [0.6.5 scalajs-tools]({{ site.production_url }}/api/scalajs-tools/0.6.5/#org.scalajs.core.tools.package) ([Scala.js version]({{ site.production_url }}/api/scalajs-tools-js/0.6.5/#org.scalajs.core.tools.package)) +* [0.6.5 scalajs-js-envs]({{ site.production_url }}/api/scalajs-js-envs/0.6.5/#org.scalajs.jsenv.package) +* [0.6.5 scalajs-test-adapter]({{ site.production_url }}/api/scalajs-sbt-test-adapter/0.6.5/#org.scalajs.testadapter.package) +* [0.6.5 sbt-scalajs]({{ site.production_url }}/api/sbt-scalajs/0.6.5/#org.scalajs.sbtplugin.package) + #### Scala.js 0.6.4 * [0.6.4 scalajs-library]({{ site.production_url }}/api/scalajs-library/0.6.4/#scala.scalajs.js.package) * [0.6.4 scalajs-test-interface]({{ site.production_url }}/api/scalajs-test-interface/0.6.4/) diff --git a/doc/js-interoperability.md b/doc/js-interoperability.md index 64968cb3..a8e63106 100644 --- a/doc/js-interoperability.md +++ b/doc/js-interoperability.md @@ -15,6 +15,7 @@ called from JavaScript code. * [Call JavaScript APIs from Scala.js](calling-javascript.html) * [Export Scala.js APIs to JavaScript](export-to-javascript.html) +* [Write JavaScript classes in Scala.js](sjs-defined-js-classes.html) ## Type Correspondance Some Scala types are directly mapped to corresponding underlying diff --git a/doc/sjs-defined-js-classes.md b/doc/sjs-defined-js-classes.md new file mode 100644 index 00000000..3f8ab327 --- /dev/null +++ b/doc/sjs-defined-js-classes.md @@ -0,0 +1,278 @@ +--- +layout: page +title: Scala.js-defined JS classes +--- +{% include JB/setup %} + +As explained in detail in the [guide to write facade types](./calling-javascript.html), classes, traits and objects inheriting from `js.Any` are native by default. +To implement a JavaScript class in Scala.js, it should be annotated with `@ScalaJSDefined`: + +{% highlight scala %} +import scala.scalajs.js +import js.annotation._ + +@ScalaJSDefined +class Foo extends js.Object { + val x: Int = 4 + def bar(x: Int): Int = x + 1 +} +{% endhighlight %} + +Such classes are called Scala.js-defined JS classes. +All their members are automatically visible from JavaScript code. +The class itself (its constructor function) is not visible by default, but can be exported with `@JSExport`. +Moreover, they can extend JavaScript classes (native or Scala.js-defined), and, if exported, be extended by JavaScript classes. + +Being JavaScript types, the Scala semantics do not apply to these classes. +Instead, JavaScript semantics apply. +For example, overloading is dispatched at run-time, instead of compile-time. + + +## Restrictions + +Scala.js-defined JS types have the following restrictions: + +* Private methods cannot be overloaded. +* Qualified private members, i.e., `private[EnclosingScope]`, must be `final`. +* Scala.js-defined JS classes, traits and objects cannot directly extend native JS traits (it is allowed to extend a native JS class). +* Scala.js-defined JS traits cannot declare concrete term members, i.e., they must all be abstract. +* Scala.js-defined JS classes and objects must extend a JS class, for example `js.Object` (they cannot directly extend `AnyRef with js.Any`). +* Declaring a method named `apply` without `@JSName` is illegal. +* Declaring a method with `@JSBracketSelect` or `@JSBracketCall` is illegal. +* Mixing fields, pairs of getter/setter, and/or methods with the same name is illegal. (For example `def foo: Int` and `def foo(x: Int): Int` cannot both exist in the same class.) + +There is also one implementation restriction, which will be lifted in a future version: + +* A Scala.js-defined JS class cannot have secondary constructors, and its primary constructor cannot have default parameters nor repeated parameters (varargs). + + +## Semantics + + +### What JavaScript sees + +* `val`s and `var`s become actual JavaScript *fields* of the object, so JavaScript sees a field stored on the object. +* `def`s with `()` become JavaScript *methods* on the prototype. +* `def`s without `()` become JavaScript *getters* on the prototype. +* `def`s whose Scala name ends with `_=` become JavaScript *setters* on the prototype. + +In other words, the following definition: + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object { + val x: Int = 5 + var y: String = "hello" + def z: Int = 42 + def z_=(v: Int): Unit = println("z = " + v) + def foo(x: Int): Int = x + 1 +} +{% endhighlight %} + +can be understood as the following ECMAScript 6 class definition (or its desugaring in ES 5.1): + +{% highlight javascript %} +class Foo extends global.Object { + constructor() { + super(); + this.x = 5; + this.y = "hello"; + } + get z() { + return 42; + } + set z(v) { + console.log("z = " + v); + } + foo(x) { + return x + 1; + } +} +{% endhighlight %} + +The JavaScript names are the same as the field and method names in Scala by default. +You can override this with `@JSName("customName")`. + +`private`, `private[this]` and `private[EnclosingScope]` methods, getters and setters are not visible at all from JavaScript. +Private fields, however, will exist on the object, with unpredictable names. +Trying to access them is undefined behavior. + +All other members, including protected ones, are visible to JavaScript. + + +### `super` calls + +`super` calls have the semantics of `super` references in ECMAScript 6. +For example: + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object { + override def toString(): String = super.toString() + " in Foo" +} +{% endhighlight %} + +has the same semantics as: + +{% highlight javascript %} +class Foo extends global.Object { + toString() { + return super.toString() + " in Foo"; + } +} +{% endhighlight %} + +which, in ES 5.1, gives something like + +{% highlight javascript %} +Foo.prototype.toString = function() { + return global.Object.prototype.toString.call(this) + " in Foo"; +}; +{% endhighlight %} + +For fields, getters and setters, the ES 6 spec is a bit complicated, but it essentially "does the right thing". +In particular, calling a super getter or setter works as expected. + + +### Scala.js-defined JS object + +A Scala.js-defined JS `object` is a singleton instance of Scala.js-defined JS class. +There is nothing special about this, it's just like Scala objects. + +Scala.js-defined JS objects are not automatically visible to JavaScript. +They can be `@JSExport`ed just like Scala object: they will appear as a 0-argument function returning the instance of the object. + + +### Scala.js-defined JS traits + +Traits and interfaces do not have any existence in JavaScript. +At best, they are documented contracts that certain classes must satisfy. +So what does it mean to have native JS traits and Scala.js-defined JS traits? + +Native JS traits can only be extended by native JS classes, objects and traits. +In other words, a Scala.js-defined JS class/trait/object cannot extend a native JS trait. +They can only extend Scala.js-defined JS traits. + +At the moment, Scala.js-defined JS traits cannot declare any concrete term members, i.e., all its `val`s, `var`s and `def`s must be abstract. +So it is not possible to *mix in* traits into Scala.js-defined JS classes. +You can only implement interfaces. + +{% highlight scala %} +@ScalaJSDefined +trait Bar extends js.Object { + val x: Int + val y: Int = 5 // illegal + + def foo(x: Int): Int + def bar(x: Int): Int = x + 1 // illegal +} +{% endhighlight %} + + +### Anonymous classes + +An anonymous class extending `js.Any` is automatically Scala.js-defined. +This is particularly useful to create typed object literals, in the presence of a Scala.js-defined JS trait describing an interface. +For example: + +{% highlight scala %} +@ScalaJSDefined +trait Position extends js.Object { + val x: Int + val y: Int +} + +val pos = new Position { + val x = 5 + val y = 10 +} +{% endhighlight %} + +#### Caveat with reflective calls + +It is possible to *define* an object literal with the anonymous class syntax without the support of a super class or trait defining the API, like this: + +{% highlight scala %} +val pos = new js.Object { + val x = 5 + val y = 10 +} +{% endhighlight %} + +However, it is thereafter impossible to access its members easily. +The following does not work: + +{% highlight scala %} +println(pos.x) +{% endhighlight %} + +This is because `pos` is a *structural type* in this case, and accessing `x` is known as a *reflective call* in Scala. +Reflective calls are not supported on values with JavaScript semantics, and will fail at runtime. +Fortunately, the compiler will warn you against reflective calls, unless you use the relevant language import. + +Our advice: do not use the reflective calls language import. + + +### Run-time overloading + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object { + def bar(x: String): String = "hello " + x + def bar(x: Int): Int = x + 1 +} + +val foo = new Foo +println(foo.bar("world")) // choose at run-time which one to call +{% endhighlight %} + +Even though typechecking will resolve to the first overload at compile-time to decide the result type of the function, the actual call will re-resolve at run-time, using the dynamic type of the parameter. Basically something like this is generated: + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object { + def bar(x: Any): Any = { + x match { + case x: String => "hello " + x + case x: Int => x + 1 + } + } +} +{% endhighlight %} + +Besides the run-time overhead incurred by such a resolution, this can cause weird problems if overloads are not mutually exclusive. +For example: + +{% highlight scala %} +@ScalaJSDefined +class Foo extends js.Object { + def bar(x: String): String = bar(x: Any) + def bar(x: Any): String = "bar " + x +} + +val foo = new Foo +println(foo.bar("world")) // infinite recursion +{% endhighlight %} + +With compile-time overload resolution, the above would be fine, as the call to `bar(x: Any)` resolves to the second overload, due to the static type of `Any`. +With run-time overload resolution, however, the type tests are executed again, and the actual run-time type of the argument is still `String`, which causes an infinite recursion. + + +## Goodies + + +### `js.constructorOf[C]` + +To obtain the JavaScript constructor function of a Scala.js-defined JS class without instantiating it nor exporting it, you can use [`js.constructorOf[C]`]({{ site.production_url }}/api/scalajs-library/{{ site.scalaJSVersion }}/#scala.scalajs.js.package@constructorOf[T<:scala.scalajs.js.Any]:scala.scalajs.js.Dynamic), whose signature is: + +{% highlight scala %} +package object js { + def constructorOf[C <: js.Any]: js.Dynamic = +} +{% endhighlight %} + +`C` must be a class type (i.e., such that you can give it to `classOf[C]`) and refer to a JS *class* (not a trait nor an object). +It can be a native JS class or a Scala.js-defined JS class. +The method returns the JavaScript constructor function (aka the class value) for `C`. + +This can be useful to give to JavaScript libraries expecting constructor functions rather than instances of the classes. diff --git a/downloads.md b/downloads.md index b0befbf1..1c282f61 100644 --- a/downloads.md +++ b/downloads.md @@ -9,6 +9,12 @@ We strongly recommend using the SBT plugin, as shown in the [bootstrapping skele The CLI distribution requires `scala` and `scalac` (of the right major version) to be on the execution path. Unpack it wherever you like and add the `bin/` folder to your execution path. +#### Scala.js 0.6.5 +* [0.6.5, Scala 2.11 (tgz, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.5.tgz) +* [0.6.5, Scala 2.11 (zip, 24MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.5.zip) +* [0.6.5, Scala 2.10 (tgz, 21MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.5.tgz) +* [0.6.5, Scala 2.10 (zip, 21MB)]({{ site.production_url }}/files/scalajs_2.10-0.6.5.zip) + #### Scala.js 0.6.4 * [0.6.4, Scala 2.11 (tgz, 23MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.4.tgz) * [0.6.4, Scala 2.11 (zip, 23MB)]({{ site.production_url }}/files/scalajs_2.11-0.6.4.zip) diff --git a/index.md b/index.md index 134aac15..ac762711 100644 --- a/index.md +++ b/index.md @@ -210,6 +210,7 @@ List of websites using Scala.js: ## Version History +- [0.6.5](/news/2015/08/31/announcing-scalajs-0.6.5/) - [0.6.4](/news/2015/07/03/announcing-scalajs-0.6.4/) - [0.6.3](/news/2015/05/12/announcing-scalajs-0.6.3/) - [0.6.2](/news/2015/03/16/announcing-scalajs-0.6.2/)