- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Why abstract override is need to override an abstract override?
Thu, 2011-01-06, 03:06
If I have an "abstract override" in a trait and I override that in
another trait, why is it necessary to do that with "abstract
override", rather than with plain "override"? For example:
trait T1 {
def f
}
trait T2 extends T1 {
abstract override def f = "in T1"
def something = super.f // So the "abstract override" is needed
}
trait T3 extends T2 {
override def f = "in T2" // Error: must be "abstract override"
}
When the compiler compiles T3, it already knows that T2 will be among
the super-types of T3, and also that T2 has declared that one of its
super-types must have a non-abstract f. Hence it's known that T3 will
inherit a non-abstract f when it's actually used. That the compiler
knows this shows because this works:
trait T3 extends T2 {
def something2 = super.f // No "abstract override" is needed now
}
Thu, 2011-01-06, 10:37
#2
Re: Why abstract override is need to override an abstract overr
Thursday, January 6, 2011, 3:46:01 AM, Lex wrote:
> Abstract override is not what you think it is. Here is an article
> explaining abstract override:
> http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
I red that before and some more, I understand what the intended usage
of it is. I deliberately did not put super.f into the constructor, to
keep the example free from a such coincidence, after all, referring to
super.f anywhere in T2 makes the "abstract override" needed, and
rightfully so. So I figured (badly?) that the generalized meaning of
"abstract override", regardless what the original motive behind it
was, is that "I know that so far it's not guaranteed that there will
be a concrete super.f when this trait will be actually mixed in
somewhere, only that there will be a concrete f, so please ensure that
there will be a concrete super.f too". I mean, if it's ultimate
meaning is just that "I want to use the stackable trait pattern
regarding this member", that would be strange, especially as it's not
called "stacking override" or like. Anyway... what does "abstract
override" mean in the head of the designers? (In T3 I don't even
override an abstract f. The f in T2 is concrete. Even if it would be
like f = super.f + something, it would be still a concrete f.)
> 2011/1/5 Daniel Dekany :
>> If I have an "abstract override" in a trait and I override that in
>> another trait, why is it necessary to do that with "abstract
>> override", rather than with plain "override"? For example:
>>
>> trait T1 {
>> def f
>> }
>>
>> trait T2 extends T1 {
>> abstract override def f = "in T1"
>> def something = super.f // So the "abstract override" is needed
>> }
>>
>> trait T3 extends T2 {
>> override def f = "in T2" // Error: must be "abstract override"
>> }
>>
>> When the compiler compiles T3, it already knows that T2 will be among
>> the super-types of T3, and also that T2 has declared that one of its
>> super-types must have a non-abstract f. Hence it's known that T3 will
>> inherit a non-abstract f when it's actually used. That the compiler
>> knows this shows because this works:
>>
>> trait T3 extends T2 {
>> def something2 = super.f // No "abstract override" is needed now
>> }
>>
>> --
>> Best regards,
>> Daniel Dekany
>>
>>
>
Thu, 2011-01-06, 10:57
#3
Re: Why abstract override is need to override an abstract overr
On Thu, Jan 06, 2011 at 10:30:46AM +0100, Daniel Dekany wrote:
> [abstract override stuff]
I enjoyed this kafkaesque sequence.
scala> new T3 { def f: Unit = () }
:6: error: overriding method f in trait T3 of type => Unit;
method f needs `override' modifier
new T3 { def f: Unit = () }
^
scala> new T3 { override def f: Unit = () }
:6: error: overriding method f in trait T3 of type => Unit;
method f needs `abstract override' modifiers
new T3 { override def f: Unit = () }
^
scala> new T3 { abstract override def f: Unit = () }
:6: error: `abstract override' modifier only allowed for members of traits
new T3 { abstract override def f: Unit = () }
^
WHY ARE YOU HITTING YOURSELF?
WHY ARE YOU HITTING YOURSELF?
Real mature, scala compiler.
I also tried throwing some bippy in there:
trait T1 {
def f: Unit
}
trait T2 extends T1 {
abstract override def f: Unit = "in T1"
def something = super.f // So the "abstract override" is needed
}
trait Q1 {
def f: Unit = "bippy"
}
trait T3 extends T2 with Q1 {
abstract override def f: Unit = "in T2" // Error: must be "abstract override"
}
And I was suitably rewarded.
scala> new T3 { }
Exception in thread "main" java.lang.AssertionError: assertion failed: method f
at scala.Predef$.assert(Predef.scala:99)
at scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:110)
at scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:95)
at scala.tools.nsc.symtab.SymbolTable.atPhase(SymbolTable.scala:96)
at scala.tools.nsc.transform.Mixin.scala$tools$nsc$transform$Mixin$$rebindSuper(Mixin.scala:95)
at scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:325)
at scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:278)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
Thu, 2011-01-06, 12:47
#4
Re: Why abstract override is need to override an abstract overr
Kafika would have been proud.
On Jan 6, 2011 10:52 AM, "Paul Phillips" <paulp@improving.org> wrote:
On Thu, Jan 06, 2011 at 10:30:46AM +0100, Daniel Dekany wrote:
> [abstract override stuff]
I enjoyed this kafkaesque sequence.
scala> new T3 { def f: Unit = () }
<console>:6: error: overriding method f in trait T3 of type => Unit;
method f needs `override' modifier
new T3 { def f: Unit = () }
^
scala> new T3 { override def f: Unit = () }
<console>:6: error: overriding method f in trait T3 of type => Unit;
method f needs `abstract override' modifiers
new T3 { override def f: Unit = () }
^
scala> new T3 { abstract override def f: Unit = () }
<console>:6: error: `abstract override' modifier only allowed for members of traits
new T3 { abstract override def f: Unit = () }
^
WHY ARE YOU HITTING YOURSELF?
WHY ARE YOU HITTING YOURSELF?
Real mature, scala compiler.
I also tried throwing some bippy in there:
trait T1 {
def f: Unit
}
trait T2 extends T1 {
abstract override def f: Unit = "in T1"
def something = super.f // So the "abstract override" is needed
trait Q1 {
}
def f: Unit = "bippy"
}
trait T3 extends T2 with Q1 {
abstract override def f: Unit = "in T2" // Error: must be "abstract override"
}
And I was suitably rewarded.
scala> new T3 { }
Exception in thread "main" java.lang.AssertionError: assertion failed: method f
at scala.Predef$.assert(Predef.scala:99)
at scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:110)
at scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:95)
at scala.tools.nsc.symtab.SymbolTable.atPhase(SymbolTable.scala:96)
at scala.tools.nsc.transform.Mixin.scala$tools$nsc$transform$Mixin$$rebindSuper(Mixin.scala:95)
at scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:325)
at scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:278)
at scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
at scala.collection.immutable.List.foreach(List.scala:45)
--
Paul Phillips | Those who can make you believe absurdities
In Theory | can make you commit atrocities.
Empiricist | -- Voltaire
i'll ship a pulp |----------* http://www.improving.org/paulp/ *----------
Thu, 2011-01-06, 15:37
#5
Re: Why abstract override is need to override an abstract overr
The language seems clearly broken here. abstract override makes sense
when the overriding method (f) invokes its super (super.f), but not
when some other method (`something`) invokes super.f ... `something`
is abstract, but it isn't overriding anything, but the language not
only doesn't require that `something` be declared abstract, it doesn't
allow it. OTOH, the language demands that f be declared abstract even
though it isn't, it only overrides. "abstract override" ties two
attributes together that are actually orthogonal. ISTM that correct
would be
trait T1 {
def f
}
trait T2 extends T1 {
override def f = "in T1" // override is optional
abstract def something = super.f
}
but that isn't how Scala is defined.
Thu, 2011-01-06, 16:27
#6
Re: Why abstract override is need to override an abstract overr
Thursday, January 6, 2011, 10:52:07 AM, Paul Phillips wrote:
> On Thu, Jan 06, 2011 at 10:30:46AM +0100, Daniel Dekany wrote:
>> [abstract override stuff]
>
> I enjoyed this kafkaesque sequence.
>
scala>> new T3 { def f: Unit = () }
> :6: error: overriding method f in trait T3 of type => Unit;
> method f needs `override' modifier
> new T3 { def f: Unit = () }
> ^
>
scala>> new T3 { override def f: Unit = () }
> :6: error: overriding method f in trait T3 of type => Unit;
> method f needs `abstract override' modifiers
> new T3 { override def f: Unit = () }
> ^
>
scala>> new T3 { abstract override def f: Unit = () }
> :6: error: `abstract override' modifier only allowed for members of traits
> new T3 { abstract override def f: Unit = () }
I would say that the inherent problem here is that at the moment you
say new T3 { abstract override def f: Unit = () } all hope is lost for
T2 to ever get its concrete super.f. Even if that (anonymous) class
were abstract, there is just no way to add anything to the linear
super types of T2 anymore. But of course scalac instead bitches :)
about whether it's an abstract override or not... Hmm... you know
what, I might as well just get how the brain of Martin et al. ticked
here. Is maybe that "abstract override def f" says that "I'm now
overriding f with something concrete, but I'm aware of that it's still
not yet usable, as it needs that yet abstract super.f to become
concrete somewhere later".
BTW, it doesn't mater in this topic, but just for the record... in my
example T1 meant to be:
trait T1 {
def f: String
}
> WHY ARE YOU HITTING YOURSELF?
> WHY ARE YOU HITTING YOURSELF?
>
> Real mature, scala compiler.
>
> I also tried throwing some bippy in there:
>
> trait T1 {
> def f: Unit
> }
>
> trait T2 extends T1 {
> abstract override def f: Unit = "in T1"
> def something = super.f // So the "abstract override" is needed
> }
>
> trait Q1 {
> def f: Unit = "bippy"
> }
>
> trait T3 extends T2 with Q1 {
> abstract override def f: Unit = "in T2" // Error: must be "abstract override"
> }
>
> And I was suitably rewarded.
>
scala>> new T3 { }
> Exception in thread "main" java.lang.AssertionError: assertion failed: method f
> at scala.Predef$.assert(Predef.scala:99)
> at
> scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:110)
> at
> scala.tools.nsc.transform.Mixin$$anonfun$scala$tools$nsc$transform$Mixin$$rebindSuper$1.apply(Mixin.scala:95)
> at
> scala.tools.nsc.symtab.SymbolTable.atPhase(SymbolTable.scala:96)
> at
> scala.tools.nsc.transform.Mixin.scala$tools$nsc$transform$Mixin$$rebindSuper(Mixin.scala:95)
> at
> scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:325)
> at
> scala.tools.nsc.transform.Mixin$$anonfun$mixinTraitMembers$1$1.apply(Mixin.scala:278)
> at
> scala.collection.LinearSeqOptimized$class.foreach(LinearSeqOptimized.scala:61)
> at scala.collection.immutable.List.foreach(List.scala:45)
>
Thu, 2011-01-06, 16:47
#7
Re: Why abstract override is need to override an abstract overr
Thursday, January 6, 2011, 3:29:15 PM, Jim Balter wrote:
> The language seems clearly broken here. abstract override makes sense
> when the overriding method (f) invokes its super (super.f), but not
> when some other method (`something`) invokes super.f ... `something`
> is abstract, but it isn't overriding anything, but the language not
> only doesn't require that `something` be declared abstract, it doesn't
> allow it. OTOH, the language demands that f be declared abstract even
> though it isn't, it only overrides. "abstract override" ties two
> attributes together that are actually orthogonal. ISTM that correct
> would be
>
> trait T1 {
> def f
> }
>
> trait T2 extends T1 {
> override def f = "in T1" // override is optional
> abstract def something = super.f
> }
But why would be "something" abstract just because it calls something
that's abstract?
I'm not sure if it's absolutely clear for everyone that the above
trait do have a pending problem, so certainly I should give scala
*some* feedback to tell that I'm aware of it, and I'm doing it on
purpose. Currently, if I just want to call super.f outside f, but I
don't want to change f, then I can do that like this:
trait T2 extends T1 {
abstract override def f = super.f // just to calm scalac down...
def something = super.f + "mooo"
}
It's bit ugly... but it's quite an artificial example, so I'm all
right with this. It wasn't the thing that bugged me... but see the
other mail, I might get it now.
> but that isn't how Scala is defined.
>
Thu, 2011-01-06, 20:47
#8
Re: Why abstract override is need to override an abstract overr
I'm not a scala expert but I don't think that the language is broken... (To not say that it is quite presumptuous to say that!!)
Of course, the scala compiler, like most compilers, has some bugs(AssertionFailed) and also sometimes give useless messages, also like most compilers...
From my little experience, traits may be sometimes a bit tricky if you don't understand exactly what you are doing but I don't see anything wrong with them.
Let's take your original example:
> trait T1 {
> def f
> }
>
> trait T2 extends T1 {
> abstract override def f = "in T1"
> def something = super.f // So the "abstract override" is needed
> }
>
> trait T3 extends T2 {
> override def f = "in T2" // Error: must be "abstract override"
> }
And let's assume, that T3 is valid, that it can actually provide a CONCRETE implementation of f.
Then, you can create an instance of T3 as there is no more abstract method in it. So, what should happen if you call on this instance t.something ?
It will goes into method "something" of T2 and then try to call super.f ....but who is this "super" of T2? T3 is a SUBTYPE of T2, so it's not him...and guess what, there is no "super" object on which to call super.f...
So, I would say thank you scalac for not letting us do impossible stuffs....
Somehow, I think we can say that as soon as you "abstract override" a method in T2 (which is required of course to call a super.f) you force any instance of T2 to also be the SUBTYPE of a ANOTHER subtype of T1 which have a concrete f.
Therefore, T2 cannot be anymore the SUPERTYPE of a type which have a concrete f otherwise you could avoid to make that new subtype a subtype of a concrete T1, which would lead to inconsistencies as demonstrated above...
Maybe, it would be possible to allow declaration like your T3 and then force T3 to be used ONLY as a mixin of another concrete T1. Thus, T3 will override f in the concrete T1 with which it will me mixed but not the super.f in T2....but I think it would much much more confusing to allow such something and very likely completely useless....
Actually, the explanations you gave to Paul say roughly the same thing, so you should not have any problem with your example as it is the same in substabce...
Best,
ma
2011/1/6 Daniel Dekany <ddekany@freemail.hu>
Of course, the scala compiler, like most compilers, has some bugs(AssertionFailed) and also sometimes give useless messages, also like most compilers...
From my little experience, traits may be sometimes a bit tricky if you don't understand exactly what you are doing but I don't see anything wrong with them.
Let's take your original example:
> trait T1 {
> def f
> }
>
> trait T2 extends T1 {
> abstract override def f = "in T1"
> def something = super.f // So the "abstract override" is needed
> }
>
> trait T3 extends T2 {
> override def f = "in T2" // Error: must be "abstract override"
> }
And let's assume, that T3 is valid, that it can actually provide a CONCRETE implementation of f.
Then, you can create an instance of T3 as there is no more abstract method in it. So, what should happen if you call on this instance t.something ?
It will goes into method "something" of T2 and then try to call super.f ....but who is this "super" of T2? T3 is a SUBTYPE of T2, so it's not him...and guess what, there is no "super" object on which to call super.f...
So, I would say thank you scalac for not letting us do impossible stuffs....
Somehow, I think we can say that as soon as you "abstract override" a method in T2 (which is required of course to call a super.f) you force any instance of T2 to also be the SUBTYPE of a ANOTHER subtype of T1 which have a concrete f.
Therefore, T2 cannot be anymore the SUPERTYPE of a type which have a concrete f otherwise you could avoid to make that new subtype a subtype of a concrete T1, which would lead to inconsistencies as demonstrated above...
Maybe, it would be possible to allow declaration like your T3 and then force T3 to be used ONLY as a mixin of another concrete T1. Thus, T3 will override f in the concrete T1 with which it will me mixed but not the super.f in T2....but I think it would much much more confusing to allow such something and very likely completely useless....
Actually, the explanations you gave to Paul say roughly the same thing, so you should not have any problem with your example as it is the same in substabce...
Best,
ma
2011/1/6 Daniel Dekany <ddekany@freemail.hu>
Thursday, January 6, 2011, 3:29:15 PM, Jim Balter wrote:
> The language seems clearly broken here. abstract override makes sense
> when the overriding method (f) invokes its super (super.f), but not
> when some other method (`something`) invokes super.f ... `something`
> is abstract, but it isn't overriding anything, but the language not
> only doesn't require that `something` be declared abstract, it doesn't
> allow it. OTOH, the language demands that f be declared abstract even
> though it isn't, it only overrides. "abstract override" ties two
> attributes together that are actually orthogonal. ISTM that correct
> would be
>
> trait T1 {
> def f
> }
>
> trait T2 extends T1 {
> override def f = "in T1" // override is optional
> abstract def something = super.f
> }
But why would be "something" abstract just because it calls something
that's abstract?
I'm not sure if it's absolutely clear for everyone that the above
trait do have a pending problem, so certainly I should give scala
*some* feedback to tell that I'm aware of it, and I'm doing it on
purpose. Currently, if I just want to call super.f outside f, but I
don't want to change f, then I can do that like this:
trait T2 extends T1 {
abstract override def f = super.f // just to calm scalac down...
def something = super.f + "mooo"
}
It's bit ugly... but it's quite an artificial example, so I'm all
right with this. It wasn't the thing that bugged me... but see the
other mail, I might get it now.
> but that isn't how Scala is defined.
>
> -- Jim
--
Best regards,
Daniel Dekany
Thu, 2011-01-06, 22:17
#9
Re: Why abstract override is need to override an abstract overr
Thursday, January 6, 2011, 8:37:53 PM, Marc-Antoine Nüssli wrote:
[snip]
>> trait T1 {
>> def f
(Meant to be "def f: String"... but it doesn't mater here...)
>> }
>>
>> trait T2 extends T1 {
>> abstract override def f = "in T1"
>> def something = super.f // So the "abstract override" is needed
>> }
>>
>> trait T3 extends T2 {
>> override def f = "in T2" // Error: must be "abstract override"
>> }
[snip]
> So, what should happen if you call on this instance t.something ?
> It will goes into method "something" of T2 and then try to call
> super.f ....but who is this "super" of T2?
It depends on where do you mix T2 into...
> T3 is a SUBTYPE of T2, so it's not him...and guess what, there is no
> "super" object on which to call super.f...
>
> So, I would say thank you scalac for not letting us do impossible stuffs....
It's absolutely possible that T2 *will* have a super.f though. Look:
class IHaveAnF extends T1 {
def f = "I'm concrete!"
}
and then:
new IHaveAnF with T3
so now T2's super is IHaveAnF. (If you find that confusing, you need
to dig into "linear super types" or type hierarchy linearization.) So
with that it will actually compile and run, if you use "abstract
override" in T3.
> Somehow, I think we can say that as soon as you "abstract override"
> a method in T2 (which is required of course to call a super.f) you
> force any instance of T2 to also be the SUBTYPE of a ANOTHER subtype
> of T1 which have a concrete f.
[snip]
T2 is not a subtype of IHaveAnF, but IHaveAnF it's still part of its
list of linear super types.
Abstract override is not what you think it is. Here is an article
explaining abstract override:
http://www.artima.com/scalazine/articles/stackable_trait_pattern.html
2011/1/5 Daniel Dekany :
> If I have an "abstract override" in a trait and I override that in
> another trait, why is it necessary to do that with "abstract
> override", rather than with plain "override"? For example:
>
> trait T1 {
> def f
> }
>
> trait T2 extends T1 {
> abstract override def f = "in T1"
> def something = super.f // So the "abstract override" is needed
> }
>
> trait T3 extends T2 {
> override def f = "in T2" // Error: must be "abstract override"
> }
>
> When the compiler compiles T3, it already knows that T2 will be among
> the super-types of T3, and also that T2 has declared that one of its
> super-types must have a non-abstract f. Hence it's known that T3 will
> inherit a non-abstract f when it's actually used. That the compiler
> knows this shows because this works:
>
> trait T3 extends T2 {
> def something2 = super.f // No "abstract override" is needed now
> }
>
> --
> Best regards,
> Daniel Dekany
>
>