I am trying to implement template method pattern with implicits. Class A is the top class with 2 extensions.
Class A that is defining the template pattern and has some method doSomething(). This method uses several implicits inside. This class is abstract.
Class B and Class C are extending Class A, providing implicits in scope, implementing other abstract methods and are no more abstract.
Example (using spray's pipeline):
A:
abstract class A[T <: Any : Manifest] {
....
abstract def method: PartialFunction[T,Unit] //not interesting
def doSomething() {
//method using implicit parser HttpResponse -> T
val responseFuture: Future[T] = pipeline(Get(url))
responseFuture.onSuccess(method)
}
}
B:
import CaseClassB._ //importing implicits that transfer HttpResponse -> CaseClassB
class B extends A[CaseClassB] {
def method: PartialFunction[CaseClassB,Unit] = {//not interesting}
}
This setting does not work (compilation of Class A fails because of "could not find implicit value for evidence parameter"). Is there a better way how to overcome this problem without a need to have something like "implicit abstract def" in Class A that would need to be overriden? The reason I don't like this is that Class B and Class C are providing implicits using imports.
Related
I am implementing an extension of ml.Transformer in Spark; but this question is Scala specific. Here is an example object (part of a Class/Object pair):
abstract class UDFTransformer(func: UserDefinedFunction,
inputFieldNames: Seq[String],
outputFieldName: String) extends Transformer with MLWritable with Serializable {
... definitions here ...
}
object UDFTransformer extends MLReadable[UDFTransformer] {
// Since there are no parameters associted with the UDF, there is nothing to save!
class Writer(instance: UDFTransformer) extends MLWriter {
override protected def saveImpl(path: String): Unit = {}
}
abstract protected class Reader extends MLReader[UDFTransformer]
override def read: MLReader[UDFTransformer] = new Reader
override def load(path: String): UDFTransformer = super.load(path)
}
The new Reader does not compile because the class is abstract and cannot be instantiated. But; any child class will have to define it; along with its necessary members. I cannot just make read abstract as well, this gives me a warning Only classes can have declared but undefined methods.
The fundamental problem is that each child class of my UDFTransformer is going to wrap a specific UDF. Therefore, the reader needs to be able to generate a specific UDF object; this can't be declared in the superclass. But this 'factory' belongs in the companion object, not in the abstract class itself.
How can I go about building a companion object for an abstract class that can leave the definition of read undefined?
The normal way to do it is by creating an abstract class or trait for the companion objects. Something like
abstract class UDFTransformerCompanion[T <: UDFTransformer] extends MLReadable[T] {
abstract def read: MLReader[T]
override def load(path: String): T = super.load(path)
}
class SomeTransformer extends UDFTransformer { ... }
object SomeTransformer extends UDFTransformerCompanion[SomeTransformer] {
override def read: MLReader[SomeTransformer] = ...
}
Not sure why you have the load = super.load override, and it doesn't look like you can have a companion object for the UDFTransformer itself, at least not one extending this abstract class.
See GenericTraversableTemplate for a standard library example.
I am new to scala. I don't understand scala traits properly. I have read it is similar to java interfaces but the methods need not be abstract. But how can I declare a scala trait and instantiate it in the following code. BTW, the following code is working fine.
trait fooable {
def foo: Unit = {
println("This is foo")
}
}
object Main {
def main(args: Array[String]): Unit = {
println("This is morking")
val foo = new fooable{}
foo.foo
}
}
Output -
This is morking
This is foo
Thanks in advance.
Scala traits are more general than both Java interfaces and abstract classes.
You can use a trait as an interface, you can use it to store some implementation, you can use it simply to define a common super-type:
trait Message
case class Text(text: String) extends Message
case class Data(data: ByteString) extends Message
Multiple traits can be 'mixed in' a class:
class MyClass extends TraitA with TraitB with TraitC
where any conflict with identically named methods is resolved by the simple rule: the last trait takes precedence. This code:
trait TraitA { def print() { println("A") } }
trait TraitB { def print() { println("B") } }
trait TraitC { def print() { println("C") } }
new MyClass.print()
will print "C".
Scala traits can't be instantiated. You are creating an anonymous class in you example. If you add an abstract method to your trait it will not compile.
Unrelated note:
It is a good practice to write braces "()" in methods with side effects. Your method foo has a side effect: it prints something. So you should write "foo()".
When you instantiate a trait you create an instance of an anonymous class that extends that trait it works the same way as creating anonymous classes of interfaces in java. If you had any unimplemented methods in the trait fooable the compiler would've forced you to implement them on spot when you created your anonymous class.
Indeed your code should work fine and output the same result you mentioned. However the important point to note here is TRAIT CAN NEVER EVER be instantiated. Its the same concept that Java interface can never ever be instantiated.
When scala compiler notice the code foo = new fooable{}, It internally creates an anonymous class which extends your fooable trait and thus it inherits foo() method due to inheritance. See following code snippet:
scala> val foo = new fooable{}
foo: fooable = $anon$1#277c0f21
Thus when you call foo.foo, At runtime it invokes a anonymous's class(i.e. $anon$1#277c0f21) inherited method foo().
The same understanding is true in case of Java as well, Following is perfectly legal java code:
Runnable r = new Runnable() {
public void run() {
System.out.println(" Cat");
}
};
r.run()
Happy learning !
An Scala Trait is abstract and can't be instantiated. In the code above its instantiated as
val foo = new fooable{}
and NOT as
val foo = new fooable()
The curly braces created some anonymous class which is not fooable but an empty one
What are Traits?
Traits are similar to interfaces in any other language. Scala allows traits to be instantiate during definition as well as during construction. For example if we have a trait and a abstract class
trait testTrait {
}
abstract class BaseClass {}
class Derive extends BaseClass with testTrait {
}
// ---------------------- OR----------------------
// Traits can be used during instantiation
class Derive extends BaseClass {
}
val classInst = new Derive with testTrait
Traits can also be chained using multiple with trait
In Scala I want to return a instance of a class for a method defined in a trait which uses generics, the code example I have is this:
File 1
package packOne
import packTwo.A
trait MyTrait[T <: MyTrait[T <: A]] {
def otherFunct(): String
def funct[T <: A](): T
}
File 2
package packTwo
import packOne.MyTrait
abstract class A(someParameter: String) {}
class B(someParameter: String) extends A(someParameter) {}
object B extends MyTrait[B] { // <--- the B inside MyTrait here is the class not the object, or at least that is what I want
def otherFunct(): String = "Hello"
def funct[B](): C = new B("hi") // <--- I think here is the key
}
basically what I want is an interface that have method to return a concrete implementation of class A, in an implementing object (which happen to be a companion object for a class extending A).
Why do I want that to be on an object?, is because I want to call that method without the need of an instance (like an static method in java), so that I can call B.funct() and have an instance of B class kind of like a factory method, for other classes extending A for example a call to X.funct will return an instance of class X.
I have tried to remove the generic type from the function definition except on the return type of the function and just leave it in the trait definition (like def funct(): T) but that does not work either.
I am quite new to Scala so if you could explain it for dummies and avoid complex scala unique concepts I would appreciate
How about simply:
trait A
class B(someParameter: String) extends A
trait MyTrait[T <: A] {
def otherFunct: String //Parentheses on parameterless methods with no side effects and no serious computation are generally unidiomatic in Scala
def funct: T //Note, no generic parameter on this method
}
object B extends MyTrait[B] {
def otherFunct = "Hello"
def funct = new B("hi")
}
And then:
B.funct //returns a new `B`
The apply method is often used in this factory style (e.g. Seq.apply() which is equivalent to Seq())
I have a super class:
class P(name:String)
And a helper trait:
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
Then I want to define an object which extends P:
object C extends P(prop("user.name")
It's not compiled, because it can't find the prop method. So I with the SysConfig:
object C extends P(prop("user.name") with SysConfig
Unfortunately, it still can't be compiled
Is there any way to make it work?
The arg is evaluated in a context outside the current definition, so no.
You have to put the computation in another object.
If you were thinking this, the answer also turns out to be no:
scala> class P(name: String)
defined class P
scala> trait Prop { def prop(k: String) = sys.props(k) }
defined trait Prop
scala> class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
<console>:9: error: module extending its companion class cannot use default constructor arguments
class C(p: String = C.prop("user.name")) extends P(p); object C extends C() with Prop
^
That's because default args are methods defined by the companion.
Similarly,
scala> class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
<console>:9: error: super constructor cannot be passed a self reference unless parameter is declared by-name
class C(p: String) extends P(p); object C extends C(C.prop("user.name")) with Prop
^
If I dont misunderstand this :), I think there are 2 things are impossible here.
trait composition or stackable trait is always make right trait wins. In this example, it tries to use left one override the right one.
when we use trait composition, trait structure would not change. The only flexible thing we can do is the sub-trait polymorphism. Cake pattern is using this way, but linearization is a problem. However, it is not related to this.
I think the correct way to do this, is to create a class/trait to do the override thing
class P(name:String)
trait SysConfig {
def prop(key:String) = System.getProperty(key)
}
class C extends P("123") with SysConfig {
override def prop(key: String) = "123"
}
trait Foo extends P with SysConfig {
override def prop(key: String) = "123"
}
new C
I'm trying to import a bunch of methods from one class to another without extending it. I've made it work but why one approach works and the other doesn't is beyond me.
Stripped down, here is what I'm trying to do
class A {def x() {println("x")}}
object A
class B {
import A._
def y() {x()}
}
And the compiler tells me "not found: value x"
But it works if I do either this
class C extends A
class B {
import C._
or if I do this
object C extends A
class B {
import C._
Can someone explain why this is the case?
The reason why your code example class C extends A is not working is that you import class members which can only exist in the class they are defined.
Whereas when you write object C extends A you will create a singleton (in Scala called object like the keyword) which represents an instance and allows you to import its members.
So, to make members of other classes visible you always have to extend them, either by an object or by another class/trait. It is not enough to declare a companion object of a class because it does not hold an instance of its companion class.
There also the possibility of using implicits.
You need to have a way to get from a instance of B to the desired instance of
A. In the example below I use a member value, but it should be possible to make
it a function as well.
The trait exposed exposes the this in B to the implicits declared in A.
The trait PathTo can be used to expose a path to the desired instance of A.
class A {
def a1(){ println("a1") };
def a2(){ println("a2") };
def a3(){ println("a3") };
}
object A{
def a1()(implicit a:A){a.a1};
def a2()(implicit a:A){a.a2};
def a3()(implicit a:A){a.a3};
//makes it possible to use a1() instead of a1()(this.a)
implicit def insertPathToA(implicit path:PathTo[A]):A=path.pathTo;
// Makes it possible to write this.a2() instead of this.a.a2();
implicit def convertPathToA(path:PathTo[A]):A=path.pathTo;
};
trait exposed[U]{
implicit def self:U=this.asInstanceOf[U];
}
trait PathTo[U]{
implicit def pathTo:U;
}
class B(val a:A) extends exposed[B] with PathTo[A] {
// imports the magic
import A._
override def pathTo:A=a;
def y() {
a1() ;
this.a2();
};
}