0

Running the following Scala code compiled into scala-js version 0.8.0, I get the following error:
An undefined behavior was detected: undefined is not an instance of java.lang.String

trait MyDataType extends js.Any {
  var wordy: String = js.native
}
// This usually comes from the backend.
val dataStruct = js.Dynamic.literal().asInstanceOf[MyDataType]
val isWordy = dataStruct.wordy

Scala-js fiddle (press CTRL+ENTER)

After investigation, the code above is compiled as:

var dataStruct = {};
var isWordy  = $as_T(dataStruct["wordy"]); // Line causing problem.

Obviously it is because of this $as_T which causes this trouble. How can I make sure that the code above is unchecked ?

Edit I found a workaround which is not very elegant.

val isWordy = dataStruct.asInstanceOf[js.Dynamic].wordy

But still, why this $as_T ?

Mikaël Mayer
  • 10,425
  • 6
  • 64
  • 101

1 Answers1

4

I think the question is the wrong way around. Saying asInstanceOf[MyDataType] is telling Scala to typecheck it. That's almost exactly what that means. And when it typechecks, it typechecks completely: you are telling Scala.js that this is an instance of MyDataType, and therefore it must completely conform to MyDataType.

So if you really don't want it type-checked, the correct solution is simply to leave off the asInstanceOf. At that point it's a JavaScript dynamic, and you can do essentially anything with it.

(Or you need to assign something to wordy inside of literal(), so that it is actually MyDataType.)

In other words, Scala.js has its feet in two worlds: the untyped JavaScript and the strongly-typed Scala. Both work well, but at any given time you have to choose which one you're operating in.

ETA: a bit of rationale. The whole point of a strongly typed language is that everything in the code knows, with certainty, what the structure of the type is -- that way, you only have to worry about bugs in your code, not bad data. That's why asInstanceOf needs to be hard-assed: so that, if you pass the value to some function that expects MyDataType, it knows for certain that wordy is defined.

Justin du Coeur
  • 2,699
  • 1
  • 14
  • 19
  • 1
    In addition, an alternative solution to your problem is to fix `MyDataType` so that it encodes the fact that `wordy` might not be there. To do this, type it as `var wordy: js.UndefOr[String]`. In that case, your test becomes `val isWordy = dataStruct.wordy.isDefined`. – sjrd Aug 13 '15 at 06:57
  • Thank you Seb, that's exactly what I was looking for. – Mikaël Mayer Aug 13 '15 at 07:28