Converting scala callbacks to js.Function

604 views
Skip to first unread message

Asko Kauppi

unread,
Aug 18, 2014, 5:03:32 PM8/18/14
to scal...@googlegroups.com
I want to give a callback to a JavaScript API. It's expecting js.Function1[Double,Unit]. How should I formulate such a function in Scala.js?

      Snap.animate(0, 2*PI, ((rad: Double) => {
        val x= 210 * Math.cos( rad + PI )
        val y= 210 * Math.sin( rad + PI )
        table.transform( s"t$x,$y" )
        hand.transform( s"r$rad,300,300")
      }): js.Function1[Double,Unit], 12000 )

This is not the ideal code, having casts and all. It gives in compilation: 

/Users/asko/Hg/scalajs-snapsvg/example/src/main/scala/clock.scala:110: type mismatch;
[error]  found   : Double => hand.type (with underlying type Double => hand.type)
[error]  required: scala.scalajs.js.Function1[Double,Unit]
[error]       Snap.animate(0, 2*PI, ((rad: Double) => {

There must be a very simple solution to this. Why don't the Scala.js functions simply get implemented as js.Function? How are they different?

If I remove the type enforcement (this is how I'd like the code to be):

      Snap.animate(0, 2*PI, (rad: Double) => {
        val x= 210 * Math.cos( rad + PI )
        val y= 210 * Math.sin( rad + PI )
        table.transform( s"t$x,$y" )
        hand.transform( s"r$rad,300,300")
      } , 12000 )

/Users/asko/Hg/scalajs-snapsvg/example/src/main/scala/clock.scala:110: overloaded method value animate with alternatives:
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int)akauppi.scalajs.snapsvg.SnapAnimMina <and>
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int,easing: scala.scalajs.js.Function1[Double,Double])akauppi.scalajs.snapsvg.SnapAnimMina <and>
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int,easing: scala.scalajs.js.Function1[Double,Double],callback: scala.scalajs.js.Function0[Unit])akauppi.scalajs.snapsvg.SnapAnimMina
[error]  cannot be applied to (Int, Double, Double => hand.type, Int)
[error]       Snap.animate(0, 2*PI, ((rad: Double) => {

...the callback is seen as Double => hand.type (return type of the last statement). Should I force it to be Unit, somehow? 

Any samples that already tackle such conversions would be appreciated.

thanks,
- asko

Jason Jackson

unread,
Aug 18, 2014, 6:55:35 PM8/18/14
to Asko Kauppi, scal...@googlegroups.com
You can put a bare (), which is unit, on the line after
hand.transform(). Then the function will be of the correct type.

Jason
> --
> You received this message because you are subscribed to the Google Groups
> "Scala.js" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to scala-js+u...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/scala-js/71b64ec9-3b7c-4a8d-a6f2-fb2340915b3c%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Asko Kauppi

unread,
Aug 19, 2014, 2:22:43 AM8/19/14
to scal...@googlegroups.com, aka...@gmail.com
Hi Jason,

sbt does not find 'bare()' nor 'js.bare()' but I had placed a 'Unit' there with similar intentions. 

Having said that, shouldn't Scala function blocks ending with anything get converted to '=> Unit' when needed. Of course they should.

If 'Unit' is added, compilation gives:

/Users/asko/Hg/scalajs-snapsvg/example/src/main/scala/clock.scala:112: overloaded method value animate with alternatives:
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int)akauppi.scalajs.snapsvg.SnapAnimMina <and>
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int,easing: scala.scalajs.js.Function1[Double,Double])akauppi.scalajs.snapsvg.SnapAnimMina <and>
[error]   (from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int,easing: scala.scalajs.js.Function1[Double,Double],callback: scala.scalajs.js.Function)akauppi.scalajs.snapsvg.SnapAnimMina
[error]  cannot be applied to (Double, Double, Double => Unit.type, Int)
[error]       Snap.animate(0.0, 2*PI, (rad: Double) => {
[error]            ^

(from: Double,to: Double,setter: scala.scalajs.js.Function1[Double,Unit],duration: Int)
(Double, Double, Double => Unit.type, Int)

Only the callback argument is different, so clearly some conversion is lacking there.

Should it be made implicitly - am I missing some import statement that enables such? 

Currently only importing 'scala.scalajs.js'.

- asko

Jason Jackson

unread,
Aug 19, 2014, 7:11:11 AM8/19/14
to Asko Kauppi, scal...@googlegroups.com
Sorry, I did not mean to literally type the word bare. I meant to put
a () and nothing else on the last line. In other words:

hand.transform( s"r$rad,300,300")
()

As for the technical details, I do not know. I just know that I had a
similar problem with d3 and this is how I fixed it.

Jason
> https://groups.google.com/d/msgid/scala-js/6b141412-d2f4-4e0d-a424-0f01b2e8cded%40googlegroups.com.

Asko Kauppi

unread,
Aug 19, 2014, 3:16:38 PM8/19/14
to scal...@googlegroups.com
Thank you, Jason. 

That did it. I now have an animated clock demo (very simple) running on scala.js. I'll add some license text and place the stuff on GitHub - within a week.

I'm still not pleased with how "elegant" the Scala.js side of the code is. There seems to be needs for boilerplate that I'd like to eliminate. But it works, therefore it's worth getting it out. :)

- asko

Sébastien Doeraene

unread,
Aug 23, 2014, 5:21:13 AM8/23/14
to Asko Kauppi, scal...@googlegroups.com
Hi,

It would be best to define animate method as receiving a js.Function1[Double, _]. That way your first example function, which is inferred to return hand.type (and not Unit) would be valid. In general if a function type has a Unit result type, it should be _ instead: you don't really need the function to return Unit, rather, you don't care what it returns (hence it can return anything).

Cheers,
Sébastien


--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.

Asko Kauppi

unread,
Aug 23, 2014, 11:46:46 AM8/23/14
to scal...@googlegroups.com, aka...@gmail.com
Thanks, Sébastien

That's exactly what I wanted to know. Is the use of _ with FunctionN traits described somewhere? I might have completely missed it, or it's not in the documentation. We can't expect people to crawl through all of the mailing list for these things. 

Anyways, I'm placing the project online at GitHub after some license texts. Will notify on the mailing list, of course.

- asko

Sébastien Doeraene

unread,
Aug 23, 2014, 11:55:57 AM8/23/14
to Asko Kauppi, scal...@googlegroups.com

Hi,

No, it's not explained anywhere, because there's nothing specific to Scala.js about it. The same idiom is used for Scala APIs. See for example the foreach method.

Cheers,
Sébastien

Haoyi Li

unread,
Aug 23, 2014, 11:59:27 AM8/23/14
to Sébastien Doeraene, Asko Kauppi, scal...@googlegroups.com

Probably still could go in the scalajs interop docs though, since its something that will continue to bite people. Even if technically not scalajs specific, I bet lots of people who hit this (e.g. me, multiple times!) will have never hit it anywhere else before that.

Asko Kauppi

unread,
Aug 24, 2014, 4:22:09 PM8/24/14
to scal...@googlegroups.com, sjrdo...@gmail.com, aka...@gmail.com
The particular binding is now publicly available: https://github.com/akauppi/scalajs-snapsvg

I would like people to:
- check the documentation (README, LICENSE, TODO)
- check the build (do you get example/clock.html up - with animation on clicking it) with the help of the docs

It's a start, lots to do, but I wanted this out since the first little demo works and this allows us to contribute to the binding.

Cheers,

- asko
Reply all
Reply to author
Forward
0 new messages