I'm new to Scala and can't find a way to achieve what I want.
I want to have abstract method in parent class like this
def copy():M
and then in each child class this method should have different number of arguments like
def copy(id: Int, title: String):M
Now when I try
override def copy(id: Int, title: String):M
I've got compilation error
method copy overrides nothing
If your parameters would be of the same type, you could write method signature like this
def copy(args: SomeType*):M
If not, you can use abstract type
trait T {
type CopyParam
def copy(c: CopyParam): T
}
case class SomeCopyParam(i: Int, s: String)
class A extends T {
type CopyParam = SomeCopyParam
def copy(c: SomeCopyParam): A = {
println(c.i + c.s)
this // some changed copy should be here
}
}
And use it like this:
val original = new A()
val copy = original.copy(SomeCopyParam(1, "a"))
Related
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())
}
I have some code like the following:
class Test(var f1 : String) {
def this(a : Int) {
this(makeStr(a))
}
private def makeStr(a : Int): Unit = {
"ABC" + a
}
}
The error I get is: not found: value makeStr.
It seems like the scala compiler cannot see the makeStr method in the constructor. It seems to be quite different from Java where it is doable. Does anyone know what is the right way to initialize the instance fields which requires some methods to compute the values?
You can't call instance methods before the primary constructor has run. You can declare makeStr as a method in the companion object so you can run it before the primary constructor. Also not that it should return String, not Unit as in your code.
class Test(var f1 : String) {
def this(a : Int) {
this(Test.makeStr(a))
}
override def toString = s"Test($f1)"
}
object Test{
private def makeStr(a : Int): String = {
"ABC" + a
}
}
new Test(1) //res0: Test = Test(ABC1)
It's a bit more idiomatic to define factory methods in the companion object instead of using multiple constructors though, as the other answers mention.
If I understand correctly, you are trying to create a class with multiple constructors. In scala, the best practice is different from Java.
You should first create a class and then its companion object in order to implement different constructors.
//your class
class Test(val f1: String)
//its companion object
object Test {
def apply(f1: String): Test = new Test(f1)
def apply(f1: Int): Test = new Test("ABC" + f1)
}
You can simply test the code above by the following code:
object Main {
def main(args: Array[String]): Unit = {
val testInt: Test = Test(1)
val testString: Test = Test("1")
println(testInt.f1)
println(testString.f1)
}
}
I feel in this case that the best solution would be to use factory methods instead of auxi constructor.
So you can define your constructor private and provide factory apply methods in companion object:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class Test private(var f1 : String)
object Test {
def apply(i: String) = new Test(i)
def apply(s:Int) = new Test(makeStr(s))
def makeStr(s: Int) = {
"ABC" + s } }
// Exiting paste mode, now interpreting.
defined class Test
defined object Test
For more infor refer
I'm trying to use mixin composition using functions, but I have an error in the apply method of obj object:
Overriding method apply in trait t of type (s: String)String; method apply needs abstract override modifiers.
How to solve this error and which is the correct implementacion?
trait t extends Function1[String,String] {
abstract override def apply(s: String): String = {
super.apply(s)
println("Advice" + s)
s
}
}
object MixinComp {
def main(args: Array[String]) {
val obj = new Function1[String, String] with t {
override def apply(s: String) = s
}
println(obj.apply("Hi"))
}
}
Your immediate problem (the reason it complains about the error) is that you can't have an abstract call in your linearization flow (your t.apply calls super.apply, which is abstract).
Also, the apply method you define in the top level anonymous class overrides everything, and does not call super, making the t being mixed in completely irrelevant.
Something like this would solve both problems:
trait t extends Function1[String,String] {
abstract override def apply(s: String): String = {
println("Advice" + s)
super.apply(s) // I rearranged this a little, because it kinda makes more sense this wat
}
}
// Note, this extends `Function1`, not `t`, it, just a "vanilla" Function1
class foo extends Function1[String, String] {
def apply(s: String): String = s
}
// Now I am mixing in the t. Note, that the apply definition
// from foo is now at the bottom of the hierarchy, so that
// t.apply overrides it and calls it with super
val obj = new foo with t
obj("foo")
You won't need to use the abstract modifier in your t trait definition, if you don't call the super.apply. And in this particular case I dont see any need for calling super.apply as Function1's apply is abstract. You probably need custom apply implementations. The following code should work.
trait t extends Function1[String, String] {
override def apply(s: String): String = {
// super.apply(s)
println("Advice" + s)
s
}
}
Case1: use the overridden apply method in t trait:
val obj = new Function1[String, String] with t {}
obj.apply("hello") // prints: Advicehello
Case 2: override the apply method in t trait in an anonymous class:
val obj = new Function1[String, String] with t {
override def apply(s: String): String = s
}
obj.apply("hello") // prints hello
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
}
}
Suppose I have a trait SomeTrait with an unimplemented method func. This method is going to return something that extends SomeTrait. In other words, I've got something like the following:
trait SomeTrait
{
def func(x: Int): SomeTrait
}
Now, I implement a class ExtensionClass that extends SomeTrait and it turns out that I in fact want the implementation of func in this class to return an object of type ExtensionClass:
class ExtensionClass(val param: String) extends SomeTrait
{
override def func(x: Int): SomeTrait = return new ExtensionClass("test")
// ExtensionClass also defines another method not specified in SomeTrait
def anotherMethod: String = return param ++ "!"
}
So far, everything above works nicely. The problem arises if I want to call anotherMethod on the object returned by func like so:
val extension = new ExtensionClass("hello")
extension.func(5).anotherMethod
The type system only recognises that the object given by extension.func(5) is of type SomeTrait and so anotherMethod is not visible. This brings us to my question:
Question:
Is it possible to make the above work without having to explicitly cast/pattern match on the result of func? For instance, can I update the type signature of func in SomeTrait so that some sort of type inference can happen? Any help will be appreciated.
You can add a generic parameter:
trait SomeTrait[T <: SomeTrait[T]] {
def func(x: Int): T
}
class ExtensionClass(val param: String) extends SomeTrait[ExtensionClass] {
def func(x: Int) = new ExtensionClass("test")
def anotherMethod: String = param ++ "!"
}
alternatively you could add an abstract type member:
trait SomeTrait {
type T <: SomeTrait
def func(x: Int): T
}
class ExtensionClass(val s: String) extends SomeTrait {
type T = ExtensionClass
def func(x: Int) = new ExtensionClass("test")
def anotherMethod: String = s ++ "!"
}