- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Strange trait stacking issue
Mon, 2009-03-16, 08:19
Hi, I ran into a strange trait stacking issue lately. It definitely
unexpected to me, but I can't tell whether it's a bug or a feature. I
have trait T the modifies the way toString works, but it does not seem
to work stack on the default toString method of case classes:
Consider the following code
object Main {
trait T { abstract override def toString:String = super.toString+"T" }
trait Base
case class B(i:Int) extends Base with T
def main(args: Array[String]) {
object y extends B(1)
println(y)
}
}
This program prints Main$y$2$@44c829c0T rather than B(1)T.
I am just curious what you think: this is I should expect or something
to be reported?
Mon, 2009-03-16, 11:17
#2
Re: Strange trait stacking issue
This works as expected:
case class B(i:Int) extends Base //with T
def main(args: Array[String]) {
object y extends B(1) with T
println(y)
}
}
It seems that the mix-in rules in class definitions is a bit different here, but I can't see a good reason for that, except that the abstract override is supposed to refer to an abstract definition in a super class. toString isn't abstract and I didn't manage to define a non-case class with T.
-Carsten
On Mon, Mar 16, 2009 at 8:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
case class B(i:Int) extends Base //with T
def main(args: Array[String]) {
object y extends B(1) with T
println(y)
}
}
It seems that the mix-in rules in class definitions is a bit different here, but I can't see a good reason for that, except that the abstract override is supposed to refer to an abstract definition in a super class. toString isn't abstract and I didn't manage to define a non-case class with T.
-Carsten
On Mon, Mar 16, 2009 at 8:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
Hi, I ran into a strange trait stacking issue lately. It definitely
unexpected to me, but I can't tell whether it's a bug or a feature. I
have trait T the modifies the way toString works, but it does not seem
to work stack on the default toString method of case classes:
Consider the following code
object Main {
trait T { abstract override def toString:String = super.toString+"T" }
trait Base
case class B(i:Int) extends Base with T
def main(args: Array[String]) {
object y extends B(1)
println(y)
}
}
This program prints Main$y$2$@44c829c0T rather than B(1)T.
I am just curious what you think: this is I should expect or something
to be reported?
Mon, 2009-03-16, 11:27
#3
Re: Strange trait stacking issue
When T calls super.toString, you're calling the toString defined on AnyRef (T's super), not the toString defined on case classes.
The first-cut approach to this would be to refer explicitly to the toString we want:
trait T { self =>
abstract override def toString: String = self.toString + "T"
}
Unfortunately this leads to a StackOverflowException. Probably a bug.
The next approach is to redefine it yourself, I'm afraid. This isn't hard once you know that all case classes implement Product, and Product has a few methods which might be helpful.
trait T extends Product {
override def toString: String =
(0 until productArity).map(productElement).mkString(productPrefix + "(", ", ", ")T")
}
It's not pretty, but that should do it.
--j
On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
The first-cut approach to this would be to refer explicitly to the toString we want:
trait T { self =>
abstract override def toString: String = self.toString + "T"
}
Unfortunately this leads to a StackOverflowException. Probably a bug.
The next approach is to redefine it yourself, I'm afraid. This isn't hard once you know that all case classes implement Product, and Product has a few methods which might be helpful.
trait T extends Product {
override def toString: String =
(0 until productArity).map(productElement).mkString(productPrefix + "(", ", ", ")T")
}
It's not pretty, but that should do it.
--j
On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
Hi, I ran into a strange trait stacking issue lately. It definitely
unexpected to me, but I can't tell whether it's a bug or a feature. I
have trait T the modifies the way toString works, but it does not seem
to work stack on the default toString method of case classes:
Consider the following code
object Main {
trait T { abstract override def toString:String = super.toString+"T" }
trait Base
case class B(i:Int) extends Base with T
def main(args: Array[String]) {
object y extends B(1)
println(y)
}
}
This program prints Main$y$2$@44c829c0T rather than B(1)T.
I am just curious what you think: this is I should expect or something
to be reported?
Mon, 2009-03-16, 11:37
#4
Re: Strange trait stacking issue
Hmmm, interesting. That's a strange rule, though, as toString is
always inherited from Any at least, but I see that overriding
downstream in the hierarchy really prevents automatic derivation...
Is this also true for equality and hashing?
>>
> No, this is as expected. Case class B does not implement its own
> toString method if one was inherited. In your case, it inherited a
> toString method from T.
>
> -- Martin
>
Mon, 2009-03-16, 11:47
#5
Re: Strange trait stacking issue
On Mon, Mar 16, 2009 at 9:45 AM, Jorge Ortiz wrote:
> When T calls super.toString, you're calling the toString defined on AnyRef
> (T's super), not the toString defined on case classes.
>
> The first-cut approach to this would be to refer explicitly to the toString
> we want:
>
> trait T { self =>
> abstract override def toString: String = self.toString + "T"
> }
>
> Unfortunately this leads to a StackOverflowException. Probably a bug.
No bug. For me this is just plain recursive...
Mon, 2009-03-16, 12:57
#6
Re: Strange trait stacking issue
Jorge, I'm not sure you're correct here:
trait A {
scala> trait x { override def toString : String = super.toString }
defined trait x
scala> case class y(myInt : Int) extends x
defined class y
scala> y(5)
res0: y = y@76d50842
scala> val z = y(5)
z: y = y@76d50842
scala> z.toString
res1: String = y@76d50842
scala> case class A(myInt : Int)
defined class A
scala> val b = new A(5) with x
b: A with x = A(5)
scala> b.toString
res2: String = A(5)
scala>
On Mon, Mar 16, 2009 at 4:45 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
trait A {
def service(){ Console.print(“A”) }
}
trait B extends A {
def service(){ Console.print(“B”); super.service() }
}
trait C extends A {
def service() { Console.print(“C”); super.service() }
}
val x = new A with B with C
x.service() //Output CBA
The "super" defined in B + C should both point to A, but instead x.service correctly displays CBA. This means scala is "doing the right thing" with super calls + mixin. However if I change the implemntations of C and B to have super[A].service(); then it only displays "CA".
I beleive the issue is that when using Case classes, the toString method is not generated if it "already exists". In this case, it thinks the trait created the toString method.
See the following:
scala> trait x { override def toString : String = super.toString }
defined trait x
scala> case class y(myInt : Int) extends x
defined class y
scala> y(5)
res0: y = y@76d50842
scala> val z = y(5)
z: y = y@76d50842
scala> z.toString
res1: String = y@76d50842
scala> case class A(myInt : Int)
defined class A
scala> val b = new A(5) with x
b: A with x = A(5)
scala> b.toString
res2: String = A(5)
scala>
On Mon, Mar 16, 2009 at 4:45 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
When T calls super.toString, you're calling the toString defined on AnyRef (T's super), not the toString defined on case classes.
The first-cut approach to this would be to refer explicitly to the toString we want:
trait T { self =>
abstract override def toString: String = self.toString + "T"
}
Unfortunately this leads to a StackOverflowException. Probably a bug.
The next approach is to redefine it yourself, I'm afraid. This isn't hard once you know that all case classes implement Product, and Product has a few methods which might be helpful.
trait T extends Product {
override def toString: String =
(0 until productArity).map(productElement).mkString(productPrefix + "(", ", ", ")T")
}
It's not pretty, but that should do it.
--j
On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
Hi, I ran into a strange trait stacking issue lately. It definitely
unexpected to me, but I can't tell whether it's a bug or a feature. I
have trait T the modifies the way toString works, but it does not seem
to work stack on the default toString method of case classes:
Consider the following code
object Main {
trait T { abstract override def toString:String = super.toString+"T" }
trait Base
case class B(i:Int) extends Base with T
def main(args: Array[String]) {
object y extends B(1)
println(y)
}
}
This program prints Main$y$2$@44c829c0T rather than B(1)T.
I am just curious what you think: this is I should expect or something
to be reported?
Mon, 2009-03-16, 13:17
#7
Re: Strange trait stacking issue
Yeah, the relevant part of the spec is SLS 5.2.3
My first attempt was made under the (misguided) hope that case class's special toString was defined in the Product trait and was thus callable (with the proper prefix) even by case classes that override toString.
Is there any reason why ==, hashCode, and toString for case classes aren't defined in Product? Case classes that define their own would still override Product's implementation, and if a trait A is mixed in which defines one of these methods, the case class can automatically choose A's version.
Would this be a bad idea? Are there performance problems I'm missing?
--j
On Mon, Mar 16, 2009 at 4:54 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
My first attempt was made under the (misguided) hope that case class's special toString was defined in the Product trait and was thus callable (with the proper prefix) even by case classes that override toString.
Is there any reason why ==, hashCode, and toString for case classes aren't defined in Product? Case classes that define their own would still override Product's implementation, and if a trait A is mixed in which defines one of these methods, the case class can automatically choose A's version.
Would this be a bad idea? Are there performance problems I'm missing?
--j
On Mon, Mar 16, 2009 at 4:54 AM, Josh Suereth <joshua.suereth@gmail.com> wrote:
Jorge, I'm not sure you're correct here:
trait A {def service(){ Console.print(“A”) }
}
trait B extends A {
def service(){ Console.print(“B”); super.service() }
}
trait C extends A {
def service() { Console.print(“C”); super.service() }
}
val x = new A with B with C
x.service() //Output CBA
The "super" defined in B + C should both point to A, but instead x.service correctly displays CBA. This means scala is "doing the right thing" with super calls + mixin. However if I change the implemntations of C and B to have super[A].service(); then it only displays "CA".
I beleive the issue is that when using Case classes, the toString method is not generated if it "already exists". In this case, it thinks the trait created the toString method.
See the following:
scala> trait x { override def toString : String = super.toString }
defined trait x
scala> case class y(myInt : Int) extends x
defined class y
scala> y(5)
res0: y = y@76d50842
scala> val z = y(5)
z: y = y@76d50842
scala> z.toString
res1: String = y@76d50842
scala> case class A(myInt : Int)
defined class A
scala> val b = new A(5) with x
b: A with x = A(5)
scala> b.toString
res2: String = A(5)
scala>If you allow the case class to create the toString, then mixing them together later produces the desired result.
On Mon, Mar 16, 2009 at 4:45 AM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
When T calls super.toString, you're calling the toString defined on AnyRef (T's super), not the toString defined on case classes.
The first-cut approach to this would be to refer explicitly to the toString we want:
trait T { self =>
abstract override def toString: String = self.toString + "T"
}
Unfortunately this leads to a StackOverflowException. Probably a bug.
The next approach is to redefine it yourself, I'm afraid. This isn't hard once you know that all case classes implement Product, and Product has a few methods which might be helpful.
trait T extends Product {
override def toString: String =
(0 until productArity).map(productElement).mkString(productPrefix + "(", ", ", ")T")
}
It's not pretty, but that should do it.
--j
On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
Hi, I ran into a strange trait stacking issue lately. It definitely
unexpected to me, but I can't tell whether it's a bug or a feature. I
have trait T the modifies the way toString works, but it does not seem
to work stack on the default toString method of case classes:
Consider the following code
object Main {
trait T { abstract override def toString:String = super.toString+"T" }
trait Base
case class B(i:Int) extends Base with T
def main(args: Array[String]) {
object y extends B(1)
println(y)
}
}
This program prints Main$y$2$@44c829c0T rather than B(1)T.
I am just curious what you think: this is I should expect or something
to be reported?
Mon, 2009-03-16, 14:17
#8
Re: Strange trait stacking issue
2009/3/16 Jorge Ortiz :
> Yeah, the relevant part of the spec is SLS 5.2.3
>
> My first attempt was made under the (misguided) hope that case class's
> special toString was defined in the Product trait and was thus callable
> (with the proper prefix) even by case classes that override toString.
>
> Is there any reason why ==, hashCode, and toString for case classes aren't
> defined in Product?
I've been wondering the same myself and would strongly encourage them
being so. I would like to see case classes made less magic, and this
seems like a very good step towards that. They've been turned into too
much of a convenience "do everything" concept, and I'd like to see
them reclaimed more as a "just for pattern matching".
> Case classes that define their own would still override
> Product's implementation, and if a trait A is mixed in which defines one of
> these methods, the case class can automatically choose A's version.
>
> Would this be a bad idea? Are there performance problems I'm missing?
It does have one unfortunate performance implication of potentially
causing unneeded boxing. I believe case class hash codes already have
this problem, and this would add that to equality.
Mon, 2009-03-16, 16:57
#9
Re: Strange trait stacking issue
The problem is that the toString method is very often in the base
class, not the case class. For instance List has a toString method
defined. We don't want a synthetic toString (defined either in :: or
in Product2) override that.
Cheers
Mon, 2009-03-16, 22:17
#10
Re: Strange trait stacking issue
In the case of List and ::, List already inherits from Product. It can specifically override toString to use Collection's toString, not Product's.
In the hypothetical case of:
class A { override def toString = "A" }
case class B extends A
Then the desugaring should expand to:
class B extends A with Product {
override def toString = super[A].toString
...
}
Which implements the current special case logic of "don't add a toString if one is already defined", except it's implemented in Scala rather than compiler magic.
This has the advantage of someone like Christian being able to come along and say:
class A extends Product { override def toString = super[Product].toString + "A" }
case class B extends A
which gets desugared to:
class B extends A with Product
and the current rules for mixin inheritance just do the right thing, with no need for more special cases.
--j
On Mon, Mar 16, 2009 at 8:40 AM, martin odersky <martin.odersky@epfl.ch> wrote:
In the hypothetical case of:
class A { override def toString = "A" }
case class B extends A
Then the desugaring should expand to:
class B extends A with Product {
override def toString = super[A].toString
...
}
Which implements the current special case logic of "don't add a toString if one is already defined", except it's implemented in Scala rather than compiler magic.
This has the advantage of someone like Christian being able to come along and say:
class A extends Product { override def toString = super[Product].toString + "A" }
case class B extends A
which gets desugared to:
class B extends A with Product
and the current rules for mixin inheritance just do the right thing, with no need for more special cases.
--j
On Mon, Mar 16, 2009 at 8:40 AM, martin odersky <martin.odersky@epfl.ch> wrote:
The problem is that the toString method is very often in the base
class, not the case class. For instance List has a toString method
defined. We don't want a synthetic toString (defined either in :: or
in Product2) override that.
Cheers
Mon, 2009-03-16, 22:47
#11
Re: Strange trait stacking issue
A side remark: in my application I was much more interesting in seeing
the class name than the product components themselves.
Would not that essential information be lost by inheriting from Product?
On 3/16/09, Jorge Ortiz wrote:
> In the case of List and ::, List already inherits from Product. It can
> specifically override toString to use Collection's toString, not Product's.
>
> In the hypothetical case of:
>
> class A { override def toString = "A" }
> case class B extends A
>
> Then the desugaring should expand to:
>
> class B extends A with Product {
> override def toString = super[A].toString
> ...
> }
>
> Which implements the current special case logic of "don't add a toString if
> one is already defined", except it's implemented in Scala rather than
> compiler magic.
>
> This has the advantage of someone like Christian being able to come along
> and say:
>
> class A extends Product { override def toString = super[Product].toString
> + "A" }
> case class B extends A
>
> which gets desugared to:
>
> class B extends A with Product
>
> and the current rules for mixin inheritance just do the right thing, with no
> need for more special cases.
>
> --j
>
>
> On Mon, Mar 16, 2009 at 8:40 AM, martin odersky
> wrote:
> > The problem is that the toString method is very often in the base
> > class, not the case class. For instance List has a toString method
> > defined. We don't want a synthetic toString (defined either in :: or
> > in Product2) override that.
> >
> > Cheers
> >
> > -- Martin
> >
> >
> >
> >
> > On Mon, Mar 16, 2009 at 1:07 PM, Jorge Ortiz
> wrote:
> > > Yeah, the relevant part of the spec is SLS 5.2.3
> > >
> > > My first attempt was made under the (misguided) hope that case class's
> > > special toString was defined in the Product trait and was thus callable
> > > (with the proper prefix) even by case classes that override toString.
> > >
> > > Is there any reason why ==, hashCode, and toString for case classes
> aren't
> > > defined in Product? Case classes that define their own would still
> override
> > > Product's implementation, and if a trait A is mixed in which defines one
> of
> > > these methods, the case class can automatically choose A's version.
> > >
> > > Would this be a bad idea? Are there performance problems I'm missing?
> > >
> > > --j
> > >
> > > On Mon, Mar 16, 2009 at 4:54 AM, Josh Suereth
> > > wrote:
> > >>
> > >> Jorge, I'm not sure you're correct here:
> > >>
> > >> trait A {
> > >>
> > >> def service(){ Console.print(“A”) }
> > >>
> > >> }
> > >>
> > >> trait B extends A {
> > >>
> > >> def service(){ Console.print(“B”); super.service() }
> > >>
> > >> }
> > >>
> > >> trait C extends A {
> > >>
> > >> def service() { Console.print(“C”); super.service() }
> > >>
> > >> }
> > >>
> > >> val x = new A with B with C
> > >>
> > >> x.service() //Output CBA
> > >>
> > >> The "super" defined in B + C should both point to A, but instead
> x.service
> > >> correctly displays CBA. This means scala is "doing the right thing"
> with
> > >> super calls + mixin. However if I change the implemntations of C and B
> to
> > >> have super[A].service(); then it only displays "CA".
> > >>
> > >> I beleive the issue is that when using Case classes, the toString
> method
> > >> is not generated if it "already exists". In this case, it thinks the
> trait
> > >> created the toString method.
> > >>
> > >> See the following:
> > >>
> > >> scala> trait x { override def toString : String = super.toString }
> > >> defined trait x
> > >>
> > >> scala> case class y(myInt : Int) extends x
> > >> defined class y
> > >>
> > >> scala> y(5)
> > >> res0: y = y@76d50842
> > >>
> > >> scala> val z = y(5)
> > >> z: y = y@76d50842
> > >>
> > >> scala> z.toString
> > >> res1: String = y@76d50842
> > >>
> > >> scala> case class A(myInt : Int)
> > >> defined class A
> > >>
> > >> scala> val b = new A(5) with x
> > >> b: A with x = A(5)
> > >>
> > >> scala> b.toString
> > >> res2: String = A(5)
> > >>
> > >> scala>
> > >>
> > >>
> > >> If you allow the case class to create the toString, then mixing them
> > >> together later produces the desired result.
> > >>
> > >>
> > >> On Mon, Mar 16, 2009 at 4:45 AM, Jorge Ortiz
> > >> wrote:
> > >>>
> > >>> When T calls super.toString, you're calling the toString defined on
> > >>> AnyRef (T's super), not the toString defined on case classes.
> > >>>
> > >>> The first-cut approach to this would be to refer explicitly to the
> > >>> toString we want:
> > >>>
> > >>> trait T { self =>
> > >>> abstract override def toString: String = self.toString + "T"
> > >>> }
> > >>>
> > >>> Unfortunately this leads to a StackOverflowException. Probably a bug.
> > >>>
> > >>> The next approach is to redefine it yourself, I'm afraid. This isn't
> hard
> > >>> once you know that all case classes implement Product, and Product has
> a few
> > >>> methods which might be helpful.
> > >>>
> > >>> trait T extends Product {
> > >>> override def toString: String =
> > >>> (0 until
> productArity).map(productElement).mkString(productPrefix
> +
> > >>> "(", ", ", ")T")
> > >>> }
> > >>>
> > >>> It's not pretty, but that should do it.
> > >>>
> > >>> --j
> > >>>
> > >>> On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy
> > >>> wrote:
> > >>>>
> > >>>> Hi, I ran into a strange trait stacking issue lately. It definitely
> > >>>> unexpected to me, but I can't tell whether it's a bug or a feature. I
> > >>>> have trait T the modifies the way toString works, but it does not
> seem
> > >>>> to work stack on the default toString method of case classes:
> > >>>>
> > >>>> Consider the following code
> > >>>>
> > >>>> object Main {
> > >>>>
> > >>>> trait T { abstract override def toString:String = super.toString+"T"
> }
> > >>>>
> > >>>> trait Base
> > >>>>
> > >>>> case class B(i:Int) extends Base with T
> > >>>>
> > >>>> def main(args: Array[String]) {
> > >>>> object y extends B(1)
> > >>>> println(y)
> > >>>> }
> > >>>> }
> > >>>>
> > >>>> This program prints Main$y$2$@44c829c0T rather than B(1)T.
> > >>>>
> > >>>> I am just curious what you think: this is I should expect or
> something
> > >>>> to be reported?
> > >>>
> > >>
> > >
> > >
> >
>
>
Mon, 2009-03-16, 23:37
#12
Re: Strange trait stacking issue
The class name is defined is Product as productPrefix. Case classes should just override that.
--j
On Mon, Mar 16, 2009 at 2:27 PM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
--j
On Mon, Mar 16, 2009 at 2:27 PM, Christian Szegedy <christian.szegedy@gmail.com> wrote:
A side remark: in my application I was much more interesting in seeing
the class name than the product components themselves.
Would not that essential information be lost by inheriting from Product?
On 3/16/09, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
> In the case of List and ::, List already inherits from Product. It can
> specifically override toString to use Collection's toString, not Product's.
>
> In the hypothetical case of:
>
> class A { override def toString = "A" }
> case class B extends A
>
> Then the desugaring should expand to:
>
> class B extends A with Product {
> override def toString = super[A].toString
> ...
> }
>
> Which implements the current special case logic of "don't add a toString if
> one is already defined", except it's implemented in Scala rather than
> compiler magic.
>
> This has the advantage of someone like Christian being able to come along
> and say:
>
> class A extends Product { override def toString = super[Product].toString
> + "A" }
> case class B extends A
>
> which gets desugared to:
>
> class B extends A with Product
>
> and the current rules for mixin inheritance just do the right thing, with no
> need for more special cases.
>
> --j
>
>
> On Mon, Mar 16, 2009 at 8:40 AM, martin odersky <martin.odersky@epfl.ch>
> wrote:
> > The problem is that the toString method is very often in the base
> > class, not the case class. For instance List has a toString method
> > defined. We don't want a synthetic toString (defined either in :: or
> > in Product2) override that.
> >
> > Cheers
> >
> > -- Martin
> >
> >
> >
> >
> > On Mon, Mar 16, 2009 at 1:07 PM, Jorge Ortiz <jorge.ortiz@gmail.com>
> wrote:
> > > Yeah, the relevant part of the spec is SLS 5.2.3
> > >
> > > My first attempt was made under the (misguided) hope that case class's
> > > special toString was defined in the Product trait and was thus callable
> > > (with the proper prefix) even by case classes that override toString.
> > >
> > > Is there any reason why ==, hashCode, and toString for case classes
> aren't
> > > defined in Product? Case classes that define their own would still
> override
> > > Product's implementation, and if a trait A is mixed in which defines one
> of
> > > these methods, the case class can automatically choose A's version.
> > >
> > > Would this be a bad idea? Are there performance problems I'm missing?
> > >
> > > --j
> > >
> > > On Mon, Mar 16, 2009 at 4:54 AM, Josh Suereth <joshua.suereth@gmail.com>
> > > wrote:
> > >>
> > >> Jorge, I'm not sure you're correct here:
> > >>
> > >> trait A {
> > >>
> > >> def service(){ Console.print(“A”) }
> > >>
> > >> }
> > >>
> > >> trait B extends A {
> > >>
> > >> def service(){ Console.print(“B”); super.service() }
> > >>
> > >> }
> > >>
> > >> trait C extends A {
> > >>
> > >> def service() { Console.print(“C”); super.service() }
> > >>
> > >> }
> > >>
> > >> val x = new A with B with C
> > >>
> > >> x.service() //Output CBA
> > >>
> > >> The "super" defined in B + C should both point to A, but instead
> x.service
> > >> correctly displays CBA. This means scala is "doing the right thing"
> with
> > >> super calls + mixin. However if I change the implemntations of C and B
> to
> > >> have super[A].service(); then it only displays "CA".
> > >>
> > >> I beleive the issue is that when using Case classes, the toString
> method
> > >> is not generated if it "already exists". In this case, it thinks the
> trait
> > >> created the toString method.
> > >>
> > >> See the following:
> > >>
> > >> scala> trait x { override def toString : String = super.toString }
> > >> defined trait x
> > >>
> > >> scala> case class y(myInt : Int) extends x
> > >> defined class y
> > >>
> > >> scala> y(5)
> > >> res0: y = y@76d50842
> > >>
> > >> scala> val z = y(5)
> > >> z: y = y@76d50842
> > >>
> > >> scala> z.toString
> > >> res1: String = y@76d50842
> > >>
> > >> scala> case class A(myInt : Int)
> > >> defined class A
> > >>
> > >> scala> val b = new A(5) with x
> > >> b: A with x = A(5)
> > >>
> > >> scala> b.toString
> > >> res2: String = A(5)
> > >>
> > >> scala>
> > >>
> > >>
> > >> If you allow the case class to create the toString, then mixing them
> > >> together later produces the desired result.
> > >>
> > >>
> > >> On Mon, Mar 16, 2009 at 4:45 AM, Jorge Ortiz <jorge.ortiz@gmail.com>
> > >> wrote:
> > >>>
> > >>> When T calls super.toString, you're calling the toString defined on
> > >>> AnyRef (T's super), not the toString defined on case classes.
> > >>>
> > >>> The first-cut approach to this would be to refer explicitly to the
> > >>> toString we want:
> > >>>
> > >>> trait T { self =>
> > >>> abstract override def toString: String = self.toString + "T"
> > >>> }
> > >>>
> > >>> Unfortunately this leads to a StackOverflowException. Probably a bug.
> > >>>
> > >>> The next approach is to redefine it yourself, I'm afraid. This isn't
> hard
> > >>> once you know that all case classes implement Product, and Product has
> a few
> > >>> methods which might be helpful.
> > >>>
> > >>> trait T extends Product {
> > >>> override def toString: String =
> > >>> (0 until
> productArity).map(productElement).mkString(productPrefix
> +
> > >>> "(", ", ", ")T")
> > >>> }
> > >>>
> > >>> It's not pretty, but that should do it.
> > >>>
> > >>> --j
> > >>>
> > >>> On Mon, Mar 16, 2009 at 12:16 AM, Christian Szegedy
> > >>> <christian.szegedy@gmail.com> wrote:
> > >>>>
> > >>>> Hi, I ran into a strange trait stacking issue lately. It definitely
> > >>>> unexpected to me, but I can't tell whether it's a bug or a feature. I
> > >>>> have trait T the modifies the way toString works, but it does not
> seem
> > >>>> to work stack on the default toString method of case classes:
> > >>>>
> > >>>> Consider the following code
> > >>>>
> > >>>> object Main {
> > >>>>
> > >>>> trait T { abstract override def toString:String = super.toString+"T"
> }
> > >>>>
> > >>>> trait Base
> > >>>>
> > >>>> case class B(i:Int) extends Base with T
> > >>>>
> > >>>> def main(args: Array[String]) {
> > >>>> object y extends B(1)
> > >>>> println(y)
> > >>>> }
> > >>>> }
> > >>>>
> > >>>> This program prints Main$y$2$@44c829c0T rather than B(1)T.
> > >>>>
> > >>>> I am just curious what you think: this is I should expect or
> something
> > >>>> to be reported?
> > >>>
> > >>
> > >
> > >
> >
>
>
On Mon, Mar 16, 2009 at 8:16 AM, Christian Szegedy
wrote:
> Hi, I ran into a strange trait stacking issue lately. It definitely
> unexpected to me, but I can't tell whether it's a bug or a feature. I
> have trait T the modifies the way toString works, but it does not seem
> to work stack on the default toString method of case classes:
>
> Consider the following code
>
> object Main {
>
> trait T { abstract override def toString:String = super.toString+"T" }
>
> trait Base
>
> case class B(i:Int) extends Base with T
>
> def main(args: Array[String]) {
> object y extends B(1)
> println(y)
> }
> }
>
> This program prints Main$y$2$@44c829c0T rather than B(1)T.
>
> I am just curious what you think: this is I should expect or something
> to be reported?
>
No, this is as expected. Case class B does not implement its own
toString method if one was inherited. In your case, it inherited a
toString method from T.