If I understand correctly, traits are the closest thing to Java interfaces and class constructors automatically set the variables.
But what if I have a class that extends a trait and has a constructor which sets a variable from the trait, so something like:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Where I want the foo string of the trait been set when I make a Bar object.
The compiler seems to give me errors about this. What is the correct way to achieve this?
trait Foo { var foo: String = _ }
class Bar(foo0: String) extends Foo { foo = foo0 }
The trait declares an uninitialized var; the class then sets it equal to the input parameter.
Alternatively,
trait Foo {
def foo: String
def foo_=(s: String): Unit
}
class Bar(var foo: String) extends Foo {}
declares the getter/setter pair corresponding to a foo, which are set by the class.
Bar must define the abstract var foo in Foo (would be the same for a val). This can be done in the constructor
class Bar(var foo: String) extends Foo{...}
(of course, it could be done in the body of Bar too). By default, constructor parameters will be turned to private val if need be, that is if they are used outside the initiailization code, in methods. But you can force the behavior by marking them val or var, and possibly control the visibility as in
class X(protected val s: String, private var i: Int)
Here you need a public var to implement Foo.
Related
When we have a case class, we call map the type with the name of the type, e.g.:
case class Foo(value: String)
val value = Some("Yay!")
val foo = value.map(Foo)
But if we also provide a companion object, this stops working value.map(Foo) and looks like this works: value.map(Foo(_)). Why?
case class Foo(value: String)
object Foo {}
val value = Some("Yay!")
val foo = value.map(Foo)
println(foo)
ScalaFiddle.scala:5: error: type mismatch;
found : ScalaFiddle.this.Foo.type
required: scala.this.Function1[lang.this.String,?]
val foo = value.map(Foo)
If you don't define object Foo at all, then the synthetic companion object has the following declaration:
<synthetic> object Foo
extends scala.runtime.AbstractFunction1[String,Foo]
with Serializable
But if you define your own object Foo as follows
case class Foo(v: String)
object Foo {}
then the declaration of the Foo object changes accordingly to:
object Foo extends scala.AnyRef with Serializable
and it no longer extends Function1.
The method apply(v: String): Foo is still automatically generated on Foo, but it no longer implements the Function1[String, Foo] interface. If you declare the companion object like this:
object Foo extends (String => Foo) { ... }
then you again can use it in expressions like value.map(Foo).
The value.map(Foo(_)) syntax always works, because it's just a shortcut for
value.map(x => Foo.apply(x))
and the closure doesn't care at all about what interfaces are implemented by Foo, it cares only about the existence of the apply method.
For example, there are two scala class called A and B.
class A{
val aVariable:String="a"
}
class B(val newVariable:String) extends A{
def newMethod(): Unit ={
}
}
The problem is how to use an A object to instantiate a B object with its variable?
For example, a function take an A object and a string to create a B object
val bObject:B=BuildFunc(new A(),"string")
And if A contains much variables, is there a way to avoid setting each of manually?
It seems in Java this could be done by code like super(aObject), is there equivalent method in Scala?
There's multiple solutions here. For example, one would be defining A's promoting the A's constructor parameters into fields:
class A(val foo: String)
class B(override val foo: String, val baz: String) extends A(foo)
If you can't change A's definition though then maybe this will help:
class A {
val foo: String = "foo"
}
class B(override val foo: String, val baz: String) extends A
Hope that helps.
Given:
class Foo(x: Int) {}
object Foo {
def apply(x: Int) = new Foo(x)
}
Besides marking Foo's constructor as private, how can I present a warning or compile-time failure when calling new Foo(...)?
In other words, I'd like to restrict (either by compile-time warning or error) construction of Foo to Foo.apply.
Is this possible?
In scala there are two idiomatic ways how to achieve that.
Constructor private to the class and companion object.
Factory has access to constructor, while anyone else doesn't:
class Foo private[Foo](val x: Int)
object Foo {
def apply(x:Int) = new Foo(x)
}
val foo = new Foo(1) // cannot compile
val foo1 = Foo(1) //compiles fine
Sealed abstract class.
In scala sealed class can be extended only in the same source file it is defined.
I suggest to make Foo sealed abstract class and return anonymous child of Foo in object's apply method.
sealed abstract class Foo(val x:Int)
object Foo {
def apply(x:Int):Foo = new Foo(x) {}
}
In this case Foo can be created nowhere except the file where it is defined.
UPD: Actually, this question was already discussed on stackoverflow.
UPD2: Added brief overview of both methods.
In the following code:
trait Base {
val foo: String = {
println("Hi, I'm initializing foo in trait Base")
"foo"
}
}
class Overrider extends Base {
override val foo = "bar!"
}
object Runner extends App {
println(new Overrider().foo)
println((new {override val foo = "baz"} with Base).foo)
}
Base trait's foo value initialisation is called regardless of whether I override the val by extending the trait or using an early initialiser:
Hi, I'm initializing foo in trait Base
bar!
Hi, I'm initializing foo in trait Base
baz
Is there a way to use vals and avoid that happening or should I just stick with lazy vals?
Either use lazy val as you mentioned or def. AFAIK there is no other way to avoid the initialization of vals in base classes. This is because everything outside class member definitions goes into the constructor. Therefore vals will be initialized on construction time.
Another approach would be to define an interface which you extend from:
trait Base {
def foo: String
}
class Foo extends Base {
override val foo = "foo"
}
class Bar extends Base {
override val foo = "bar"
}
As other users answered to your question, you have to define foo as a def if you do not want the Base trait method being valuated.
You told to me in the comments of your question that you were trying to implement a wiring module, as the one described in this link. Then, you're basically trying to implement the thin cake pattern.
In this case, it is not logically correct to declare foo as a val. foo represents a dependency that cannot be eagerly resolved . If you use a val, the two components will be tight coupled. You've to define foo as a def to let to your main application (or test) to wire foo to the correct type, i.e. a concrete class or a mock.
Let me know if you want some more explanations.
I'm just learning about classes and objects and Scala, and yesterday I saw something like this:
class Foo(bar: Int) {
def increaseByOne = bar + 1
}
Why am I able to use bar in method increaseByOne? I would expect the the method definition complain about not knowing bar.
I though the right way to define such a class would be
class Foo(x: Int) {
val bar = x
def increaseByOne = bar + 1
}
That's one of the wonderful features of Scala: if you reference constructor argument from any method that is not a constructor, Scala will automatically assign that constructor variable to a field. So effectively Scala translates your first code snippet into the second one for you (with private[this] modifier).
Moreover, preceding constructor argument with val/var will create getters/setters as well:
class Foo(val bar: Int)
val foo = new Foo(42);
println(foo.bar)
In this case bar is defined as private[this] and can be acessed within the class definition. You can check it with -Xprint:typer option:
class Foo extends java.lang.Object with ScalaObject {
<paramaccessor> private[this] val bar: Int = _;
def this(bar: Int): $line1.$read.$iw.$iw.Foo = {
Foo.super.this();
()
}
}