Generic type having the special constructor and calling it - scala

Let's say I have a few classes class and all they extend Response(response), that is to say, have the same constructor:
import scalaj.http.Http
class MyClass1(response: Http.Request) extends Response(response) {
//....
}
class MyClass2(response: Http.Request) extends Response(response) {
//....
}
How do I create a generic method which accepts only a type of the classes above and call its constructor:
def myGeneric[A <: ???](r: Http.Request) = {
new A(r) // doesn't compile
}
I'd like to call it like this:
myGeneric[MyClass1](r) // r is Http.Request
I can do this:
def myGeneric[A <: ???](r: Http.Request)(f: r => A) = {
f(r) // f - is the constructor
}
myGeneric[MyClass1](r) { x =>
new MyClass1(x)
}
But is there more elegant way to achieve the same?

Maybe you could make myGeneric take a factory as the implicit parameter. For example:
def myGeneric[A](r: Request)(implicit f: Request => A) {
... val a = f(r) ...
If I remember right, bare implicit functions like that can get confusing, so maybe ...
trait MyFactory[T] {
def make(r: Request): T
}
...
def myGeneric[A](r: Request)(implicit f: MyFactory[A]) ...
// which is same as...
def myGeneric[A : MyFactory](r: Request) ...

Related

Scala. Is there a way to choose super method implementation with self-types?

When I extend traits I can choose which method implementation to use. Like here:
object Main {
def main(args: Array[String]): Unit = {
val c = new C
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C extends A with B {
val b = super[A].foo
val a = super[B].foo
}
}
But if I want to do the same with self-types it's seems like it's not possible:
object Main {
def main(args: Array[String]): Unit = {
val c = new C with A with B
println(c.a)
println(c.b)
}
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
class C {
self: A with B =>
val b = super[A].foo
val a = super[B].foo
}
}
This doesn't compile. Am I right and it's not possible? If I'm right, why is that and is there a workaround for it?
UPDATE:
Why do I needed in a first place? I was playing around with dependency injection using self-types instead of constructor injection. So I had a base trait Converter and child traits FooConverter and BarConverter. And I wanted to write it like that(which doesn't work of course):
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: Converter[Foo] with Converter[Bar] =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
I thought it's because of generics, but it turned that it's not. So I was just wondering if it's possible to somehow invoke super method of chosen trait with self-types. Because with simple inheritance it's possible. As for my original problem I can write it like this and it will work:
object Main {
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
trait FooConverter extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
trait BarConverter extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
class Service {
this: FooConverter with BarConverter =>
def fooBar(f: Foo, b:Bar) = {
convert(f)
convert(b)
}
}
}
Probably tighter abstraction, but I'm not sure if it's bad for this kind of situation and if I need such broad abstraction like Converter[A] at all.
Calling super methods from already constructed type is impossible (you can do it only from the inside). In your example, you're trying to call foo on the instance self, which is constructed in runtime, so foo is virtual and could be overridden - compiler doesn't know which actual implementation is going to be called (formal vs real type problem). So technically - it's impossible to do what you want (call virtual method as a static one).
The naive hack is :
trait CC extends A with B {
val b = super[A].foo
val a = super[B].foo
}
class C {
self: CC =>
}
It basically provides encapsulation you want - you might wanna redefine a and b in class C as they're not going to be available (in type C itself) till you mix C with CC.
Note that in every example you provide (including my naive solution) - resulting val c has access to foo anyway and which exact foo is going to be called depends on how do you mix A and B (A with B or B with A). So, the only encapsulation you get is that type C itself isn't going to have foo method. This means that self-type gives you kind of a way to temporary close (make private) a method in "subclass" without violating LSP - but it's not the only way (see below).
Besides all of that, cake-injection that you're trying to implement is considered impractical by some authors. You might want to have a look at Thin Cake Pattern - as a remark, I successfully used something like this in real project (in combination with constructor injection).
I would implement your converter services this way:
class Foo
class Bar
trait Converter[A] {
def convert(a: A): String
}
object FooConverter1 extends Converter[Foo] {
override def convert(a: Foo): String = ???
}
object BarConverter1 extends Converter[Bar] {
override def convert(a: Bar): String = ???
}
trait FooBarConvertService {
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait Converters {
def fooConverter: Converter[Foo] = FooConverter1
def barConverter: Converter[Bar] = BarConverter1
}
object App extends FooBarConvertService with Converters with ...
This allows you to change/mock converter implementation when putting it all together.
I'd also notice that Converter[Bar] is nothing else but Function1[Bar, String] or just Bar => String, so actually you don't need separate interface for that:
sealed trait FooBar //introduced it just to make types stronger, you can omit it if you prefer
class Foo extends FooBar
class Bar extends FooBar
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
def fooConverter: Converter[Foo]
def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
def barConverter: Bar => String = ???
}
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can also use def fooConverter(f: Foo): String = ??? instead def fooConverter: Foo => String = ???.
Talking about encapsulation - it's more weak here as you can access transitive dependencies, so if you really need it - use private[package] modifier.
Converters module:
package converters
trait FooBarConvertService {
type Converter[T <: FooBar] = T => String
private[converters] def fooConverter: Converter[Foo]
private[converters] def barConverter: Converter[Bar]
def fooBar(f: Foo, b: Bar) = {
fooConverter(f)
barConverter(b)
}
}
trait FooConverterProvider {
private[converters] def fooConverter: Foo => String = ???
}
trait BarConverterProvider {
private[converters] def barConverter: Bar => String = ???
}
Core module:
package client
import converters._
object App
extends FooBarConvertService
with FooConverterProvider
with BarConverterProvider
You can use objects object converters {...}; object client {...} instead of packages if you prefer.
This encapsulation is even stronger than self-type based one, as you can't access fooConverter/barConverter from the App object (in your example foo is still accessable from val c = new C with A with B):
client.App.fooBar(new Foo, new Bar) //OK
client.App.fooConverter
<console>:13: error: method fooConverter in trait FooConverterProvider cannot be accessed in object client.App
client.App.fooConverter
^
Keep in mind that self types are meant to allow you to require that any client code that uses the trait you are mixing in must also mix in another trait. In other words it is a way of declaring dependencies. But it is not classical inheritance. So when you say class C { self: A with B => } A and B actually are not there at the time. You have just defined that the client code has to mix in A and B in order to then mix in C.
But for your specific use case, it seems like you can accomplish the same goal with something like this code. In other words first create a third trait and then extend it into a specific class.
object DoubleSelfType extends App {
val c = new DoubleFoo
println(c.a)
println(c.b)
trait Parent {
def foo: String
}
trait A extends Parent {
override def foo = "from A"
}
trait B extends Parent {
override def foo = "from B"
}
trait C {
self: A with B =>
val a = ""
val b = ""
}
class DoubleFoo extends C with A with B {
override val b = super[A].foo
override val a = super[B].foo
}
}

More aesthetic way to instantiate an anonymous implementation of a trait

Say I have a function that expects an instance of a trait:
trait MyTrait[T] {
def f1: T
def f2(t: T): Unit
}
def foo[T](t: MyTrait[T]) { ... }
Now, anywhere I call this function I need to use the following syntax:
val x = foo[String](new MyTrait[String] {
def f1 = "Hello"
def f2(str: String) = { ... }
}
I am wondering if there is another way I can achieve this to make my usages simpler and more aesthetic? Ideally I would like to have the following usage:
val x = foo() {
def f1 = "Hello"
def f2(str: String) = { ... }
}
If you use this trait anonymous everywhere like you described, throw it away!
Instead make the function look like
def foo[T](f1: T, f2: T => Unit)
so you can call it like
foo("Hello", (myString:String) => { } )
An alternative to Nabil A.'s answer, if you want to keep the trait, is to subclass it using a case class that takes f1 and (a function describing) f2 as parameters:
case class MyClass[T](f1: T, _f2: T => Unit) extends MyTrait[T] {
def f2(t: T) = _f2(t)
}
You can then instantiate it as:
foo(MyClass[String]("hello", str => {...}))

Class type required but T found

I can't create an actor for some reason (here is a simple version of my class hierarchy):
abstract class Class1[T <: Class2[_]: ClassTag] extends Actor {
//....
val res = List(1, 2, 3) map { x => context actorOf Props(new T(x)) } // error
}
abstract class Class2[U <: Class3 : ClassTag](a: Int) extends Actor { ... }
abstract class Class3(b: Int) extends Actor
But there is an error saying class type required but T found.
You can't call new T(x) with type parameter T. There could be no such constructor for T:
class WithoutSuchConstructor extends Class2[Class3](1)
You should specify method to create T explicitly:
abstract class Class1[T <: Class2[_]: ClassTag] extends Actor {
//....
def createT(i: Int): T
val res = List(1, 2, 3) map { x => context actorOf Props(createT(x)) }
}
Alternatively:
abstract class Class1[T <: Class2[_]: ClassTag](createT: Int => T) extends Actor {
//....
val res = List(1, 2, 3) map { x => context actorOf Props(createT(x)) }
}
One approach I have used involves creating an 'instantiator' trait which can be used to create instances of types for which an implicit instantiator exists:
trait Instantiator[+A] {
def apply(): A
}
object Instantiator {
def apply[A](create: => A): Instantiator[A] = new Instantiator[A] {
def apply(): A = create
}
}
class Foo() { ... }
object Foo {
implicit val instantiator: Instantiator[Foo] = Instantiator { new Foo() }
}
// def someMethod[A]()(implicit instantiator: Instantiator[A]): A = {
def someMethod[A : Instantiator](): A = {
val a = implicitly[Instantiator[A]].apply()
...
}
someMethod[Foo]()
I think this is because of JVM restriction also known as "type erasure".
http://docs.oracle.com/javase/tutorial/java/generics/erasure.html
also see "Cannot Create Instances of Type Parameters" at
http://docs.oracle.com/javase/tutorial/java/generics/restrictions.html
By the way C# allows you to write:
new T()
when you define a restriction
where T: new()
but unfortunately constructor must be parameterless

How to specify the return type of a function to be a (arbitrary) monad?

In short, I want to declare a trait like this:
trait Test {
def test(amount: Int): A[Int] // where A must be a Monad
}
so that I can use it without knowing what monad that A is, like:
class Usecase {
def someFun(t: Test) = for { i <- t.test(3) } yield i+1
}
more details...
essentially, I want to do something like this:
class MonadResultA extends SomeUnknownType {
// the base function
def test(s: String): Option[Int] = Some(3)
}
class MonadResultB(a: MonadResultA) extends SomeUnknownType {
// added a layer of Writer on top of base function
def test(s: String): WriterT[Option, String, Int] = WriterT.put(a.test(s))("the log")
}
class Process {
def work(x: SomeUnknownType) {
for {
i <- x.test("key")
} yield i+1
}
}
I wanted to be able to pass any instances of MonadResultA or MonadResultB without making any changes to the function work.
The missing piece is that SomeUnknowType, which I guess should have a test like below to make the work function compiles.
trait SomeUnknowType {
def test(s: String): T[Int] // where T must be some Monad
}
As I've said, I'm still learning this monad thing... if you find my code is not the right way to do it, you're more than welcomed to point it out~
thanks a lot~~
Assuming you have a type class called Monad you can just write
def test[A:Monad](amount: Int): A[Int]
The compiler will require that there is an implicit of type Monad[A] in scope when test is called.
EDIT:
I'm still not sure what you're looking for, but you could package up a monad value with its corresponding type class in a trait like this:
//trait that holds value and monad
trait ValueWithMonad[E] {
type A[+E]
type M <: Monad[A]
val v:A[E]
val m:M
}
object M {
//example implementation of test method
def test(amount:Int):ValueWithMonad[Int] = new ValueWithMonad[Int] {
type A[+E] = Option[E]
type M = Monad[Option]
override val v = Option(amount)
override val m = OptionMonad
}
//test can now be used like this
def t {
val vwm = test(1)
vwm.m.bind(vwm.v, (x:Int) => {
println(x)
vwm.m.ret(x)
})
}
}
trait Monad[A[_]] {
def bind[E,E2](m:A[E], f:E=>A[E2]):A[E2]
def ret[E](e:E):A[E]
}
object OptionMonad extends Monad[Option] {
override def bind[E,E2](m:Option[E], f:E=>Option[E2]) = m.flatMap(f)
override def ret[E](e:E) = Some(e)
}

Method polymorphism

I am trying to write a generic method f[T](id:String) that is something like this:
case class A(x:String)
case class B(y:String)
case class C(z:String)
def f[T](id:String): T = { /* equivalent to T(id) */ }
val result1:A = f[A]("123") // returns A("123")
val result2:B = f{B]("345") // returns B("345")
val result3:C = f[C]("567") // returns C("567")
Unfortunately I cannot figure out how to work with the type T inside the method, besides using reflection. By "working with the type T" i mean for example being able to do something like the following, which I know doesn't work (for illustration purposes only):
T match {
case A => A(id)
case B => B(id)
}
or simply invoke T(ID) to create a new object of whatever type T is.
I can of course break up this into three methods:
def f1(id:String): A = { A(id) }
def f2(id:String): B = { B(id) }
def f3(id:String): C = { C(id) }
val result1:A = f1("123") // returns A("123")
val result2:B = f2("345") // returns B("345")
val result3:C = f3("567") // returns C("567")
but I'm hoping there is a way to keep it as one generic method to avoid some ugly boilerplate code duplication, and still be nearl as fast as the tree method version.
If you do not want to use reflection (ClassTag or TypeTag), you could use a Factory type class to achieve the desired functionality (unless it defeats the purpose of your generic function by generating a lot of duplicated simple code ;)).
case class A(s: String)
case class B(s: String)
case class C(s: String)
trait Factory[T] extends ((String) => T) {
def apply(arg: String): T
}
object Factory {
implicit object AFactory extends Factory[A] {
override def apply(arg: String): A = A(arg)
}
implicit object BFactory extends Factory[B] {
override def apply(arg: String): B = B(arg)
}
implicit object CFactory extends Factory[C] {
override def apply(arg: String): C = C(arg)
}
}
def create[T : Factory](arg: String): T = implicitly[Factory[T]].apply(arg)
create[A]("foo") | -> res0: A = A(foo)