Scala. Is there a way to choose a super implementation method using types?

When I expand the features, I can choose which implementation of the method to use. Like here:

object Main {

  def main(args: Array[String]): Unit = {
    val c = new C
    println(c.a)
    println(c.b)
  }

  trait Parent {
    def foo: String
  }

  trait A extends Parent {
    override def foo = "from A"
  }

  trait B extends Parent {
    override def foo = "from B"
  }

  class C extends A with B {
    val b = super[A].foo
    val a = super[B].foo
  }

}

But if I want to do the same with self-types, it seems like this is not possible:

object Main {

  def main(args: Array[String]): Unit = {
    val c = new C with A with B
    println(c.a)
    println(c.b)
  }

  trait Parent {
    def foo: String
  }

  trait A extends Parent {
    override def foo = "from A"
  }

  trait B extends Parent {
    override def foo = "from B"
  }

  class C {
    self: A with B =>

    val b = super[A].foo
    val a = super[B].foo
  }

}

This does not compile. Am I right and is this impossible? If I'm right, why is this a workaround?

UPDATE: Why do I need first? I played with dependency injection using self-types instead of constructor injection. Thus, I had the base attribute Converter and the child attributes FooConverter and BarConverter. And I wanted to write it like this (which of course does not work):

object Main {

  class Foo

  class Bar

  trait Converter[A] {
    def convert(a: A): String
  }

  trait FooConverter extends Converter[Foo] {
    override def convert(a: Foo): String = ???
  }

  trait BarConverter extends Converter[Bar] {
    override def convert(a: Bar): String = ???
  }

  class Service {

    this: Converter[Foo] with Converter[Bar] =>

    def fooBar(f: Foo, b:Bar) = {
      convert(f)
      convert(b)
    }
  }

}

, - , , . , - . . , , :

object Main {

  class Foo

  class Bar

  trait Converter[A] {
    def convert(a: A): String
  }

  trait FooConverter extends Converter[Foo] {
    override def convert(a: Foo): String = ???
  }

  trait BarConverter extends Converter[Bar] {
    override def convert(a: Bar): String = ???
  }

  class Service {

    this: FooConverter with BarConverter =>

    def fooBar(f: Foo, b:Bar) = {
      convert(f)
      convert(b)
    }
  }

}

, , , , , Converter [A] .

+4
2

super ( ). foo self, , foo - , ( ). - , ( ).

:

trait CC extends A with B {
  val b = super[A].foo
  val a = super[B].foo
}

class C {
  self: CC =>

}

, - a b C, ( C), C CC.

, , ( ) - val c foo foo , , a b (A with B B with A). , , , , C foo. , self-type ( ) "" LSP - (. ).


, , , - . - , - ( ).

:

class Foo

class Bar

trait Converter[A] {
  def convert(a: A): String
}

object FooConverter1 extends Converter[Foo] {
  override def convert(a: Foo): String = ???
}

object BarConverter1 extends Converter[Bar] {
  override def convert(a: Bar): String = ???
}


trait FooBarConvertService {
  def fooConverter: Converter[Foo]
  def barConverter: Converter[Bar]

  def fooBar(f: Foo, b: Bar) = {
    fooConverter(f)
    barConverter(b)

  }

}

trait Converters {
  def fooConverter: Converter[Foo] = FooConverter1 
  def barConverter: Converter[Bar] = BarConverter1 
}

object App extends FooBarConvertService with Converters with ... 

/ , .

, Converter[Bar] - , Function1[Bar, String] Bar => String, :

sealed trait FooBar //introduced it just to make types stronger, you can omit it if you prefer
class Foo extends FooBar
class Bar extends FooBar

trait FooBarConvertService {

  type Converter[T <: FooBar] = T => String

  def fooConverter: Converter[Foo]
  def barConverter: Converter[Bar]
  def fooBar(f: Foo, b: Bar) = {
    fooConverter(f)
    barConverter(b)
  }

}

trait FooConverterProvider {
  def fooConverter: Foo => String = ??? 
}

trait BarConverterProvider {
  def barConverter: Bar => String = ??? 
}

object App 
  extends FooBarConvertService 
  with FooConverterProvider 
  with BarConverterProvider

def fooConverter(f: Foo): String = ??? def fooConverter: Foo => String = ???.

, , , , , private[package].

:

package converters

trait FooBarConvertService {

  type Converter[T <: FooBar] = T => String

  private[converters] def fooConverter: Converter[Foo]
  private[converters] def barConverter: Converter[Bar]

  def fooBar(f: Foo, b: Bar) = {
    fooConverter(f)
    barConverter(b)
  }

}

trait FooConverterProvider {
  private[converters] def fooConverter: Foo => String = ??? 
}

trait BarConverterProvider {
  private[converters] def barConverter: Bar => String = ??? 
}

:

package client 
import converters._  

object App 
  extends FooBarConvertService 
  with FooConverterProvider 
  with BarConverterProvider

object converters {...}; object client {...} , .

, self, fooConverter/barConverter App ( foo - val c = new C with A with B):

 client.App.fooBar(new Foo, new Bar) //OK
 client.App.fooConverter
 <console>:13: error: method fooConverter in trait FooConverterProvider cannot be accessed in object client.App
          client.App.fooConverter
                     ^
+2

, self , , , , , . , . . , , C {self: A B = > } A B . , B, C.

, - . , , .

object DoubleSelfType extends App {
      val c = new DoubleFoo
      println(c.a)
      println(c.b)

      trait Parent {
        def foo: String
      }

      trait A extends Parent {
        override def foo = "from A"
      }

      trait B extends Parent {
        override def foo = "from B"
      }

      trait C {
        self: A with B =>

        val a = ""
        val b = ""

      }

      class DoubleFoo extends C with A with B {
        override val b = super[A].foo
        override val a = super[B].foo
      }

    }
+1

Source: https://habr.com/ru/post/1657636/


All Articles