How to call super method when overriding a method through a trait

后端 未结 3 1930
南笙
南笙 2020-12-29 06:19

It would appear that it is possible to change the implementation of a method on a class with a trait such as follows:

trait Abstract { self: Result =>
            


        
相关标签:
3条回答
  • 2020-12-29 06:50

    Here is the answer I was looking for. Thank you Shadowlands for pointing me in the right direction with Scala's abstract override feature.

    trait Abstract extends Result {
        abstract override def userRepr = "abstract " + super.userRepr
    }
    
    abstract class Result {
        def userRepr: String = "wtv"
    }
    
    case class ValDefResult(name: String) extends Result {
        override def userRepr = name
    }
    
    val a = new ValDefResult("asd") with Abstract
    a.userRepr
    

    Live code is available here: http://www.scalakata.com/52536cc2e4b0b1a1c4daa4a4

    Sorry for the confusing example code, I am writing a library that deals with the Scala AST and was not inspired enough to change the names.

    0 讨论(0)
  • 2020-12-29 06:51

    abstract override is the mechanism, aka stackable traits. It's worth adding that linearization counts, because that's what determines what super means.

    This question is a great addendum to the canonical Q&A on self-type vs extension.

    Where the inheritance is ambiguous with self-types:

    scala> trait Bar { def f: String = "bar" }
    defined trait Bar
    
    scala> trait Foo { _: Bar => override def f = "foo" }
    defined trait Foo
    
    scala> new Foo with Bar { }
    <console>:44: error: <$anon: Foo with Bar> inherits conflicting members:
      method f in trait Foo of type => String  and
      method f in trait Bar of type => String
    (Note: this can be resolved by declaring an override in <$anon: Foo with Bar>.)
                  new Foo with Bar { }
                      ^
    

    Then obviously, you can choose:

    scala> new Foo with Bar { override def f = super.f }
    res5: Foo with Bar = $anon$1@57a68215
    
    scala> .f
    res6: String = bar
    
    scala> new Foo with Bar { override def f = super[Foo].f }
    res7: Foo with Bar = $anon$1@17c40621
    
    scala> .f
    res8: String = foo
    

    or

    scala> new Bar with Foo {}
    res9: Bar with Foo = $anon$1@374d9299
    
    scala> .f
    res10: String = foo
    
    0 讨论(0)
  • 2020-12-29 06:53

    I don't know if you are in a position to make the following changes, but the effect you want can be achieved by introducing an extra trait (I'll call it Repr), and using abstract override in the Abstract trait:

    trait Repr {
        def userRepr: String
    }
    
    abstract class Result extends Repr {
        def userRepr: String = "wtv"
    }
    
    case class ValDefResult(name: String) extends Result {
        override def userRepr = name
    }
    
    trait Abstract extends Repr { self: Result =>
        abstract override def userRepr = "abstract-" + super.userRepr // 'super.' works now
    }
    

    Your example usage now gives:

    scala> val a = new ValDefResult("asd") with Abstract
    a: ValDefResult with Abstract = ValDefResult(asd)
    
    scala> a.userRepr
    res3: String = abstract-asd
    
    0 讨论(0)
提交回复
热议问题