Consider the following code in scala https://scastie.scala-lang.org/xmJEm5YoTfujUnQbAnycDg
trait MyFactory[Record] {
def apply(
paramInt: Int
): MyBuilder[Record]
def apply(
paramInt: Int,
paramString: String
): MyBuilder[Record] = {
// DO something with string
// doesn't work with MyFactory[Record](paramInt) also
return MyFactory(paramInt)
}
}
object MyFactory {
}
class MyBuilder[Record] {
}
I am expecting that I can implement default apply for one of the overloading function and call the other, but compiler is complaining object MyFactory in object Playground does not take parameters which confuses me because the trait does have apply taking parameters, and I see default method work in the official doc https://docs.scala-lang.org/overviews/scala-book/traits-abstract-mixins.html for trait, so I am confuse why it can't find the correct overloading function
trait TailWagger {
def startTail(): Unit = println("tail is wagging")
def stopTail(): Unit = println("tail is stopped")
}
I assume the compiler will look at the trait to see the correct apply to use
What am I doing wrong?
Why not just do this?
return apply(paramInt)
The error is because you are trying to call apply on the companion object which doesn't have an apply method. The apply in the trait can only be called on an instance of the trait because it is a method of that trait.
Related
I have a generic class that looks like:
class GenericClass[T <: AnyRef] {
def getHash(obj: T): String = obj.toString
}
As you can see, type T needs to have implemented the toString function in order for getHash to work properly. My question: is that possible to apply type bound/constraints so that type T always have toString implemented?
One way that I can think of is to use type class and context bound:
class GenericClass[T : ClassWithToString] {...}
trait ClassWithToString[T] {
def toString(t: T): String
}
implicit object SomeTypeWithToString extends ClassWithToString[SomeType] {
override def toString(a: SomeType): String = a.toString()
}
However, this approach requires clients to define new implicit objects whenever they want to use GenericClass with a new type, which is not ideal in my case. Especially given toString is a very common function that's being implemented by many types. Wanted to get some advice from you on how to solve this issue elegantly!
i am trying to do something like this in scala so that the Category class receives its attributes by parameters but i get the following error:
object creation impossible, since method apply in trait ModelCompanion of type => asd.Category is not defined
object Category extends ModelCompanion[Category] {
^
one error found
Code here:
object asd {
trait ModelCompanion[M <: Model[M]] {
def apply: M
}
trait Model[M <: Model[M]] {
var id: Int = 0
}
object Category extends ModelCompanion[Category] {
def apply(name: String): Category = new Category(name)
}
class Category(var name: String) extends Model[Category] {
// Do something with name
}
}
I am new to scala so if you could give me some guidance on this I would be very grateful.
ModelCompanion defines an abstract method apply without any arguments (or argument lists). In Category you define an apply method that takes an argument of type String. That's not an implementation of the abstract method because it doesn't accept the same number and types of arguments. Therefore Category does not provide a suitable definition of ModelCompanion's abstract apply method and therefore can not be instantiated.
Depending on the behavior you want, you should either change the definition of ModelCompanion.apply to def apply(name: String): M or introduce another type argument and use that as the argument type.
Shortly:
def apply:M
//and
def apply(name:String):M
//are not the same methods
//if you try define it with override modifier
override def apply(name: String): Category = new Category(name)
//it will expose this fact to you with error:
//method apply overrides nothing.
//Note: the super classes of object Category
// contain the following, non final members named apply:
//def apply: ammonite.$sess.cmd8.asd.Category
//You need to define `ModelCompanion` with appriopriate `apply`
trait ModelCompanion[M <: Model[M]] {
def apply(name:String): M
}
// or override properly current (argumentless) one
object Category extends ModelCompanion[Category] {
override def apply: Category = new Category("Category" + Random.nextInt())
}
Why does this not compile?
The error given is class SomeElement needs to be abstract, since method eval in trait Element of type [T <: Typed]=> scala.util.Try[T] is not defined
I cannot understand why the method eval defined on SomeElement does not satisfy the type constraints.
As I understand it, eval should return something wrapped in a Try which subclasses Typed.
Try is covariant in its type parameter. The implementation of eval in SomeElement returns a NumberLike, and NumberLike subclasses Typed. So what's gone wrong?
import scala.util.Try
trait Element {
def eval[T <: Typed]: Try[T]
}
trait Typed
case class NumberLike(n: Long) extends Typed
case class SomeElement(n: Long) extends Element {
def eval = Try {
NumberLike(n)
}
}
object app extends Application {
println (SomeElement(5).eval)
}
Trying to add an explicit type parameter to eval in SomeElement doesn't help either:
case class SomeElement(n: Long) extends Element {
def eval[NumberLike] = Try {
NumberLike(n)
}
}
Changing the defintion of SomeElement to the above gives:
found : <empty>.NumberLike
required: NumberLike(in method eval)
NumberLike(n)
EDIT I would really like to know why this doesn't compile. Workarounds for the problem are helpful, but I really want to know what's going on here.
The type parameter T being defined on the function, not on the enclosing type Element, it can't be 'erased' by inheritance and must be kept on the overriding function (http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#class-members).
Moving the type parameter to Element definition make it work as following.
trait Element[T <: Typed] {
def eval: Try[T]
}
trait Typed
case class NumberLike(n: Long) extends Typed
case class SomeElement(n: Long) extends Element[NumberLike] {
def eval = Try {
NumberLike(n)
}
}
Or using a type member:
trait Element {
type T <: Typed
def eval: Try[T]
}
trait Typed
case class SomeElement(n: Long) extends Element {
type T = NumberLike
def eval = Try {
NumberLike(n)
}
}
Since someone has given a solution, I'm trying to explain why.
In java, something like this is illegal:
class A {
<T> T f() {return null;}
Object f() {return null;}
}
But in scala, it's legal:
class A {
def f[T](): T = ???
def f(): Any = ???
}
The main difference is that: scala treat 2 methods with same name and parameters list different if one of them has type parameter and another don't.(I think the signature of scala method include type parameters, correct me if I was wrong :) )
So in your case, you can't overwrite a method with type parameter by a normal method.(they have different signatures)
I'm not sure which one is better, personally I prefer the scala rule :)
I'm looking for a way to define a method that returns a type T where T = the type of the subclass.
I know I could possibly do this using abstract types, but dislike the overhead of having to redefine T for each subclass.
Some sample code:
object Helper {
def help[A <: MyClass](cls: A): Option[A] = { cls.foo() map { _.asInstanceOf[A] } }
}
class MyClass {
type T <: MyClass
def foo(): Option[T] = Some(this.asInstanceOf[T])
}
class ChildClass extends MyClass {
type T = ChildClass
}
Possibly a new language feature has made this easier? Or can I use this.type in some way? It's important to me that I be able to define a helper class that can call into foo in this way.
If you are always returning this, then you can indeed have as return type this.type. Or have you tried it already?
this.type is especially useful e.g. when you want to chain calls to the same object, or provide a static guarantee that you will be returning the same object (and not a copy). For instance, Buffers in Scala have the append operation :+, which returns a Buffer[A], and +=, which returns this.type. The former duplicates the mutable sequence; the latter guarantees that you update the original object.
To follow up on Jean-Phillippe's answer, who wrote his exactly when I'm writing mine, here's the code:
trait SomeTrait {
def foo: this.type = this
}
class UsesTrait extends SomeTrait
object Main {
def main(args: Array[String]) {
println((new UsesTrait).foo) // prints UsesTrait#<hash value>
}
}
I found the following idiom useful:
class MyClass[T] {
self: T =>
def foo(): Option[T] = Some(this)
}
class ChildClass extends MyClass[ChildClass]
new ChildClass().foo()
//--> Option[ChildClass] = Some(ChildClass#2487b1)
I'm trying to implement a Scala trait that handles the details of interfacing with a Java library that requires us to create
What I want to do is something like:
trait SomeTrait[A] extends JavaAPI {
def foo = {
callApi(classOf[A])
}
override def bar = {
foo
}
}
Note that bar is actually overriding a method from a base class, so I can't change it's signature.
I've tried several variations with Manifests, etc., but can't quite get this to work. Is there a way to get the runtime class of a parameterized type?
This flavour should do the trick:
trait SomeTrait[A] {
def foo(implicit ev: Manifest[A]) = {
callApi(ev.erasure)
}
}
update At some point, the manifest must be injected via a method parameter. A constructor would be a good choice, if traits could have them.
Actually, they can! The trait has the constructor of whatever it's mixed-in to, so if you specify an abstract manifest that deriving classes must define...
trait SomeTrait {
def ev: Manifest[_] //abstract
def foo = println(ev.erasure)
}
//this `ev` provides the implementation, note that it MUST be a val, or var
class Concrete[T](implicit val ev: Manifest[T]) extends SomeTrait
And all is good again.
You have to get the manifest in there somehow, and traits have no constructor parameters. Only you can say what tradeoff you want to make. Here's another one.
trait SomeTrait[A] {
implicit def manifesto: Manifest[A]
def foo = println(manifest[A].erasure)
}
object SomeTrait {
def apply[A: Manifest] : SomeTrait[A] = new SomeTrait[A] { def manifesto = manifest[A] }
}
Due to type erasure, the compiler has no way to figure out what the type should be within the trait. Thus what you want can't be done. However, you could make it a class. That way the compiler can pass an evidence parameter when an instance is created.
class SomeTrait[A](implicit ev: Manifest[A]) extends JavaApi {
def foo = {
callApi(ev.erasure)
}
override def bar = {
foo
}
}
It might be a little inconvenient to do so in your code, but you can do this
trait SomeTrait[A] extends JavaAPI {
def objType: Class[A]
def foo = {
callApi(objType)
}
override def bar = {
foo
}
}
object SomeImplementation with SomeTrait[SomeObject] {
val objType: Class[SomeObject] = classOf[SomeObject]
}
I know it is a little wordy, but that's the way I solved this problem. I hope to find a better solution in the future, but this is what I'm using now. Let me know if that helps you.