I have a trait with a method that's being used by 3 different classes, in one of the classes, I would like to override the method to accept an additional param, is this possible? how would one go about this in scala?
PS: I am new to Scala
Desired example:
trait Iterator {
def hasNext(a : String):
}
class Iterator extends Iterator {
override def hasNext(a : String, b: String) = {
...
}
}
Related
Given the following base class and one of its methods:
abstract class ServiceIf(val name: String) {
def run(args: Any*): Any = {}
An attempted subclass implementation is:
class RexecIf extends ServiceIf("Rexec") {
override def run(execParams: ExecParams, nLoops: Int) = {
However the "varargs" does not work:
Is this expected behavior - that is that varargs should/may not be used for base class methods?
Update I did not mention originally: a goal is to use the method within reflection for configuration file driven workflows. So using types-based approaches (as in the first answer) may be practical in some use cases but not in mine.
The overridden method has to be able to be called with any arguments the original accepted, not just the two you've provided. That is, a call recexif.run(1, 2, 3) has to be valid.
Also consider:
abstract class Base {
def run(arg: Any) = {}
}
class Derived extends Base {
override def run(arg: Int) = {}
}
This is similarly wrong, because the "override" does not implement the contract of the base method.
If you want the different implementations to accept different parameters for run, consider introducing an associated type or a type parameter. For example:
abstract class ServiceIf[RunArgs](val name: String) {
def run(arg: RunArgs): Any = {}
}
class RexecIf extends ServiceIf[(ExecParams, Int)]("Rexec") {
override def run(arg: (ExecParams, Int)) = {
// ...
}
}
You cannot override a general method with a more specific method. The override method must accept all the arguments that are accepted by the base method. So the code in the question can never be made to work.
You can, of course, have the override method fail unless it gets the values that it needs. Here is an example of how this works in this case:
abstract class ServiceIf(val name: String) {
def run(args: Any*): Any = {}
}
class RexecIf extends ServiceIf("Rexec") {
override def run(args: Any*) = {
val Seq(execParams: ExecParams, nLoops: Int) = args
}
}
This will fail with MatchError if the args do not match the pattern in the override method.
While this is not an "answer" it is maybe the closest workaround - to use a Seq explicitly instead of the varargs ?
abstract class ServiceIf(val name: String) {
def run(args: Seq[Any]): Any = {}
class RexecIf extends ServiceIf("Rexec") {
override def run(args: Seq[Any]) = {
val Seq(execParams: ExecParams, nLoops: Int) = args
I will go ahead with the above approach unless a more definitive answer appears - and would still receive its proper due.
Is there a way to return different return types from a single method in scala?
For example, if I have a load() method, I would like to return different data types depending on the object that called this method.
def load(path: String):<return type>
{
// if this instance is of type "type1", do some processing on this object,
// and return object of type "type1"
// else if this instance is of type "type2", do some processing on this object,
// and return object of type return "type2"
}
If I understand correctly what you want, F-bounded polymorphism may work for you:
trait Base[T <: Base[T]] {
def load(path: String): T
}
class Type1 extends Base[Type1] {
override def load(path: String): Type1 = new Type1 // provisional implementation
}
class Type2 extends Base[Type2] {
override def load(path: String): Type2 = new Type2
}
Then load will return the type of the current object. Note the result types in those expressions:
new Type1().load(path)
scala> res2: Type1 = Type1#744f0e0b
new Type2().load(path)
scala> res3: Type2 = Type2#77988c45
You can use scala's Either:
def load(path : String) : Either[Type1, Type2] = {
this match {
case t1 : Type1 => Left(someProcessing(t1))
case t2 : Type2 => Right(someOtherProcessing(t2))
}
}
As others stated, you can use
You can use scala's Either
just keep in mind that every method that invokes your method, will need to check which of the types it is returning (using .map or pattern matching). Either is usually used like Either[ErrorType, NormalType] btw, but of course you can use it however you want
scala cats library has other alternative: http://eed3si9n.com/herding-cats/Xor.html
and of course, scalaz also provides an alternative: http://appliedscala.com/blog/2016/scalaz-disjunctions/
As a last resort, don't you can define your own "Either"
If your requirement is as simple as returning some instance of the type of context instance... ie this then you can just do this,
class A() {
def omg(s: String): this.type = new A()
}
And if inheritence is involved,
trait A {
type omgType
def omg(s: String): omgType
}
class B() extends A {
override type omgType = this.type
override def omg(s: String): omgType = new B()
}
class C() extends A {
override type omgType = this.type
override def omg(s: String): omgType = new C()
}
But if you want more generality then you may want to read the following and apply it there,
The easiest way will be to take inspiration from the magnet pattern which was heavily used in Spray.
We can leverage the inspiration to build our custom solution, remember it is neither pure magnet pattern nor is path dependent type approach. Its a hacky cocktail of both.
So... lets say you want your def process to be able to support input parameters of type Int and String and finally return the respective result.
You will need to define implicit magnets for these types,
trait ProcessMagnet {
type Input
type Result
def input: Input
def process: Result
}
object ProcessMagnetProvider {
implicit def stringToStringProcessMagnet(string: String): ProcessMagnet = new ProcessMagnet {
override type Input = String
override type Result = String
override def input: Input = string
// define this for your doing...
override def process: Result = input + "_omg"
}
//... add for all your inputs
implicit def intToIntProcessMagnet(int: Int): ProcessMagnet = new ProcessMagnet {
override type Input = Int
override type Result = Int
override def input: Input = int
// define this for your doing...
override def process: Result = input + 1
}
}
def process[T](t: T)(implicit pmConverter: T => ProcessMagnet): ProcessMagnet = pmConverter(t)
// now just import our implicit magnets...
import ProcessMagnetProvider._
val intResult: Int = process(5).process.asInstanceOf[Int]
val stringResult: String = process("omg").process.asInstanceOf[String]
what about factory method and just defining a trait loadable eg:
trait Loadable {
def load(path: String): Loadable
}
class Type1 extends Loadable {
def load(path: String): Type1 = this
}
class Type2 extends Loadable {
def load(path: String): Type2 = this
}
object Main {
def test(): Loadable = {
new Type1().load("path")
}
def main(args: Array[String]): Unit = {
println(test().getClass)
}
}
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
I have 3 classes:
class AClass
class Base { val a = "a" }
class BaseOne extends Base { val b = "b" }
class BaseTwo extends Base { val c = "c" }
I want to extend a trait which contains a generic method, I'm not allowed to change the trait
trait Converter {
def toAClass[T <: Base](e: T): AClass
def fromAClass[T <: Base](s: AClass): T
}
I want to extend it in several different objects
object ConverterBaseOne extends Converter {
// ERROR
override def toAClass(e: BaseOne) : AClass = { printf(e.b) } // b is known
override def fromAlcass(a: AClass) : BaseTwo = {....}
}
I know there is a way to do it with class parameter: trait Converter[T <: Base]
and also saw this post https://stackoverflow.com/a/4627144/980275
I'm asking if there is a solution without changing the trait ???
Thank you
You are changing the signature of the method, so it is not a legal override, it would break polymorphism. You must either parametrize the Converter trait or use another method name.
You can, however, receive a Base object and cast it, but it is not recommended practice since it may result in an exception at runtime:
object ConverterBaseOne extends Converter {
override def toAClass[T <: Base](e: T): AClass = {
printf(e.asInstanceOf[BaseOne].b)
// ...
}
}
Scala allows to define update such as
def update(index: Int, value: String) { ... }
and then call it like
foo(i) = "Text"
Is there a trait that encapsulates that? Something like
trait Update1[+A,+B] {
def update(i: A, v: B)
}
(Of course I could define such a trait myself, but it would only work for instances that I mix with it, not with other ones constructed beyond my influence.)
The reason why you can't define such a trait is that you are using covariant type parameters in a place where they are not allowed. The following traits compile fine in Scala 2.10:
trait Update1[-A, -B] {
def update(i: A, v: B) : Unit
}
trait MyFunction1[-A, +B] {
def apply(a:A): B
}
trait Mutable[-A, B] extends Update1[A,B] with MyFunction1[A,B]
Notice that in order to have a mutable trait you have to fix the B parameter, so it allows neither covariance nor contravariance. If you take a look at the mutable collections in the Scala API you can see that in fact this is how they are declared.
In addition, nothing prevents you to mix a trait in an object instead of in a class to make the compiler happy, if you know that class already implements the methods defined in the trait. For example, you can have the following:
class SingleStringCollection(v: String) extends MyFunction1[Int, String] {
private var someString: String = v
def apply(a: Int): String = someString
def update(i: Int, v: String): Unit = {
someString = v
}
override def toString = someString
}
val test1: Update1[Int, String] = new SingleStringCollection("hi") // this would fail
val test2: Update1[Int, String] = new SingleStringCollection("hi") with Update1[Int, String] // this would work
Or you could also use structural typing if you just want to require that your val or parameter implements a list of known methods:
type UpdatableStructuralType = {
def update(i: Int, v: String) : Unit
}
val test3: UpdatableStructuralType = new SingleStringCollection("hi") // this would work
test3(0) = "great" // And of course this would also work
So you have several alternatives if you want to accept parameters conforming to some trait or requiring some methods to be implemented.