Say I have these two classes:
class A {
def foo(i: String) = println(s"${i}")
def foo(i: String, j: Int) = println(s"${i} ${j}")
}
class B {
def foo(i: Int) = println(s"${i}")
def foo(i: Int, j: String) = println(s"${i} ${j}")
}
I have the variable with the same name as a global variable and as a method in a class:
val inst = A()
abstract class AppB extends App {
def inst = B()
}
I extend the above:
object MyApp extends AppB {
// Should reference A
inst.foo("s11")
inst.foo("s22", 11)
// Should reference B
inst.foo(33)
inst.foo(44, "s33")
}
Assuming I do not want to rename, is there a way to:
Reference the global val inst?
"Shadow" def inst somehow, so that I can only use the global val inst one?
From https://dotty.epfl.ch/docs/reference/dropped-features/package-objects.html:
If a source file src.scala contains such top-level definitions, they will be put in a synthetic object named src$package
Maybe using the "auto-generated" object name to access val inst can work in this case?
Related
I have an implicit class that needs to use a given parameter at runtime. So I define this implicit in another class that takes this parameter in the constructor. A simplified version of what I am doing is as follows:
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(p2: String) {
implicit class Enhancer(a: A) {
implicit def bar = s"bar: ${a.p1}, $p2"
}
}
So when I need to use this class I then do the following:
val a = A("x")
val b = new B("y")
import b._
a.bar
I am wondering if there is a neater way than the above? Specifically the middle two lines where I define the object and then import from it. For example is there any way I could have a one line call to return the implicit class I need?
Try to add implicit parameter to Enhancer.
case class A(p1: String) {
def foo = println("foo: " + p1)
}
class B(val p2: String)
implicit class Enhancer(a: A)(implicit b: B) {
implicit def bar = s"bar: ${a.p1}, ${b.p2}"
}
val a = A("x")
implicit object b extends B("y")
a.bar
or
implicit val b = new B("y")
a.bar
Or
implicit class Enhancer(val a: A) extends AnyVal {
implicit def bar(implicit b: B) = s"bar: ${a.p1}, ${b.p2}"
}
Say I have the following trait:
trait T {
val x: Int
}
def foo(i: Int): T
I would like to bet able to write and read this trait using upickle without knowing what the specific class is. e.g.:
upickle.default.write(foo(3))
Such that I could elsewhere define foo to be something like:
case class A(x: Int)
def foo(i: Int): T = A(i)
I am thinking I need to define an implicit Writer as a member of T but I don't know what the appropriate syntax would be?
trait T {
val x: Int
}
object T {
implicit val rw: ReaderWriter[T] = ...
}
The problem is what to put into the ... part: if you have a T value, you can just store its x:
... = readwriter[Int].bimap[T](
t => t.x,
i => new T { val x = i }
)
The problem with this solution is that reading a written A(3) won't return an A. And this isn't really solvable without making T sealed or otherwise handling a specific set of subclasses only.
You could include a class name as well when writing, but that won't help if the class has any fields other than x to store:
class B(override val x: Int, y: String) extends T
If T is sealed, you just write
... = macroRW
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 hierarchy:
abstract class A(val x: Int, val y: String)
class B(override val x: Int, override val y: String, val z: Int) extends A(x,y)
Now I want to initialize the values from a configuration object but I want the actual values to be the original ones.
If I would do the configuration in B only then I would do something like:
class B(override val x: Int, override val y: String, val z: Int) extends A(x,y)
def this(conf: Conf) {
this(conf.get("x"), conf.get("y"), conf.get("z"))
}
but I want to be able to do the same in A.
If I add:
abstract class A(val x: Int, val y: String)
this(conf: Conf) {
this(conf.get("x"), conf.get("y))
}
I wouldn't be able to define B (I don't have the conf in the B default constructor).
EDIT:
To make this clearer:
The use case I have is a factory which generates the proper B (there are a large number of child classes). It does so by doing something like:
def getElement(elemType: String, conf: Conf): A = {
elemType match {
case "B" => new B(conf)
}
}
Currently, I have a companion object:
object B {
def apply(conf: conf) = B(conf.getx(), conf.gety(), ...)
}
The problem is that when I need to add a new element to the parent A, I need to go and change every one of the children and I have the same code conf.getx(), conf.gety() etc.
Ideally I would like B constructor to be able to do something like:
class B(conf: Conf) extends A(conf)
but I can't do this as this would make conf into a member of B.
You can also use companion objects to define alternative constructors:
case object A {
def apply(conf: Conf): A = new A(conf.get("x"), conf.get("y"))
}
case object B {
def apply(conf: Conf): B = new B(conf.get("x"), conf.get("y"), conf.get("z"))
}
After looking around some more I found this (also points to this) and this. All three basically say the following:
If we use an argument without val or var and it is only referenced in the constructor then it does NOT become a member.
This means the following solution would work:
abstract class A(conf: Conf) {
val x = conf.getX()
val y = conf.getY()
}
class B(conf: Conf) extends A(conf) {
val z = conf.getZ()
}
would provide the required behavior cleanly and simply.
As I understand the semantics of a custom constructor may be typically added to a class via a companion object. Is there then, any way to inherit a custom constructor while inheriting a class?
On the one hand I have found that companion objects are not synthetically inherited along a case class, and on the other, I am not aware of a way of creating custom constructors inside a class itself, so that they are inherited. And yet inheriting custom constructors seems to be a perfectly valid use case to me. So is it supported in some (straightforward) way in Scala?
A naive demonstration of intent:
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
P.S. I have even found the arcane/deviant technique of defining this custom constructors result in a custom constructor that does not in actuality get inherited (it does work for just creating custom constructors, but quite oddly and unfortunately those do not get inherited). Demonstrating code:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
Clarification of Intent Edit:
consider "constructor" and "companion factory methods" interchangeable for the sake of this question.
You can't inherit constructors directly, and because you can't you also can't inherit things that use them without a little bit of work. But you can abstract away anything beyond the constructor call.
Let's suppose we have
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
and we then decide to
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
Now, what do we do about object Bar? Instead of writing all the logic over again, we create a trait to separate and abstract the object creation from the computation of the constructor parameter(s):
trait FooCompanionLike[A <: Foo] {
def apply(text: String): A // I am abstract!
def apply(i: Int): A = apply(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
Now we can
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
So you can't completely escape boilerplate, but you can reduce it to extending from a trait and a single method call.
If you do it this way (where the abstract apply perfectly matches the constructor), you can even get case classes to work without manually defining the abstract apply method in the companion:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
Short answer: no straightforward way; try to workaround and resist the desire.
Constructors in Scala are defined in the body of the class and take parameters after the class name e.g.
class A(i: Int) {
println(i)
}
The println(i) in this case is the constructor logic. If you now extend A, like this:
class B(i: Int) extends A(i)
and instantiate B, val b1 = new B(2) you'll see that the constructor is indeed inherited.
As you've already found out, Scala allows you to define alternative constructors by defining functions called this. But these alternative constructors must call the primary constructor.
The way I understand it is that there is really only one constructor for any Scala class, the alternative constructors just filter into it. For example:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}