Assuming no multiple inheritance and no concerns about interoperability with Java, are the two following declarations equal?
sealed trait Foo { def x: Int }
case object Bar extends Foo { val x = 5 }
and
sealed abstract class Foo(val x: Int)
case object Bar extends Foo(5)
First, some modifications to your code (see below). I dropped the case as it is not relevant here. I also added val in the constructor of Foo2 as x is otherwise not accessible in Bar2.
sealed trait Foo { def x: Int }
object Bar extends Foo { val x = 5 }
sealed abstract class Foo2(val x: Int)
object Bar2 extends Foo2(5)
object Main {
def main(args: Array[String]) : Unit = {
println( Bar.x )
println( Bar2.x )
}
}
Are the two following declarations equal?
We need to define, what equal means:
Equal wrt. general structure: No. A trait is not an abstract class. A trait can have no constructor parameters, while a class can. On the other hand, a class or object (here Bar2) can only derive from one (abstract) class, while it could mix-in multiple traits. A good comprehesion on traits vs. abstract class is given here: http://www.artima.com/pins1ed/traits.html#12.7 if you need to decide on a trait or a class.
Equal wrt. byte code: No. Just run javap -v <classfile> to convince yourself
Equal wrt. Bar and Bar2 only: Yes. Both can be accessed and used identically. Both are singletons and they expose a member variable x that is readable (but not writable) from outside.
Also the output of scalac -print is quite helpful, to see what is going on:
sealed abstract trait Foo extends Object {
def x(): Int
};
object Bar extends Object with com.Foo {
private[this] val x: Int = _;
<stable> <accessor> def x(): Int = Bar.this.x;
def <init>(): com.Bar.type = {
Bar.super.<init>();
Bar.this.x = 5;
()
}
};
sealed abstract class Foo2 extends Object {
<paramaccessor> private[this] val x: Int = _;
<stable> <accessor> <paramaccessor> def x(): Int = Foo2.this.x;
def <init>(x: Int): com.Foo2 = {
Foo2.this.x = x;
Foo2.super.<init>();
()
}
};
object Bar2 extends com.Foo2 {
def <init>(): com.Bar2.type = {
Bar2.super.<init>(5);
()
}
};
object Main extends Object {
def main(args: Array[String]): Unit = {
scala.this.Predef.println(scala.Int.box(Bar.x()));
scala.this.Predef.println(scala.Int.box(Bar2.x()))
};
def <init>(): com.Main.type = {
Main.super.<init>();
()
}
}
No, these are not equivalent and can lead to trouble later with initialization order. I've added exactly the same line of code to each, showing they were never equal code blocks.
sealed trait Foo {
def x: Int
val calc = x * 5 / 2 //at the time this runs, x is actually 0
}
case object Bar extends Foo {
val x = 5
}
sealed abstract class Foo2(x: Int){
val calc = x * 5 / 2
}
case object Bar2 extends Foo2(5)
println(Bar.calc)
println(Bar2.calc)
//output 0 12
Related
I want to create a companion object that is subclass of a parameterized base class, and only fixes the base classes parameter -- that is, all methods are inherited from the base class.
One way to do this is with a trait:
class Foo(v: Int, printStream: PrintStream) {
def print: Unit = printStream.println(v);
}
trait FooFactory {
protected val printsTo: PrintStream
def apply(v: Int) = new Foo(v, printsTo)
def makeFoo(v: Int) = apply(v)
}
object Foo extends FooFactory {
protected val printsTo: PrintStream = System.out
}
val foo = Foo(3)
foo.print
val f2 = Foo.makeFoo(2)
f2.print
This way seems cleaner, but Intellij seems to think the base class methods are inaccessible outside the compilation unit (the .scala file that defines the companion):
class Bar(v: Int, printStream: PrintStream) {
def print: Unit = printStream.println(v);
}
class BarFactory(printsTo: PrintStream) {
def apply(v: Int) = new Bar(v, printsTo)
def makeBar(v: Int) = apply(v)
}
object Bar extends BarFactory(System.out) {}
val bar = Bar(3)
bar.print
val b2 = Bar.makeBar(2)
b2.print
Are these effectively equivalent (except for the name change Foo => Bar, of course)? Is one preferable?
The intent is to give the companion object a default PrintStream, while allowing users to create other factories if they need to:
val BarLoggerFactory = new BarFactory(someLogPrintStream)
val bar3 = BarLoggerFactory.makeBar(3);
Let's say I have the following code for value classes:
class Meters(val x: Int) extends AnyVal {
def +(m: Meters): Meters = new Meters(x + m.x)
}
class Seconds(val x: Int) extends AnyVal {
def +(s: Seconds): Seconds = new Seconds(x + s.x)
}
Is there any way for me to remove duplication of the "+" methods?
Something kind of like:
abstract class Units[T <: Units[T]](val x: Int) extends AnyVal {
def +(other: T): T = T(x + other.x)
}
Except I can't inherit from value classes, and I definitely can't use T like a constructor.
You can use a universal trait with a type class, lets start defining the trait.
trait Sum[T <: Sum[T]] extends Any {
val x: Int
def +(other: T)(implicit evidence : FromInt[T]): T = evidence.fromInt(x + other.x)
}
Now we need a type class that tell us how to go from an integer to some type, lets define this and call it FromInt
trait FromInt[T] {
def fromInt(x: Int) : T
}
now lets define the Meters value class which is as simple as
class Meters(val x :Int) extends AnyVal with Sum[Meters]
and in the companion object we can provide an implicit value of the type class we defined.
object Meters{
implicit val intConstructable : FromInt[Meters] = new FromInt[Meters] {
override def fromInt(x: Int) = new Meters(x)
}
}
and now we can just do
val added = new Meters(2) + new Meters(3)
println(added.x)
Suppose I have such trait:
trait FooStackable {
def foo: String
def bar: Double
abstract override def logic(x: Double): Unit = {
if (x < 0) println(foo)
else super.logic(bar + x)
}
}
I want to write a test on the method logic for this trait in behaviour driven style: I want to check in test depending on input parameters what method was called and how many times. Apparently it's not possible simply to instantiate an instance of this trait(even when overriding unimplemeted methods), so mocks also will not work.
Does it make sense to write such test scenarios? (Real logic in method logic is more complex) And if yes how stackable traits are tested in isolation?
The code cannot be compiled as written. In particular, there is no 'super' in this trait as it is not derived from anything. I made some changes to work around it:
trait Stackable {
def logic(x: Double): Unit
}
trait FooStackable extends Stackable {
def foo: String
def bar: Double
abstract override def logic(x: Double): Unit = {
println("In FooStackable.logic()")
if (x < 0) println(foo)
else super.logic(bar + x)
}
}
trait TestStackable extends Stackable {
def logic(x: Double): Unit = {
println("In TestStackable.logic()")
}
}
object FooStackableTest extends TestStackable with FooStackable {
def foo: String = "foo"
def bar: Double = 1.234
override def logic(x: Double): Unit = {
println("In FooStackableTest.logic()")
super.logic(x)
}
}
With these changes FooStackable now sits in the middle between TestStackable (which implements logic() in a base class) and FooStackableTest (implements other undefined members of FooStackable and overrides logic()):
scala> FooStackableTest.logic(4.0)
In FooStackableTest.logic()
In FooStackable.logic()
In TestStackable.logic()
scala> FooStackableTest.logic(-4.0)
In FooStackableTest.logic()
In FooStackable.logic()
foo
scala>
Suppose I have a trait like so:
trait A {
def x: Long
def y: Long
}
And I have a class which takes an A and needs to be an A:
case class B(a: A, foo: Foo, bar: Bar) extends A {
override def x = a.x
override def y = a.y
}
If A had lots of members, this would get annoying quickly. Is there a pattern that lets me "decorate" A with a foo and a bar?
I came up with such code, i don't know if it would be of any use for you:
object SelfAnnotationExample extends App{
trait A {
def x: Lon
def y: Long
}
trait ExtendedA extends A { self: InstanceProvider[A] =>
def x: Long = self.instance.x
def y: Long = self.instance.y
}
trait InstanceProvider[A] {
def instance: A
}
case class B(instance: A, foo: Any) extends ExtendedA with InstanceProvider[A]
case class TestA(x: Long, y: Long) extends A
val test = B(TestA(3, 4), 23)
println(test.x)
println(test.y)
}
I use scala feature known as "self type" (Someone correct me if i named it wrong). Trait InstanceProvider is not limited for this particular case. This solution need additional trait ExtendedA definition but every concrete implementation of A can utilize it.
If you want to call members from A on B and want to pass the A part of B to functions expecting A, you can achieve it using implicit conversion from B to A:
import scala.language.implicitConversions
object Main extends App{
trait A {
def x: Long
def y: Long
}
def processA(a: A) = ()
class Foo
class Bar
case class B(a: A, foo: Foo, bar: Bar)
implicit def bToA(b: B): A = b.a
case class TestA(x: Long, y: Long) extends A
val test = B(TestA(3, 4), new Foo, new Bar)
println(test.x)
println(test.y)
processA(test)
}
When I extend traits I can choose which method implementation 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's seems like it's 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 doesn't compile. Am I right and it's not possible? If I'm right, why is that and is there a workaround for it?
UPDATE:
Why do I needed in a first place? I was playing around with dependency injection using self-types instead of constructor injection. So I had a base trait Converter and child traits FooConverter and BarConverter. And I wanted to write it like that(which doesn't work of course):
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)
}
}
}
I thought it's because of generics, but it turned that it's not. So I was just wondering if it's possible to somehow invoke super method of chosen trait with self-types. Because with simple inheritance it's possible. As for my original problem I can write it like this and it will 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: FooConverter with BarConverter =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
Probably tighter abstraction, but I'm not sure if it's bad for this kind of situation and if I need such broad abstraction like Converter[A] at all.
Calling super methods from already constructed type is impossible (you can do it only from the inside). In your example, you're trying to call foo on the instance self, which is constructed in runtime, so foo is virtual and could be overridden - compiler doesn't know which actual implementation is going to be called (formal vs real type problem). So technically - it's impossible to do what you want (call virtual method as a static one).
The naive hack is :
trait CC extends A with B {
val b = super[A].foo
val a = super[B].foo
}
class C {
self: CC =>
}
It basically provides encapsulation you want - you might wanna redefine a and b in class C as they're not going to be available (in type C itself) till you mix C with CC.
Note that in every example you provide (including my naive solution) - resulting val c has access to foo anyway and which exact foo is going to be called depends on how do you mix A and B (A with B or B with A). So, the only encapsulation you get is that type C itself isn't going to have foo method. This means that self-type gives you kind of a way to temporary close (make private) a method in "subclass" without violating LSP - but it's not the only way (see below).
Besides all of that, cake-injection that you're trying to implement is considered impractical by some authors. You might want to have a look at Thin Cake Pattern - as a remark, I successfully used something like this in real project (in combination with constructor injection).
I would implement your converter services this way:
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 ...
This allows you to change/mock converter implementation when putting it all together.
I'd also notice that Converter[Bar] is nothing else but Function1[Bar, String] or just Bar => String, so actually you don't need separate interface for that:
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
You can also use def fooConverter(f: Foo): String = ??? instead def fooConverter: Foo => String = ???.
Talking about encapsulation - it's more weak here as you can access transitive dependencies, so if you really need it - use private[package] modifier.
Converters module:
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 = ???
}
Core module:
package client
import converters._
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can use objects object converters {...}; object client {...} instead of packages if you prefer.
This encapsulation is even stronger than self-type based one, as you can't access fooConverter/barConverter from the App object (in your example foo is still accessable from 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
^
Keep in mind that self types are meant to allow you to require that any client code that uses the trait you are mixing in must also mix in another trait. In other words it is a way of declaring dependencies. But it is not classical inheritance. So when you say class C { self: A with B => } A and B actually are not there at the time. You have just defined that the client code has to mix in A and B in order to then mix in C.
But for your specific use case, it seems like you can accomplish the same goal with something like this code. In other words first create a third trait and then extend it into a specific class.
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
}
}