Re: [Scala.js] Using ScalaJS with async/promises/futures

243 views
Skip to first unread message

Brandon Barker

unread,
Jul 17, 2015, 11:21:49 AM7/17/15
to scal...@googlegroups.com, semanticbeen...@gmail.com


On Sunday, February 22, 2015 at 9:28:39 AM UTC-5, Sébastien Doeraene wrote:
Hi,

On Sun, Feb 22, 2015 at 2:51 PM, SemanticBeeng . <semanticbeen...@gmail.com> wrote:
Hi, 

1. I expose a TypeScript API (not JS) since the rest of the client code is TypeScript.

That is irrelevant. You could have type parameters in TS and not in Scala.js, or vice versa, it would still work. Type parameters are only compile-time constructs, and disappear at runtime both with TS and Scala.js. Ultimately, the level at which TS and Scala.js communicate is the untyped JS.
 
2. "they are all supposed to be implemented in js.
Hmm... what is the underlying reason for forcing this?
I can see situations where ScalaJS apis exposed to JavaScript would want to return native JS objects but also mix-in other stuff from the ScalaJS side of the API.

Is there a way to do this "mix-in" today better than my attempt?
Any idea why it throws the error in the PromiseT constructor? If it did not then I could do the "mixing" from the ScalaJS side... 

I understand ScalaJS is meant to change the world of JS development but practically they will coexist.
So maybe we should consider and provide some attention to this co-habitation?

This is a fundamental limitation of Scala.js, as it currently stands. It is impossible to write a Scala.js class that extends/implements a JS type, because that extension causes said class to be a facade type itself. You can write Scala.js classes that export members, so that they (implicitly) comply with a JS interface. Then you can soundly cast your Scala.js class to the JS interface. But the compiler will not be able to help you.

Would it be reasonable to have a "@JSNoExport" option? My current use case is also for wrappers, although somewhat simpler in nature for now: I simply want to tack on some utility functions and not expose members of the JavaScript class that really shouldn't be exposed, while providing safe getters/evaluators to Scala-JS.

Certainly I can live without these, and since it is Scala, I guess I have a number of options of where to put the helper functions, though it would still leave the original class interface exposed. I tried to use mixins but failed - not sure if that would be any better for scala-js though, since you'd still be extending the JS class in some fashion with Scala-only functions.

 
 
4. Is there anything special or better to do with the execution context to make this combine promises work?
I need to have this working from both real browser in prod but also native jasmine tests in PhantomJS.

JQueryDeferred don't use execution contexts (necessarily), so no.
 
5. So should I add type params to https://github.com/scala-js/scala-js-jquery?
Is it as simple as adding the type params?

Yes, it is as simple as that. As I said, type parameters disappear at runtime.

Cheers,
Sébastien

Brandon Barker

unread,
Jul 17, 2015, 11:23:10 AM7/17/15
to scal...@googlegroups.com
Disregard the last part of my comments about mixins; i see this was addressed already.

On Sunday, January 11, 2015 at 11:33:44 PM UTC-5, SemanticBeeng wrote:
Hi,

I am looking to use ScalaJS to develop a business API called from a web application using Durandal and Knockout. The command layer calling the API will use promises/futures to communicate with the rest of the application.

(more elaborate architectural description at the end to qualify questions below)

So am trying to determine what is the best way to write this layer driven by "executable specifications".

Found some references to ScalaJS support for async/promises but cannot quite tell which way to go.
Below I ask some questions to better understand the plans for ScalaJS, utest and seek some recommendations.

1. "The Jasmine test framework is not a good testing framework for Scala.js code, and is being removed in 0.6.x."


Q: Where can I learn more about this and understand why Jasmine is bad for ScalaJS testing?
JavaScript has impressive support for testing async code with promises: chai as promised, sinon.js, jasmine, mocha, etc 

What does "bad" mean in terms of one being able to use this existing support?

-------------------------------------------------------

2. utest seems to support async tests 


Q: Does utest mean to provide full support for promises?

Would one be able to use native JavaScript promise support to test JSExported shared APIs?
From utests? 
From other kinds of tests?

Or does "bad" in the above definition means that this is not a good idea?

-------------------------------------------------------

3. ScalaJS has support for scala Futures (scala.concurrent.Future)

References 

Q: Does utest mean to support testing such APs?

-------------------------------------------------------
4. Autowire also uses Futures.

Q: Does utest support testing such APIs? Any examples handy?

Finally

Q: Can you please suggest some material to better understand how to BDD this ScalaJS based command layer that specifies the semantics of the shared business API given that it needs to be specified with "promises" (see [1])?

=======

(context for questions)

The overall architecture uses CQRS and the calls to this business API will be using some form of command pattern. 

At this level it is customary to use "promises". 
Durandal and the rest of the application can use Q.JS (https://github.com/kriskowal/q) because they are a more standard implementation (https://blog.domenic.me/youre-missing-the-point-of-promises/).

I could write this whole command layer in ScalaJS or in TypeScript and call JSExported methods from the business API.

Regardless, I need this command layer to return Q.js promises to the rest of the application. [1]

To implement this layer I am considering using Autowire but Play! makes much of it unnecessary. 
Thinking to reuse the shared API to wrap the JavaScript routes generated by Play! instead. 
This is supposed to provide even better typesafety than AutoWire because the Ajax calls itself will no longer be handcrafted like with AutoWire.

(end of context)


Sébastien Doeraene

unread,
Jul 17, 2015, 11:27:13 AM7/17/15
to Brandon Barker, scal...@googlegroups.com
Hi,

I don't understand what you want or what you're trying to achieve? Could you elaborate, possibly on the basis of some (idealized) snippet of code?

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.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-js/024aec1a-61b2-48e7-8399-f060397525e0%40googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Brandon Barker

unread,
Jul 17, 2015, 11:35:47 AM7/17/15
to scal...@googlegroups.com, brandon...@gmail.com
Sure, thanks - I had in mind something like this:

@JSName("L.Popup")
class Popup(options: js.Object = null) extends Layer {

 
def openOn(map: MapBoxMap): Popup = js.native

  def setLatLng(latlng: js.Array[Double]): Popup = js.native

  def setContent(content: String): Popup = js.native

  //
  protected var _map: MapBoxMap = js.native

  @JSNoExport
 
def hasMap(): Boolean = if (_map == null) false else true

}

There are probably some Scala patterns I'm unaware of to do something similar.

Brandon Barker

unread,
Jul 17, 2015, 11:39:35 AM7/17/15
to scal...@googlegroups.com, Brandon Barker
This might be a bad idea at any rate, since I realized that you might
get things that would typecheck but not compile as a result.
--
Brandon Barker
brandon...@gmail.com

Sébastien Doeraene

unread,
Jul 17, 2015, 11:44:49 AM7/17/15
to Brandon Barker, scal...@googlegroups.com
Ah! I think what you want is extension methods, which you can get with an implicit class:

implicit class PopupExtension(val self: Popup) extends AnyVal {
  def hasMap(): Boolean =
    if (self._map == null) false else true
    // which is equivalent to `self._map != null`, mind you ;-)
}

That has nothing to do with exports. Exports are exposing Scala methods (in Scala classes) to JS. Here you're adding Scala method helpers to a JS class *for use by Scala*, not by JS.

Cheers,
Sébastien

Brandon Barker

unread,
Jul 17, 2015, 5:09:09 PM7/17/15
to Sébastien Doeraene, scal...@googlegroups.com
Awesome, I can see this is a great thing to know about. Thanks for the logic tip, though I think the JS logic is proving to be a more serious barrier. In the API source they do things like:

if (this._map) ....

I tried a couple of things, below, to get at the right logic. The first, commented out, was to try to test every possible way (if this._map) might be false. Maybe I missed some, haha. The second, I tried to do based on your stack overflow post, but I must be doing something not quite right, since I get a type mismatch between Bolean and js.Dynamic.



  //var _map: Any = js.native
  var _map: js.Dynamic = js.native

}

object Helpers {

  implicit class PopupExtension(val self: Popup) extends AnyVal {
    /*def hasMap(): Boolean = self._map match {
      case m: Unit => {println("false"); false}
      case m: Boolean if !m => {println("false"); false}
      case m: Int if m == 0 =>  {println("false"); false}
      case m: Any if m == null =>  {println("false"); false}
      case _ =>  {println("true"); true}
    }*/
    def hasMap(): Boolean = if (self._map) true else false
  }
}




--
Brandon Barker
brandon...@gmail.com

Justin du coeur

unread,
Jul 17, 2015, 6:03:46 PM7/17/15
to Brandon Barker, Sébastien Doeraene, scal...@googlegroups.com
On Fri, Jul 17, 2015 at 5:08 PM, Brandon Barker <brandon...@gmail.com> wrote:
Awesome, I can see this is a great thing to know about. Thanks for the logic tip, though I think the JS logic is proving to be a more serious barrier. In the API source they do things like:

if (this._map) ....

Hmm.  Are you sure you're interpreting this correctly?  This is a common JavaScript idiom for "if the field _map *exists* on this".  That is, it isn't checking for false, it's checking for undefined.  It looks weird from the Scala POV, but it makes sense in a dynamic language like JS, where the existence of any field is kind of a crapshoot.

I don't know the code, so this is just a guess, but that would usually be the way I'd read such a line... 

Sébastien Doeraene

unread,
Jul 17, 2015, 6:16:42 PM7/17/15
to Justin du coeur, Brandon Barker, scal...@googlegroups.com
No Brendon is right: `if (this._map)` tests whether `this._map` is falsy.
To test that according to JS semantics, you can use

js.DynamicImplicits.truthValue(self._map.asInstanceOf[js.Dynamic])

which returns false if and only if `self._map` is falsy. This pattern should typically be avoided in Scala code, unless transliterating from JS.

Cheers,
Sébastien

Brandon Barker

unread,
Jul 17, 2015, 7:26:57 PM7/17/15
to Sébastien Doeraene, Justin du coeur, scal...@googlegroups.com
Many thanks - that did the trick. I now have converted a moderate sized mapbox page over to using Scala-JS. Now to refactor and start to move the API out of the project!
--
Brandon Barker
brandon...@gmail.com
Reply all
Reply to author
Forward
0 new messages