In Scala no methods can be invoked on the current instance when the superclass constructor is called. So there is no opportunity for a method to be invoked which will memorise the value that it is returning, in the current instance. How can I retain the arguments produced to give to a superclass constructor, while still using inheritance, as opposed to composition, and without modifying the source code of the class I'm inheriting from?
You can also use
class Foo(arg1: Type1, arg2: Type 2)(
implicit computed: Hidden[(Type3,Type4)] = (new Type3(arg1), new Type4(arg2))
) extends Bar(computed._1, computed._2) { }
given
private[mypackage] class Hidden[A](val value: A) { }
implicit def i_can_hide_things[A](a: A) = new Hidden(a)
implicit def i_can_find_things[A](ha: Hidden[A]) = ha.value
In Scala 2.8 and above, use an early definition:
class Foo(arg1: Type1, arg2: Type2) extends {
val arg3 = new Type3(arg1)
val arg4 = new Type4(arg2)
} with Bar(arg3, arg4)
This works even if Bar is a class rather than a trait.
Create a companion object with a factory method. The factory method computes the arguments to pass them to the superclass constructor. But it doesn't do so directly, of course - it can't. Instead, it calls your primary constructor, which you can make private, like this:
class C private (private val superclassArg: ArgType) extends Super(superclassArg) { ... }
Unfortunately this solution isn't very compositional, because it doesn't allow you to inherit from C. Making the constructor of C public would, but it would still require duplicating code, and you could forget to preprocess the constructor argument. I suppose it depends whether you think it will always be essential for subclasses of C to preprocess the argument in this way.
Intersperse another class (here MemoBar) into the inheritance hierarchy, like this:
class Foo(arg1: Type1, arg2: Type2) extends MemoBar(new Type3(arg1), new Type4(arg2)) {
}
class MemoBar(protected val arg3: Type3, arg4: Type4) extends Bar(arg3, arg4) {}
Then your arg3 and arg4 will be retained and visible only to subclasses of MemoBar (in this case, just Foo, but of course you could reuse MemoBar if you faced the same problem with Bar again).
Related
I just learned about the scalar to study rocket chips.
I see some strange codes in the Config.scala of Rocket-chip
abstract class Field[T] private (val default: Option[T])
{
def this() // 1st-this
= this(None) // 2nd-this
def this(default: T) // 3rd-this
= this(Some(default)) // 4th-this
}
The above code has 4 of this. I think 2nd/4th-this are identical.
But I'm not sure 2nd/4th-this are represent Field class self-type or not.
If they are self-type, 1st/3rd-this are to be what??
I'm frustrated since I can't tell the definition of the above four this.
Could you explain this?
These are called auxiliary constructors (see https://docs.scala-lang.org/scala3/book/domain-modeling-tools.html#classes).
The "main constructor" is the one defined by the class declaration:
class Field[T] private (val default: Option[T])
With this you can create instances of Field only by passing a Option[T]. Like Field(None) or Field(Some(...)).
Then, you have 2 additional auxiliary constructors. They are defined as regular methods but they need to be called this.
The following adds a constructor that accepts no parameter so that you can create instances with Field() and it will be the same as Field(None). The 2nd this refers to the main constructor.
def this() = this(None)
Same principle for the other auxiliary constructors which allows to call Field(x) instead of Field(Some(x)).
Note that you could achieve the same with apply methods in a companion object.
Assume the following pair of classes:
class A(arg:String)
class B(argList:Vector[String]) extends A(argList.first)
I want to be able to check for argList being empty before providing the base class constructor with its first element. Unfortunately, placing that check in the default constructor for B (e.g through require, as shown here) is way too late, since the base class' constructor will need to be called first.
This is probably a more general OOP question, but the solution is likely to be Scala-specific.
What do you expect to pass if argList is empty? In any case, you could just use the following:
class B(argList:Vector[String]) extends A(argList.headOption.getOrElse("your default string here")
One way to deal with this is via a companion object. You can mark the constructor for B as private to ensure no-one can by-pass the check, then add a suitable apply method to the companion object that pre-checks the input value(s):
class A(arg:String)
class B private(argList:Vector[String]) extends A(argList.head)
object B {
def apply(argList:Vector[String]): B = argList.headOption.map(_ => new B(argList)).getOrElse(throw new RuntimeException("Oops"))
}
Usage examples:
scala> B(Vector("foo", "bar"))
res2: B = B#328e9109
scala> B(Vector())
java.lang.RuntimeException: Oops
at B$$anonfun$apply$2.apply(<console>:24)
...
Note that for simplicity's sake, I simply throw an exception when handling bad data, but would probably try some other way of handling this situation (a default value per #Zoltan's answer is one such way).
That's why in most places constructors are replaced by factory objects. In Scala it's idiomatic to use companion object as such factories.
class A(arg: String)
abstract class B(arg: String) extends A(arg) {
def argList: IndexedSeq[String]
}
object B {
case object Empty extends B("") {
def argList = IndexedSeq.empty
}
case class NonEmpty private[B](argList: Vector[String]) extends B(argList.head)
def apply(argList: Vector[String]) =
if (argList.isEmpty) Empty else NonEmpty(argList)
def unapplySeq(b:B): Option[IndexedSeq[String]] = b match {
case Empty ⇒ Some(IndexedSeq.empty)
case NonEmpty(args) ⇒ Some(args)
}
}
you could verify that
B(Vector()) == B.Empty
B(Vector("x", "y")).isInstanceOf[B.NonEmpty]
In my specific case I have a (growing) library of case classes with a base trait (TKModel)
Then I have an abstract class (TKModelFactory[T <: TKModel]) which is extended by all companion objects.
So my companion objects all inherently know the type ('T') of "answers" they need to provide as well as the type of objects they "normally" accept for commonly implemented methods. (If I get lazy and cut and paste chunks of code to search and destroy this save my bacon a lot!) I do see warnings on the Internet at large however that any form of CompanionObject.method(caseClassInstance: CaseClass) is rife with "code smell" however. Not sure if they actually apply to Scala or not?
There does not however seem to be any way to declare anything in the abstract case class (TKModel) that would refer to (at runtime) the proper companion object for a particular instance of a case class. This results in my having to write (and edit) a few method calls that I want standard in each and every case class.
case class Track(id: Long, name: String, statusID: Long) extends TKModel
object Track extends TKModelFactory[Track]
How would I write something in TKModel such that new Track(1, "x", 1).someMethod() could actually call Track.objectMethod()
Yes I can write val CO = MyCompanionObject along with something like implicit val CO: ??? in the TKModel abstract class and make all the calls hang off of that value. Trying to find any incantation that makes the compiler happy for that however seems to be mission impossible. And since I can't declare that I can't reference it in any placeholder methods in the abstract class either.
Is there a more elegant way to simply get a reference to a case classes companion object?
My specific question, as the above has been asked before (but not yet answered it seems), is there a way to handle the inheritance of both the companion object and the case classes and find the reference such that I can code common method calls in the abstract class?
Or is there a completely different and better model?
If you change TKModel a bit, you can do
abstract class TKModel[T <: TKModel] {
...
def companion: TKModelFactory[T]
def someMethod() = companion.objectMethod()
}
case class Track(id: Long, name: String, statusID: Long) extends TKModel[Track] {
def companion = Track
}
object Track extends TKModelFactory[Track] {
def objectMethod() = ...
}
This way you do need to implement companion in each class. You can avoid this by implementing companion using reflection, something like (untested)
lazy val companion: TKModelFactory[T] = {
Class.forName(getClass.getName + "$").getField("MODULE$").
get(null).asInstanceOf[TKModelFactory[T]]
}
val is to avoid repeated reflection calls.
A companion object does not have access to the instance, but there is no reason the case class can't have a method that calls the companion object.
case class Data(value: Int) {
def add(data: Data) = Data.add(this,data)
}
object Data {
def add(d1: Data, d2: Data): Data = Data(d1.value + d2.value)
}
It's difficult. However you can create an implicit method in companion object. whenever you want to invoke your logic from instance, just trigger implicit rules and the implicit method will instantiate another class which will invoke whatever logic you desired.
I believe it's also possible to do this in generic ways.
You can implement this syntax as an extension method by defining an implicit class in the top-level abstract class that the companion objects extend:
abstract class TKModelFactory[T <: TKModel] {
def objectMethod(t: T)
implicit class Syntax(t: T) {
def someMethod() = objectMethod(t)
}
}
A call to new Track(1, "x", 1).someMethod() will then be equivalent to Track.objectMethod(new Track(1, "x", 1)).
This topic has been discussed before but not answered satisfactorily (in my opinion).
Consider the following scala code:
class A(a:Int) { val _a=a }
class A1(val a:Int) { val _a=a }
class B(a:Int) extends A(a) // OK
class C(val a:Int) extends A(a) // OK
class B1(a:Int) extends A1(a) // OK
class C1(val a:Int) extends A1(a) // fails
class D1(override val a:Int) extends A1(a) // OK
I believe that declaring the class parameter as val only has an effect on the constructor call:
the parameter is copied instead of passing a reference. However in each case the class field is allocated as a val. is this correct?
Now what I do not understand is why we need the override keyword in the last line.
Note that we do not declare the classes as case classes so no automatic allocation of fields is going on.
Finally is there a good reason why one even would want to define a class like A1 with a val
class parameter?
Thanks in advance for all replies.
I believe that declaring the class parameter as val only has an
effect on the constructor call: the parameter is copied instead of
passing a reference. However in each case the class field is allocated
as a val. is this correct?
Not at all.
If there is a val or var in the constructor, that causes a val or var of the same name to be declared in the class, and assign the constructor parameter to it at construction. Otherwise, a (private) val may still be created in the class, if the constructor parameter is used outside initialization, i.e in a method.
In class A1, the member _a is really useless, because if you write
class A1(val a: Int) {}
it is equivalent to
class A1(someFreshName: Int) {val a = someFreshName}
So in C1, you are trying to declare a new member a, while there is already one. Hence the override.
In your particular instance, both member would have the same value, but you could well do (maybe not a good idea)
class C1(override val a: Int) extends A1(12)
Then, the new member a would have the constructor parameter as value, and the previous a would have value 12 and be hidden (but still, code written in A1 would access it).
Can this be done?
final case class C[A] (v: A) {
def this() = this(true)
}
When constructed with given constructor, C is automatically a C[Boolean]. This version does not compile but it feels like it should be doable somehow, especially as the following seems to work:
final case class C[A] (v: A = true)
I want some Java interoperability, so I try to avoid default values. I think that I can achieve this by using factory methods in a companion object, but can it be done directly? As C is a case class, factory methods are a bit messy IMHO.
What is wrong with
object C{
def apply() = C(true)
}
such that you use the companion object? In Java, this would be, C$.apply() no?
I suspect factory methods in the companion object are the best you can do (as wheaties has suggested). We can make it compile, but at the expense of sillyness down the line. For example:
final case class C[A] (v: A) {
def this() = this("Hello".asInstanceOf[A]) // Compiles, thanks to type erasure
}
val c = new C[Int]() // Still compiles, despite the fact that "Hello" is not an Int
println(c) // C(Hello)
c.v + 1 // Compiles, but throws a ClassCastException at run-time
The basic problem is that type parameters are specified at the class level, not the constructor level, so all constructors have to use the same type parameters. On the other hand, methods can take type parameters, so factory methods are no problem. Also, Java Interop for factory methods isn't all that bad. You could do something like:
// C.scala
final case class C[A] (v: A)
object C {
def apply(): C[Boolean] = C(true)
}
// Test.java
public class Test {
public C c = C.apply();
}
The scala compiler creates static methods to simplify Java interop, so you don't usually need to mess around with C$.