Right now I'm writing a lot of code like the following example, but the apply methods are almost equal, the only thing that changes is the resulting class. Would it be possible to use the same apply method to instantiate different implementations of a trait?
trait Base {
def name: Option[String]
def value: Int
}
case class AnImplementatation(override val name: Option[String]) extends Base {
override def value: Int = name.map(_.length).getOrElse(0)
}
object AnImplementatation {
def apply(name: String): AnImplementatation = AnImplementatation(Some(name))
}
case class AnotherImplementatation(override val name: Option[String]) extends Base {
override def value: Int = name.map(_.length).getOrElse(0) * 2
}
object AnotherImplementatation {
def apply(name: String): AnotherImplementatation = AnotherImplementatation(Some(name))
}
Related
//File Animal.scala
abstract class Animal {
val name: String
def getSomething(tClass: TypeClass): String = {
tClass.tName.split('.').lift(0)
}
def apply(tClass: TypeClass): SomeOtherClassType = {
// something...
}
// File: DogSpike, this is used for some specific cases (overwrites
base class val)
object DogSpike extends Animal {
override val name: String = "Spike"
}
this call then works (calls apply)
myTransformation(() => DogSpike(this))
Now I would like to create a more generic object that one can pass arguments but I am unable to.
It would work to create a derived Object from Animal that takes one arguments and being able to use the apply call
object TheDog(name: String) extends Animal {
override val name: String = "Spike"
//...
}
not sure how to implicitly call Animal.apply for TheDog object where I could pass a parameter (name)
myTransformation(() => TheDog(this))
// also this seems to be incorrect "*Wrong top statement declaration*"
object TheDog(val n: String) extends Animal {
override val name: String = n
//...
}
As of *Wrong top statement declaration* (I can understand only this part of your question) - you can't have constructor in object as object is a singleton, so you should use a case class (ADT):
final case class TheDog(name: String) extends Animal
scala>TheDog("Spike")
res2_2: TheDog = TheDog("Spike")
val and companion object with apply is added automatically for case classes, so you don't need to define your own own apply in Animal. case class TheDog(val name: String) is same as case class TheDog(name: String).
I's also use traits instead of abstract class:
trait Animal {
val name: String
def getSomething: String = {
"Dog: " + name
}
}
I don't understand your TypeClass type, but if you really want type classes:
trait Animal {
def name: String
}
final case class TheDog(name: String) extends Animal
final case class TheCat(name: String) extends Animal
implicit class RichDog(dog: TheDog){
def getSomething: String = {
"Dog" + dog.name
}
}
implicit class RichCat(cat: TheCat){
def getSomething: String = {
"Cat: " + cat.name
}
}
scala> TheDog("Spike").getSomething
res4_5: String = "DogSpike"
scala> TheCat("Tom").getSomething
res4_6: String = "Cat: Tom"
About calling apply "implicitly", I don't know why would anyone need this, but:
trait AnimalFactory[A <: Animal] {
def apply(name: String)(implicit constructor: String => A) = constructor(name)
}
object TheeeDog extends AnimalFactory[TheDog]
implicit def createDog(name: String) = TheDog(name)
TheeeDog("Spike")
Of course you have to provide createDog and make it visible for a client, but it doesn't really make sense if you can just use ADTs and define additional required applys in companion object:
case class TheMouse(name: String)
object TheMouse{
def apply(isJerry: Boolean): TheMouse = if (isJerry) TheMouse("Jerry") else TheMouse("NotJerry")
}
TheMouse(true)
If you want to add some parameter to constructor, just add it:
class AnimalFactory(clazz: SomeClass){
def doSomething = clazz.name
def apply(name: String)
}
val dogFactory = new AnimalFactory(dogClassDescriptor)
val catFactory = new AnimalFactory(catClassDescriptor)
dogFactory("Spike")
catFactory("Tom")
You can even create a factory for factory (I wouldn't recommend - this solution already looks overcomplicated):
object AnimalFactory{ //please don't use classes for that - avoiding `new` is not their purpose
def apply(clazz: SomeClass) = new AnimalFactory(clazz)
}
val dogFactory = AnimalFactory(dogClassDescriptor)
//or even `val spike = AnimalFactory(dogClassDescriptor)("Spike")`
But still what's the point if you could just provide underlying clazz either as a member or just in a wrapper:
final case class ClazzWrapper[T <: Animal](clazz: SomeClass, animal: T)
I am trying to create a type class in Scala and use it to make a simple polymorphic case class. This example doesn't compile and gives "could not find implicit value for parameter writer:A$A228.this.ValueWriter[T]". I can't really figure out what could be going wrong or where to start.
trait Keeper
case class StringKeeper(measure: String) extends Keeper
case class StringLengthKeeper(measure: Int) extends Keeper
trait ValueWriter[A] {
def write(value: String): A
}
object DefaultValueWriters {
implicit val stringWriter = new ValueWriter[StringKeeper] {
def write(value: String) = StringKeeper(value)
}
implicit val stringLengthWriter = new ValueWriter[StringLengthKeeper] {
def write(value: String) = StringLengthKeeper(value.length)
}
}
object Write {
def toWrite[A](value: String)(implicit writer: ValueWriter[A]) = {
writer.write(value)
}
}
case class WriterOfKeepers[T <: Keeper](value: String) {
def run: T = {
Write.toWrite[T](value)
}
}
import DefaultValueWriters._
val writerLengthKeeper = WriterOfKeepers[StringLengthKeeper]("TestString")
writerLengthKeeper.run
There is no implicit ValueWriter in scope when you call Write.toWrite.
You need to have the implicit parameter in the constructor
case class WriterOfKeepers[T <: Keeper : ValueWriter](value: String) {
def run: T = {
Write.toWrite[T](value)
}
}
or in the method
case class WriterOfKeepers[T <: Keeper](value: String) {
def run(implicit writer: ValueWriter[T]): T = {
Write.toWrite(value)
}
}
or find some other way compatible with your requirements (and I don't know those).
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.
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)
???
}
}
I am trying to write a generic method f[T](id:String) that is something like this:
case class A(x:String)
case class B(y:String)
case class C(z:String)
def f[T](id:String): T = { /* equivalent to T(id) */ }
val result1:A = f[A]("123") // returns A("123")
val result2:B = f{B]("345") // returns B("345")
val result3:C = f[C]("567") // returns C("567")
Unfortunately I cannot figure out how to work with the type T inside the method, besides using reflection. By "working with the type T" i mean for example being able to do something like the following, which I know doesn't work (for illustration purposes only):
T match {
case A => A(id)
case B => B(id)
}
or simply invoke T(ID) to create a new object of whatever type T is.
I can of course break up this into three methods:
def f1(id:String): A = { A(id) }
def f2(id:String): B = { B(id) }
def f3(id:String): C = { C(id) }
val result1:A = f1("123") // returns A("123")
val result2:B = f2("345") // returns B("345")
val result3:C = f3("567") // returns C("567")
but I'm hoping there is a way to keep it as one generic method to avoid some ugly boilerplate code duplication, and still be nearl as fast as the tree method version.
If you do not want to use reflection (ClassTag or TypeTag), you could use a Factory type class to achieve the desired functionality (unless it defeats the purpose of your generic function by generating a lot of duplicated simple code ;)).
case class A(s: String)
case class B(s: String)
case class C(s: String)
trait Factory[T] extends ((String) => T) {
def apply(arg: String): T
}
object Factory {
implicit object AFactory extends Factory[A] {
override def apply(arg: String): A = A(arg)
}
implicit object BFactory extends Factory[B] {
override def apply(arg: String): B = B(arg)
}
implicit object CFactory extends Factory[C] {
override def apply(arg: String): C = C(arg)
}
}
def create[T : Factory](arg: String): T = implicitly[Factory[T]].apply(arg)
create[A]("foo") | -> res0: A = A(foo)