- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
using this.type
Mon, 2012-01-30, 00:06
I have a class called Scalar, which represents physical scalars (physical quantities with units). It has fields called "num" for the quantity and "units" for the physical units. It has a "+" method that looks something like this (slightly simplified here):
def + (that: Scalar): Scalar = {
checkUnits(that)
new Scalar(num + that.num, units)
}
Now suppose I decide that I want to extend Scalar to create specific types of Scalars, such as Time, Length, etc., so I do this:
case class Time(s: Scalar) extends Scalar(s)
I don't want to get into a general discussion here of the static type checking for units, but it occurred to me that I might be able to get at least some static checking. The problem is that my + method returns a Scalar, not a Time. So I changed it to this:
def + (that: this.type): this.type = {
checkUnits(that)
new Scalar(num + that.num, units).asInstanceOf[this.type]
}
However, this causes all sorts of compilation errors, such as
[error] ACmodels.scala:438: type mismatch;
[error] found : dt.type (with underlying type scalar.package.Scalar)
[error] required: _1.type where val _1: scalar.package.Scalar
[error] val time1 = time + dt
I don't understand this. It's telling me there's a type mismatch, but both types are scalar.package.Scalar. Is this a compiler bug? Is there a way to do this sort of thing? Thanks.
--Russ P.
--
http://RussP.us
def + (that: Scalar): Scalar = {
checkUnits(that)
new Scalar(num + that.num, units)
}
Now suppose I decide that I want to extend Scalar to create specific types of Scalars, such as Time, Length, etc., so I do this:
case class Time(s: Scalar) extends Scalar(s)
I don't want to get into a general discussion here of the static type checking for units, but it occurred to me that I might be able to get at least some static checking. The problem is that my + method returns a Scalar, not a Time. So I changed it to this:
def + (that: this.type): this.type = {
checkUnits(that)
new Scalar(num + that.num, units).asInstanceOf[this.type]
}
However, this causes all sorts of compilation errors, such as
[error] ACmodels.scala:438: type mismatch;
[error] found : dt.type (with underlying type scalar.package.Scalar)
[error] required: _1.type where val _1: scalar.package.Scalar
[error] val time1 = time + dt
I don't understand this. It's telling me there's a type mismatch, but both types are scalar.package.Scalar. Is this a compiler bug? Is there a way to do this sort of thing? Thanks.
--Russ P.
--
http://RussP.us
Mon, 2012-01-30, 02:51
#2
Re: using this.type
> def + (that: this.type): this.type = {
>
> checkUnits(that)
> new Scalar(num + that.num, units).asInstanceOf[this.type]
> }
This signature doesn't make sense, and it is dangerous. As Rex pointed
out, if a value has type `p.type`, then the value *is* `p`, and it is
the only value of `p.type`. So, don't cast something to `this.type`.
The usual approach for what you want to do is:
trait Super[Self <: Super] {
def +(that: Self)
}
trait Sub extends Super[Sub] {
//...
}
(You could also have `Self` as a type member instead.)
Mon, 2012-01-30, 03:01
#3
Re: using this.type
Thanks, Rex, but I'd still like to know if there is a way to get what
I want. I realize that I can override the + method (and other similar
methods) for the Time class and every other such class that I decide
to create, but that would involve a lot of repetition. Is that what I
need to do? It would be much better to be able to handle it once and
for all in the Scalar class. Is that possible?
--Russ P.
On Jan 29, 4:14 pm, Rex Kerr wrote:
> this.type is not a MyType, it is the unique type of that single
> instantiated copy of that class.
>
> Thus, taking it as a parameter is a bit weird, since you already have it,
> since you're in one of its methods! (If a parameter has type this.type,
> then the value of that parameter is guaranteed to be this.)
>
> Scala doesn't have a MyType facility which, roughly speaking, would match
> what this.getClass would show.
>
> --Rex
>
> On Sun, Jan 29, 2012 at 6:06 PM, Russ Paielli wrote:
>
>
>
>
>
>
>
> > I have a class called Scalar, which represents physical scalars (physical
> > quantities with units). It has fields called "num" for the quantity and
> > "units" for the physical units. It has a "+" method that looks something
> > like this (slightly simplified here):
>
> > def + (that: Scalar): Scalar = {
>
> > checkUnits(that)
> > new Scalar(num + that.num, units)
> > }
>
> > Now suppose I decide that I want to extend Scalar to create specific types
> > of Scalars, such as Time, Length, etc., so I do this:
>
> > case class Time(s: Scalar) extends Scalar(s)
>
> > I don't want to get into a general discussion here of the static type
> > checking for units, but it occurred to me that I might be able to get at
> > least some static checking. The problem is that my + method returns a
> > Scalar, not a Time. So I changed it to this:
>
> > def + (that: this.type): this.type = {
>
> > checkUnits(that)
> > new Scalar(num + that.num, units).asInstanceOf[this.type]
> > }
>
> > However, this causes all sorts of compilation errors, such as
>
> > [error] ACmodels.scala:438: type mismatch;
> > [error] found : dt.type (with underlying type scalar.package.Scalar)
> > [error] required: _1.type where val _1: scalar.package.Scalar
> > [error] val time1 = time + dt
>
> > I don't understand this. It's telling me there's a type mismatch, but both
> > types are scalar.package.Scalar. Is this a compiler bug? Is there a way to
> > do this sort of thing? Thanks.
>
> > --Russ P.
>
> > --
> >http://RussP.us
Mon, 2012-01-30, 09:01
#4
Re: Re: using this.type
Yes its possible, if not a bit boilerplatey:
http://code.google.com/p/scala-scales/wiki/VirtualConstructorPreSIP
It can't yet be implemented via a compiler plugin (the lensed approach via sbt could be doable though) so its all manual I'm afraid.
On Jan 30, 2012 2:42 AM, "Russ P." <russ.paielli@gmail.com> wrote:Thanks, Rex, but I'd still like to know if there is a way to get what
I want. I realize that I can override the + method (and other similar
methods) for the Time class and every other such class that I decide
to create, but that would involve a lot of repetition. Is that what I
need to do? It would be much better to be able to handle it once and
for all in the Scalar class. Is that possible?
--Russ P.
On Jan 29, 4:14 pm, Rex Kerr <icho...@gmail.com> wrote:
> this.type is not a MyType, it is the unique type of that single
> instantiated copy of that class.
>
> Thus, taking it as a parameter is a bit weird, since you already have it,
> since you're in one of its methods! (If a parameter has type this.type,
> then the value of that parameter is guaranteed to be this.)
>
> Scala doesn't have a MyType facility which, roughly speaking, would match
> what this.getClass would show.
>
> --Rex
>
> On Sun, Jan 29, 2012 at 6:06 PM, Russ Paielli <russ.paie...@gmail.com>wrote:
>
>
>
>
>
>
>
> > I have a class called Scalar, which represents physical scalars (physical
> > quantities with units). It has fields called "num" for the quantity and
> > "units" for the physical units. It has a "+" method that looks something
> > like this (slightly simplified here):
>
> > def + (that: Scalar): Scalar = {
>
> > checkUnits(that)
> > new Scalar(num + that.num, units)
> > }
>
> > Now suppose I decide that I want to extend Scalar to create specific types
> > of Scalars, such as Time, Length, etc., so I do this:
>
> > case class Time(s: Scalar) extends Scalar(s)
>
> > I don't want to get into a general discussion here of the static type
> > checking for units, but it occurred to me that I might be able to get at
> > least some static checking. The problem is that my + method returns a
> > Scalar, not a Time. So I changed it to this:
>
> > def + (that: this.type): this.type = {
>
> > checkUnits(that)
> > new Scalar(num + that.num, units).asInstanceOf[this.type]
> > }
>
> > However, this causes all sorts of compilation errors, such as
>
> > [error] ACmodels.scala:438: type mismatch;
> > [error] found : dt.type (with underlying type scalar.package.Scalar)
> > [error] required: _1.type where val _1: scalar.package.Scalar
> > [error] val time1 = time + dt
>
> > I don't understand this. It's telling me there's a type mismatch, but both
> > types are scalar.package.Scalar. Is this a compiler bug? Is there a way to
> > do this sort of thing? Thanks.
>
> > --Russ P.
>
> > --
> >http://RussP.us
Mon, 2012-01-30, 15:21
#5
RE: Re: using this.type
See recent posting by Paul - the compiler knows but it isn't telling!
http://comments.gmane.org/gmane.comp.lang.scala.debate/8570
> Date: Sun, 29 Jan 2012 17:42:43 -0800
> Subject: [scala-user] Re: using this.type
> From: russ.paielli@gmail.com
> To: scala-user@googlegroups.com
>
> Thanks, Rex, but I'd still like to know if there is a way to get what
> I want. I realize that I can override the + method (and other similar
> methods) for the Time class and every other such class that I decide
> to create, but that would involve a lot of repetition. Is that what I
> need to do? It would be much better to be able to handle it once and
> for all in the Scalar class. Is that possible?
>
> --Russ P.
> Date: Sun, 29 Jan 2012 17:42:43 -0800
> Subject: [scala-user] Re: using this.type
> From: russ.paielli@gmail.com
> To: scala-user@googlegroups.com
>
> Thanks, Rex, but I'd still like to know if there is a way to get what
> I want. I realize that I can override the + method (and other similar
> methods) for the Time class and every other such class that I decide
> to create, but that would involve a lot of repetition. Is that what I
> need to do? It would be much better to be able to handle it once and
> for all in the Scalar class. Is that possible?
>
> --Russ P.
Thus, taking it as a parameter is a bit weird, since you already have it, since you're in one of its methods! (If a parameter has type this.type, then the value of that parameter is guaranteed to be this.)
Scala doesn't have a MyType facility which, roughly speaking, would match what this.getClass would show.
--Rex
On Sun, Jan 29, 2012 at 6:06 PM, Russ Paielli <russ.paielli@gmail.com> wrote: