In Scala.js 1.0, js.eval returns scala.Any instead of js.Any
See original GitHub issueIn the 0.6.x branch it returns js.Any
.
Issue Analytics
- State:
- Created 3 years ago
- Comments:8 (8 by maintainers)
Top Results From Across the Web
Scala.js 1.0.0-M6 - scala.scalajs.js
This package is only relevant to the Scala.js compiler, and should not be referenced by any project compiled to the JVM. Guide. General...
Read more >Scala.js 1.0.0 - scala.scalajs.js.Function
The bind() method creates a new function that, when called, has its this keyword set to the provided value, with a given sequence...
Read more >Announcing Scala.js 1.0.0-RC1
We are thrilled to announce the release of Scala.js 1.0.0-RC1! ... If no critical issue is found until the end of January 2020, ......
Read more >Announcing Scala.js 1.0.0
We are thrilled to announce the General Availability release of Scala.js 1.0.0! Scala.js is a close dialect of Scala compiling to JavaScript, ...
Read more >Any - extends AnyRef - Scala.js
A JavaScript type that is annotated with @js.native is a facade type to APIs implemented in JavaScript code. Its implementation is irrelevant and...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
Ah, I believe you’ve misunderstood the nature of
js.Any
, which is quite understandable since I had myself misunderstood it for years. Let me try to explain from first principles.In Scala/JVM
First, let’s look at the top of the Scala hierarchy:
Any
(if I writeAny
, it always meansscala.Any
; I writejs.Any
explicitly) is the top type of the Scala type system. No class can directly extend it butAnyVal
andAnyRef
.AnyVal
andAnyRef
form a partition of all the classes in the Scala type system. Depending on which one any given classC
inherits from,C
features different fundamental semantics:AnyVal
s are value classes; they do not have an identity, cannot be compared by referenceAnyRef
s are reference classes; they have an identity and can be compared by referenceIf you look at how one uses
AnyVal
andAnyRef
in Scala, it is almost exclusively inextends
clauses. Their use in anextends
clause likeis to give
C
the specific semantics ofAnyVal
.AnyRef
appears less often in typical code because it is the default, but if weren’t, it would be used in the same way.You’re not primarily extending
AnyVal
orAnyRef
because you want to be a subtype of those almost-top types. You’re doing it because you want the semantics that are associated with their respective hierarchies.More glaring: you never use
AnyVal
andAnyRef
as the type of a variable or a parameter. At best, you use a type parameterT <: AnyRef
if you want the capability to compareT
s by reference.Now comes
js.Any
In Scala.js, we have a third almost-top type beside
AnyVal
andAnyRef
:js.Any
:Although
js.Any
is declared as atrait
for technical reasons, there are compile-time checks that make sure that there cannot be a classC
that inherits both fromjs.Any
andAnyVal
orAnyRef
(with the exception of directly extendingAnyRef
, again for technical reasons related to how much we can convince the compiler to do what we want, and how much it constrains us).So now we have 3 almost-top classes
AnyVal
,AnyRef
andjs.Any
, forming a partition of all the classes in the Scala.js type system.Just like
AnyVal
andAnyRef
are providing specific semantics to their subtrees, so doesjs.Any
: classes inheriting fromjs.Any
have JavaScript semantics. They resolve overloads at run-time rather than compile-time, their non-private members are visible from JavaScript, they have a first-class class value (js.constructorOf[C]
), etc.Just like
AnyVal
andAnyRef
, the main usejs.Any
in code is inC extends js.Any
clauses, to associateC
with JavaScript semantics. We don’t primarily usejs.Any
for the subtyping relationship, and we almost never give the exact typejs.Any
to variables, parameters or result types, because there’s nothing you can do with ajs.Any
.An exception, like
T <: AnyRef
, is to useT <: js.Any
, when for some reason we needT
to have JavaScript semantics (e.g., if we need ajs.ConstructorTag[C]
, which only makes sense ifC
has JS semantics).What I still consider confusing
There’s one thing in the core library that contradicts the principles laid above:
js.Dynamic
. The API ofjs.Dynamic
takesjs.Any
s as inputs for all the parameters, even though I said above that we should basically never usejs.Any
as the type of a parameter.TBH, it’s a hack. We could use
scala.Any
s there, and in a sense we should, but we’re usingjs.Any
to force implicit conversions to kick in, so that simple-looking code works (usually). For example, you can give a lambda to ajs.Dynamic
method, and it will be implicitly converted to the appropriatejs.FunctionN
. That wouldn’t happen if it took ascala.Any
.Essentially, the use of
js.Any
injs.Dynamic
is a DSL-like hack, which we need because we don’t have better types. You shouldn’t copy that idiom in statically typed APIs.Addressing some of your direct comments/suggestions
Now that you hopefully have a clearer picture of the design as I see it, here are some answers to your comments and suggestions.
Absolutely. And that is why one should virtually never use
js.Any
as a type for parameters and result types. We should always usescala.Any
instead, which is the true top type of the Scala.js type system.The way of thinking is about the semantics: JS types have JS semantics (run-time overloading, etc.) which definitely does not cover Scala types, which have Scala semantics (compile-time overloading, etc.).
I believe the explanation on semantics covers why that would not be appropriate.
js.Native
would clearly be wrong, since there are non-native classes that extendjs.Any
: anything that’s not annotated with@js.native
is non-native. Being native or not is not an inherited property (otherwise we could never extend a native class from a non-native one).True 😅