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();
};
}
Related
I just found the type class concept of Scala and like it actually very much. The problem I have it that all examples I found put the type classes (objects) under one object (Like here: http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html)
Maybe this is wrong but I am a friend of having one file per class. So what I like to do is to put the type classes into several files which would mean that each implementation needs to be put into a seperate object. This now leads to the "problem" that I need to import every single implementation manually. To clarify better here a small example:
package sth
import sth.like.Like
import sth.like.StringLike._
import sth.like.IntLike._
object Application extends App {
def t[T](arg: T)(implicit l: Like[T]) = {
l.print(arg)
}
t(1)
t("Blub")
}
-
package sth.like
trait Like[T] {
def print(arg: T)
}
-
package sth.like
object IntLike {
implicit object LikeIntLike extends Like[Int] {
def print(arg: Int): Unit = println(s"INT $arg")
}
}
-
package sth.like
object StringLike {
implicit object LikeStringLike extends Like[String] {
override def print(arg: String): Unit = println(s"STRING: $arg")
}
}
This works so far. I know, the wildcard import in Application is not necessary but that is not the point. As you can see I need to import both StringLike and IntLike in Application because otherwise these are not available for the Application object.
So is it possible to do this in a generic way or is it completely bad practise to do it this way?
You could put your implicits inside traits, not objects
trait IntLike {
implicit object LikeIntLike extends Like[Int] {
def print(arg: Int): Unit = println(s"INT $arg")
}
}
And then have object with the same name, extending this trait, which would give you what you had earlier, you can import each implicit individually.
object IntLike extends IntLike
You can do the same for all other instances of your typeclass:
trait StringLike {
implicit object LikeStringLike extends Like[String] {
override def print(arg: String): Unit = println(s"STRING: $arg")
}
}
object StringLike extends StringLike
And in another file, you can combine all traits together like this:
object Implicits extends StringLike with IntLike
and import just the Implicits object if you want all your implicits in scope.
package sth
import sth.like.Like
import sth.like.Implicits._
object Application extends App {
def t[T](arg: T)(implicit l: Like[T]) = {
l.print(arg)
}
t(1)
t("Blub")
}
Optionally, you can mixin traits you need
object Application extends App with StringLike with IntLike { ... }
or even do
trait Implicits extends StringLike with IntLike
object Implicits extends Implicits
object Application extends App with Implicits { ... }
thank you very much for your answer. But I also would need to add new type classes manually to the Implicits, wouldn't I?
Couldn't I use then package objects for simplicity reasons like here:
http://naildrivin5.com/scalatour/wiki_pages/PackageObjects/
?
I mean this part:
package opower {
package object controller {
type Secured = org.springframework.security.access.annotation.Secured
type Controller = org.springframework.stereotype.Controller
...
}
}
Since it seems that there is no dynamic way I could just put all type classes into the controller object and could this then import.
Or do I missunderstand the package object?
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())
Say I have the following two typeclasses:
object Foo {
sealed trait FooClass[A]
implicit object FooString extends FooClass[String]
implicit object FooInt extends FooClass[Int]
}
object Bar {
trait BarClass[A] //leave this one unsealed as we're attempting to prove that Foo is a subset of Bar, not the other way around.
implicit object BarString extends BarClass[String]
implicit object BarInt extends BarClass[Int]
implicit object BarDouble extends BarClass[Double]
}
is it possible to provide a hint to the compiler that Foo is a subset of Bar somehow, such that the following would compile, without a change to the type signatures of either method?
class Outer(callee : Inner) {
import Foo._
def call[A : FooClass](a) : Unit = callee.call(a);
}
class Inner
import Bar._
def call[B : BarClass](b) : Unit = ();
}
val test = new Outer(new Inner)
test.call(123)
test.call("Hello World")
My main objective is to allow the Outer class to be entirely unaware of the existence of the BarClass typeclass - using the Inner class to abstract over it entirely. Is this possible? For those who are interested, there's some context over in this git repository - the commit descriptions have some more detailed exposition of the problem I'm trying to solve).
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 have a class such as this:
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
and I wish to be able to create a new instance of the above class in a typed trait. The following def make in MetaClass creates an instance of T but it lacks the internal objects associated with NormalClass.
trait MetaClass[T <: NormalClass[T]] {
def make:T = this.getClass.getSuperclass.newInstance.asInstanceOf[T]
}
I have two questions, what is the reason for the missing objects and what is the best way, using reflection, to initiate a new class with internal objects from its type
EDIT: More Detail
The problem I am facing is if I then create an instance using make e.g. var f = make and I try to access and object method e.g. f.One.getSomething I get the error value One is not a member of type parameter T.
So I think your problem in particular is the reflection:
this.getClass.getSuperclass.newInstance.asInstanceOf[T]
Here, this is your instance of MetaClass, and there's no particular reason to believe that the superclass of this is the class you want to instantiate. For example:
class Foo extends NormalClass[Foo]
object Foo extends MetaClass[Foo]
In this case, the superclass of the object Foo is not a NormalClass at all, it's java.lang.Object. As a result, it won't have members like One or Two, and you'll get a ClassCastException if you try to cast it to T.
If you want the make method to instantiate an object of type T, then you need to get the runtime class of T, and then use that to create the new instance. You can accomplish this by implicitly acquiring a ClassTag:
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
trait MetaClass[T <: NormalClass[T]] {
def make(implicit classTag: scala.reflect.ClassTag[T]): T =
classTag.runtimeClass.newInstance.asInstanceOf[T]
}
// declare a class and an object for creating instances of that class
class Foo extends NormalClass[Foo]
object Foo extends MetaClass[Foo]
// create a new instance of Foo and access its fields
val foo = Foo.make
foo.One
foo.Two
I'm not sure what the issue is. This works for me:
scala> :paste
// Entering paste mode (ctrl-D to finish)
class NormalClass[T <: NormalClass[T]] {
object One
object Two
}
trait MetaClass[T <: NormalClass[T]] {
def make:T = this.getClass.getSuperclass.newInstance.asInstanceOf[T]
}
class X extends NormalClass[X]
// Exiting paste mode, now interpreting.
defined class NormalClass
defined trait MetaClass
defined class X
scala> new X with MetaClass[X]
res0: X with MetaClass[X] = $anon$1#404fe94c
scala> res0.One
res1: res0.One.type = NormalClass$One$#53d9f80
scala> res0.Two
res2: res0.Two.type = NormalClass$Two$#4d0948bd
If that doesn't answer your question, please clarify the issue you're having.