Does Scala have something similar to implementing an explicit C # interface?

In C #, you can implement interfaces explicitly. Explicitly implemented methods can only be called through a variable that has an interface as its static type. This avoids name type and return type conflicts and provides different implementations of the same method depending on the static type this .

For instance:

 interface IFoo { int DoSomething(); } interface IBar { string DoSomething(); } class Impl : IFoo, IBar { int IFoo.DoSomething() { /* Implementation for IFoo */ } string IBar.DoSomething() { /* A different implementation for IBar */ } public void DoSomething() { /* Yet another implementation for Impl */ } } 

How would you handle this case in Scala:

 trait Foo { def doSomething(): Int } trait Bar { def doSomething(): String } class Impl extends Foo with Bar { /* only one "doSomething()" visible here (that of Bar?) */ /* what now... ? */ } 
+4
source share
2 answers

If you are just trying to get your class to follow two separate incompatible interfaces, you will have to write wrappers instead. For instance,

 implicit case class ImplAsFoo(impl: Impl) extends Foo { def asFoo = this def doSomething: Int = 5 } 

Now you can

 impl.asFoo 

on the downloader to go to the Foo wrapper.

In some cases, however, a type type template can be used more naturally to provide connectivity functionality:

 trait IFoo[A] { def doSomething: Int } trait IBar[A] { def doSomething: String } // These need to be companions so :paste if you're using REPL class Impl { def doSomething { println("Hey!") } } object Impl { implicit object FooImpl extends IFoo[Impl] { def doSomething = 5 } implicit object BarImpl extends IBar[Impl] { def doSomething = "salmon" } } def needsFoo[A <: Impl: IFoo](a: A) = implicitly[IFoo[Impl]].doSomething scala> needsFoo(new Impl) res1: Int = 5 scala> (new Impl).doSomething Hey! 

This is not exactly the same, but it also fixes the problem of having different implementations without turning off naming schemes. (If you need to doSomething with an doSomething object, you must pass it as a parameter to an implicit object that handles this case.)

If you already have traits, then, of course, this will not help you. But when you develop from scratch, instead of having a bunch of features with incompatible methods, you can try class types.

Finally, if you can’t help when a bunch of untyped things mix together, of which you need to choose Foo s, you need to come up with more complex schemes:

 trait CanBeFoo { def asFoo: Foo } trait Foo { def doSomething: Int } // :paste these two together class Impl extends CanBeFoo { def doSomething { println("Ho!") } def asFoo = ImplAsFoo(this) } case class ImplAsFoo(impl: Impl) extends Foo { def doSomething = 6 } val myList = List("salmon", new Impl, new Foo { def doSomething = 4 }) def doIt(f: Foo) { println(f.doSomething) } myList.foreach { case f: Foo => doIt(f) case cf: CanBeFoo => doIt(cf.asFoo) case _ => println("nuh-uh") } // Produces // nuh-uh // 6 // 4 

You may prefer an intermediate map:

 myList.map{ case cf: CanBeFoo => cf.asFoo; case x => x }.foreach{ case f: Foo => println(f.doSomething) case _ => println("nuh-uh") } 
+3
source

No, these are strictly incompatible base types. When a class extends a trait, it has that trait as part of its type. It cannot have mutually incompatible type identifiers, as in the case of any class that extends Foo with Bar (as you wrote these traits).

+2
source

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


All Articles