1

JavaScript short-circuit evaluation is commonly used to e.g. deal with browser incompatibilities:

var scrollPosition =
  window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0

What's the idiomatic way to write this in Scala.js?

Community
  • 1
  • 1
Rahel Lüthy
  • 6,837
  • 3
  • 36
  • 51

2 Answers2

4

A contrario @gurghet's answer, IMO the most idiomatic version is to adopt JavaScript's idiom right into Scala.js. After all, you are exploiting the dynamic nature of JavaScript anyway, so you might as well be explicit about it. You can do that with js.Dynamic:

import scala.scalajs.js
import js.Dynamic.{global => g}

def scrollPosition: Double = {
  import js.DynamicImplicits._ // to "write JavaScript"
  val pos = g.window.pageYOffset || g.document.documentElement.scrollTop || g.document.body.scrollTop || 0
  pos.asInstanceOf[Double]
}
sjrd
  • 21,805
  • 2
  • 61
  • 91
  • Thank you, `js.DynamicImplicits` was the missing piece! – Rahel Lüthy Sep 05 '16 at 12:06
  • Although I like this flexibility, wouldn't it be dangerous this code? I mean that you are taking a plain value from Javascript which could, in an extreme case, cause a run-time exception. – pietro909 Sep 06 '16 at 08:45
  • @pietro909 Well, that's ultimately *always* what you do when you're fetching any kind of value from JavaScript. By your argument, calling any JavaScript library is unsafe and should be prohibited. – sjrd Sep 06 '16 at 11:08
  • @sjrd not so far: you can still do that, just don't cast it using a method like `asInstanceOf` as it could fail at runtime. In this example, for `g.window.pageYOffset = "12"` (which in JS can happen) the function will try to perform `"12".asInstanceOf[Double]` throwing a `java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Double`. I'd rather use a `try` block or explicitly manage the edge cases. – pietro909 Sep 06 '16 at 13:50
1

I think you are better off thinking in regular scala for this one.

In particular, if you are relying on the cast of 0 to a boolean, this is a bad practice, not per se, but because you rely on implicit casting as rarely as possible and preferably when it does not change the semantic type.

I would rewrite your assignment in a more expressive way

var scrollPosition =
  if (window.pageYoffset > 0) {
    window.pageYoffset
  } else if (document.documentElement.scrollTop > 0) {
    document.documentElement.scrollTop
  } else if (document.body.scrollTop > 0) {
    document.body.scrollTop
  } else {
    0
  }

I can make it even more expressive using a match case or by giving a meaning to intermediate steps.

gurghet
  • 7,591
  • 4
  • 36
  • 63
  • I prefer this conservative approach, nonetheless, I find it quite verbose and ugly. – pietro909 Sep 06 '16 at 08:46
  • You can make it less ugly *and* more expressive, probably knowing why you want to do that. It depends on the context, what I wrote is the bare minimun. – gurghet Sep 06 '16 at 14:02