How to call `apply` on a superclass in Scala? - scala

My class inherits from some base class, and implements apply method with exactly the same signature as the base's one. I want to call base's apply method from my class.
When I try following:
class MyClass extends BaseClass {
def apply(k: String, v: String) = {
super.apply(k, v)
...
}
...
}
I got value apply is not a member of BaseClass... compile error.
How should I call base's apply method from the child class?
Also, why it is possible to override apply method without an override keyword?
EDIT: Actual code:
class OAuthParamsBuilder(helper: OAuthParamsHelper)
extends KeyValueHandler {
def apply(k: String, v: String): Unit = {
...
}
}
class OAuthInitSupportBuilder
extends OAuthParamsBuilder(StandardOAuthParamsHelper) {
/*override*/ def apply(k: String, v: String): Unit = {
super.apply(k, v)
...
}
...
}
EDIT: I've noticed that KeyValueHandler is a trait, this may be an issue.
trait KeyValueHandler extends ((String, String) => Unit)

You are not helping us help you, but I suspect this is the true definition of apply on the base class:
def apply(kv: (String, String)) = ???
EDIT
The code you pasted is not enough, as the problem is not reproducible with it:
trait OAuthParamsHelper
trait KeyValueHandler
class OAuthParamsBuilder(helper: OAuthParamsHelper) extends KeyValueHandler {
def apply(k: String, v: String): Unit = ???
}
object StandardOAuthParamsHelper extends OAuthParamsHelper
class OAuthInitSupportBuilder extends OAuthParamsBuilder(StandardOAuthParamsHelper) {
override def apply(k: String, v: String): Unit = {
super.apply(k, v)
???
}
}

Related

Defining a generic to be a case class

In this example, I want the generic T to be a case class and a DAOEntity with id, so in the abstract implementation, I can use the copy method.
How to define it?
trait DAOEntity {
def id: String
}
// How to define this generic to force the use of a `case class` to have access to `copy`?
abstract class DAO[T <: DAOEntity] {
def storeInUppercase(entity: T): T = entity.copy(id = entity.id)
}
case class MyEntity(id: String) extends DAOEntity
class MyEntityDAO extends DAO[MyEntity] {
// Other stuff
}
There is no way to know if a type is a case class or not.
And even if there was, you won't get the copy method. The language doesn't provide a way to abstract over constructor; thus neither copy and factories (apply on companions) by extension. Which makes sense, what would be the type signature of such function?
What you can do instead is create a factory-like typeclass and ask for that:
trait DAOFactory[T <: DAOEntity] {
def copy(oldEntity: T, newId: String): T
}
object DAOFactory {
def instance[T <: DAOEntity](f: (T, String) => T): DAOFactory[T] =
new DAOFactory[T] {
override final def copy(oldEntity: T, newId: String): T =
f(oldEntity, newId)
}
}
Which can be used like this:
abstract class DAO[T <: DAOEntity](implicit factory: DAOFactory[T]) {
def storeInUppercase(entity: T): T =
factory.copy(
oldEntity = entity,
newId = entity.id.toUpperCase
)
}
And entities would provide the instance like this:
final case class MyEntity(id: String, age: Int) extends DAOEntity
object MyEntity {
implicit final val MyEntityFactory: DAOFactory[MyEntity] =
DAOFactory.instance {
case (oldEntity, newId) =>
oldEntity.copy(id = newId)
}
}
// This compile thanks to the instance in the companion object.
object MyEntityDAO extends DAO[MyEntity]
You can see the code running here.

Scala object extends abstract class/trait, access companion class fields

Currently I have the following code:
case class Foo(text: String, tag: Tag) {...}
object Foo {
def doSomething(fooSeq: Seq[Foo]) = fooSeq.map(f => f.tag)
def doSomethingElse() = {...}
}
I would like to move the doSomething method into an abstract class/trait so I can parametrize the tag and reuse the code later. Ideally, I'd like to do something like this:
case class Foo(text: String, tag: Tag) {...}
object Foo extends TraitFoo[Tag] {
def doSomethingElse() = {...}
}
---------------in another file----------------
trait TraitFoo[T] = {
def doSomething(fooSeq: Seq[TraitFoo[T]]) = fooSeq.map(f => f.tag)
}
However, the compiler complains that it cannot recognize f.tag inside TraitFoo.
I considered using an abstract class, but that also causes issues, because my object Foo does not need a constructor. It only needs to access the fields in its companion class.
Perhaps you can add another type parameter to TraitFoo with a structural bound? Like this:
trait TraitFoo[A, B <: { def tag: A }] {
def doSomething(fooSeq: Seq[B]): Seq[A] = fooSeq.map(f => f.tag)
}
case class Foo(text: String, tag: Tag) { ... }
object Foo extends TraitFoo[Tag, Foo] {
def doSomethingElse() = { ... }
}
This would be essentially the same as this, but a bit less verbose / less explicit:
trait Tagged[A] {
def tag: A
}
trait TraitFoo[A, B <: Tagged[A]] {
def doSomething(fooSeq: Seq[B]): Seq[A] = fooSeq.map(f => f.tag)
}
case class Foo(text: String, tag: Tag) extends Tagged[Tag] { }
object Foo extends TraitFoo[Tag, Foo] {
def doSomethingElse() = { }
}

How to make method return type covariant

I have a following classes:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager[T <: Foo](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
And of course update function does not compiles:
Type missmatch found Foo required T
How to make def update: Foo covariant?
Looks like you want something like F-bounded polymorphism:
trait Foo[T <: Foo[T]] { self: T =>
def update: T
}
class ConcreteFoo extends Foo[ConcreteFoo] {
override def update = new ConcreteFoo
}
class FooManager[T <: Foo[T]](val foos: mutable.Map[String, T]) {
def update(id: String): Unit = {
foos.update(id, foos(id).update)
}
}
An alternative, and probably simpler, solution is to use an immutable Map, as Luka said. But then there's no need to have type parameters anymore:
trait Foo {
def update: Foo
}
class ConcreteFoo extends Foo {
override def update: Foo = new ConcreteFoo
}
class FooManager(private var _foos: immutable.Map[String, Foo]) {
def foos = _foos
def update(id: String): Unit = {
_foos = _foos.updated(id, _foos(id).update)
}
}
You could also keep your current solution and remove the type parameter. But then you have the slight inconvenience that you can't pass a mutable.Map[String,ConcreteFoo] to the constructor of FooManager.
I'd suggest going with an immutable Map instead. As only immutable collections can have covariant type parameters.
class FooManager[+T <: Foo](val foos: immutable.Map[String, T]) {
def update(id: String): FooManager[Foo] = {
new FooManager(foos.updated(id, foos(id).update))
}
}

Using trait method in the class constructor

I have a trait and a class that extends the trait. I can use the methods from the trait as follows:
trait A {
def a = ""
}
class B(s: String) extends A {
def b = a
}
However, when I use the trait's method in the constructor like this:
trait A {
def a = ""
}
class B(s: String) extends A {
def this() = this(a)
}
then the following error appears:
error: not found: value a
Is there some way to define default parameters for the construction of classes in the trait?
EDIT: To clarify the purpose: There is the akka-testkit:
class TestKit(_system: ActorSystem) extends { implicit val system = _system }
And each test looks like this:
class B(_system: ActorSystem) extends TestKit(_system) with A with ... {
def this() = this(actorSystem)
...
}
because I want to create common creation of the ActorSystem in A:
trait A {
val conf = ...
def actorSystem = ActorSystem("MySpec", conf)
...
}
It's a little bit tricky because of Scala initialization order. The simplest solution I found is to define a companion object for your class B with apply as factory method:
trait A {
def a = "aaaa"
}
class B(s: String) {
println(s)
}
object B extends A {
def apply() = new B(a)
def apply(s: String) = new B(s)
}

Scala constructor signature

Is it possible to define constructor signature in Scala ?
abstract class A {
def this (s: String): this.type // doesn't work
def this (i: Int): this.type // doesn't work
def this (d: Double): this.type // doesn't work
}
class B(var s: String) extends A {
def this(i: Int) = {
this("int "+i.toString())
}
def this(d: Double) = {
this("double "+d.toString())
}
}
What are you trying to achieve? You can do like this:
abstract class A(i: Int)
case class B(s: String) extends A(s.toInt) {
def this(i: Int) = {
this(i.toString)
}
def this(d: Double) = {
this(d.toString)
}
}
Usage:
B("1")
new B(1)
new B(1.0)
You can't do exactly what you want, as pointed out by other answer, but one approach is to use a factory:
trait Foo {
// methods you need
}
trait FooCompanion[T <: Foo] {
// these methods replace constructors in your example
def apply(s: String): T
def apply(i: Int): T
...
}
Implementation:
class Bar(s: String) extends Foo {
...
}
object Bar extends FooCompanion[Bar] {
def apply(s: String) = new Bar(s)
...
}
and you can have methods taking FooCompanion. This pattern is used e.g. in the Scala collections library.
No that is not possible. Constructors are special: You need to write new X() instead of X(), and there is no polymorphic dispatch, e.g. you cannot do def test[A]() = new A(). So there is no scenario in which an abstract constructor would make any sense.