- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
widenIfNecessary behaves differently for val and def
Wed, 2011-02-16, 14:44
For methods, the type gets widened from "a.type" (SingleType) to "object a" (TypeRef to the module class).Is this expected? Why?
scala> object adefined module a
scala> ares5: a.type = a$@6162db76
scala> val x = ax: a.type = a$@6162db76
scala> def f = af: object a
Thu, 2011-02-17, 13:57
#2
Re: Re: widenIfNecessary behaves differently for val and def
There are two questions in here. The first one is about the types that denote objects:
"a.type" (t1) is the singleton type for object a.
"object a" (t2) is the string representation of a TypeRef to the module class of "a". This typecan't be expressed in source syntax.
calling "widen" on (t1) yields (t2).
(t1) <:< (t2) is true(t2) <:< (t1) is false
I'm not sure if things are supposed to be like that. Adriaan mentioned to me, a TypeRef to amodule class also denotes one single object, so in principle it's not a more general type.
The second question is why "widenIfNecessary" behaves differently on "val" and "var / def".Well, I can understand that it doesn't make sense to keep a singleton type on a "var", since you would only be allowed to re-assign to the same value. But for def's?
The reason why my example uses an "object" is that it's hard to obtain a singleton typeotherwise. The "stabilize" method in the type checker creates a singleton type only if the expected type is a singleton, or if the selected symbol is an object. Example:
val x = new Object x // type checker infers type "Object", not "x.type"
Lukas
On Thu, Feb 17, 2011 at 13:27, Jesper Nordenberg <megagurka@gmail.com> wrote:
"a.type" (t1) is the singleton type for object a.
"object a" (t2) is the string representation of a TypeRef to the module class of "a". This typecan't be expressed in source syntax.
calling "widen" on (t1) yields (t2).
(t1) <:< (t2) is true(t2) <:< (t1) is false
I'm not sure if things are supposed to be like that. Adriaan mentioned to me, a TypeRef to amodule class also denotes one single object, so in principle it's not a more general type.
The second question is why "widenIfNecessary" behaves differently on "val" and "var / def".Well, I can understand that it doesn't make sense to keep a singleton type on a "var", since you would only be allowed to re-assign to the same value. But for def's?
The reason why my example uses an "object" is that it's hard to obtain a singleton typeotherwise. The "stabilize" method in the type checker creates a singleton type only if the expected type is a singleton, or if the selected symbol is an object. Example:
val x = new Object x // type checker infers type "Object", not "x.type"
Lukas
On Thu, Feb 17, 2011 at 13:27, Jesper Nordenberg <megagurka@gmail.com> wrote:
Related discussion: http://www.scala-lang.org/node/1499
I can't say I got any wiser from that though.
/Jesper Nordenberg
On 16 Feb, 14:43, Lukas Rytz <lukas.r...@epfl.ch> wrote:
> For methods, the type gets widened from "a.type" (SingleType) to "object a"
> (TypeRef to the module class).
> Is this expected? Why?
>
> scala> object a
> defined module a
>
> scala> a
> res5: a.type = a$@6162db76
>
> scala> val x = a
> x: a.type = a$@6162db76
>
> scala> def f = a
> f: object a
Fri, 2011-02-25, 21:17
#3
Re: Re: widenIfNecessary behaves differently for val and def
To make sure I didn't introduce any surprises, I've now confirmed the
only non-cosmetic change to widenIfNecessary in the last two years (it
was called widenIfNotFinal way back then) is as follows, the last lines
of the method:
- else if (!(sym hasFlag FINAL)) tpe1
- else tpe
+ else if (sym.isFinal || sym.isLocal) tpe
+ else tpe1
In other words, it doesn't widen local symbols. I made this change so
that code like this:
def f(x: Int) = {
val X = 1
val Y = 2
x match { case X => 1 ; case Y => 2 } }
}
would compile to a switch. So it is unrelated to the questions at hand,
and I'll take a stab at those too:
> "a.type" (t1) is the singleton type for object a.
>
> "object a" (t2) is the string representation of a TypeRef to the
> module class of "a". This type can't be expressed in source syntax.
>
> calling "widen" on (t1) yields (t2).
>
> (t1) <:< (t2) is true (t2) <:< (t1) is false
>
> I'm not sure if things are supposed to be like that.
It is my understanding that it is intentional at least in terms of the
intent at the time. Whether "object X" needs to continue to turn up as
it presently does is not so clear to me. If we ignore null, the
inhabitants of "object X" and "x.type" are the same, so I don't know
what gain is to be had from the subtype relationship.
To the extent I understand things, object X at this point is strictly an
artifact of the implementation and we should be doing what we can to
keep it out of the user-visible universe.
> The second question is why "widenIfNecessary" behaves differently on
> "val" and "var / def".
When it was first introduced the method was called "deconstIfNotFinal"
and it was only called on ValDefs. So it's not hard to imagine it has
historical characteristics which could be modified.
I don't know why "object x ; def f = x" couldn't infer x.type for f.
It'd certainly be an improvement from where I sit.
Related discussion: http://www.scala-lang.org/node/1499
I can't say I got any wiser from that though.
/Jesper Nordenberg
On 16 Feb, 14:43, Lukas Rytz wrote:
> For methods, the type gets widened from "a.type" (SingleType) to "object a"
> (TypeRef to the module class).
> Is this expected? Why?
>
> scala> object a
> defined module a
>
> scala> a
> res5: a.type = a$@6162db76
>
> scala> val x = a
> x: a.type = a$@6162db76
>
> scala> def f = a
> f: object a