How can I achieve this:
final case class ChairId(id: String)
trait GeneratorLike[TO, TC <: AbstractId] {
val prefix: String
def generate(): TC = TO.apply(prefix + "-" + UUID.randomUUID())
}
implicit object ChairIdGenerator extends GeneratorLike[ChairId.type, ChairId] {
val prefix: String = "CHAIR"
}
implicit def IdFn[TO, TC <: AbstractId](x: TO)(implicit ev: GeneratorLike[TO, TC]): GeneratorLike[TO, TC] = ev
//right now I can call:
ChairId.generate()
I don't want to define companion object for that situation and I wondered if there is a chance to extend object with use of implicits?
When I do (I use TO as TypeObject and TC as TypeClass naming) idFn[TO, TC] I want TO to be object that implements def apply(id: String): TC can I enforce that? And how would I get to use this function? It feels totally impossible to call function on type parameter :/
It is impossible to call a method on a type parameter, because it represents a type and not an object. You can call a method on an object, because it is something that exists, but a type is an abstract concept. I don't know what your motivation is for wanting to implicitly add generate() to companion objects, because it actually requires just as much code to define an implicit GeneratorLike than it does to define the companion for ChairId.
If you force GeneratorLike to have an apply method (which can be implemented by case class apply), and remove the first type parameter, this will work.
trait GeneratorLike[TC <: AbstractId] { this: Singleton =>
val prefix: String
def apply(id: String): TC
def generate(): TC = apply(prefix + "-" + UUID.randomUUID())
}
abstract class AbstractId
final case class ChairId(id: String) extends AbstractId
object ChairId extends GeneratorLike[ChairId] {
val prefix = "CHAIR"
}
scala> ChairId.generate()
res0: ChairId = ChairId(CHAIR-60bb01c7-af95-46c7-af45-0b3fa78b3080)
Structural typing is not a particularly good idea on the JVM, so always try to avoid the def test(x: {def apply(s: String)}): TC type stuff because it is implemented using reflection which can be a dog performance wise.
Second, you should probably avoid using val inside a trait. Read here.
The approach you have considered is actually the right one, and namely type classes.
trait HasGenerator[T] {
def apply(uuid: String): T
def generate[T : Generator] = apply(Generator[T].generate)
}
final case class ChairId(id: String)
object ChairId extends HasGenerator[ChairId]
trait Generator[TO] {
def prefix: String
def generate(): String = prefix + "-" + UUID.randomUUID()
def apply(): String = generate
}
object Generator {
def apply[T : Generator] = implicitly[Generator[T]]
}
// Notice .type is not necessary
implicit object ChairIdGenerator extends Generator[ChairId] {
override def prefix = "CHAIR"
}
Why not just use:
ChairId(Generator[ChairId])
This all seems like overkill though so you can quite easily somehow. It's worth fleshing out your requirements a bit more because type classes don't really seem super necessary just yet. You could just do with:
Update
If you use something like the HasGenerator that I have added above in conjunction with the companion object, you can now successfully call ChairId.generate()
Related
Let's imagine I have the following base trait and case classes
sealed trait BaseTrait
case class Foo(x: Integer = 1) extends BaseTrait
case class Bar(x: String = "abc") extends BaseTrait
I would like to create a generic interface for classes which can process BaseTrait instances, something like the following
class FooProcessor(val model: FooModel) extends BaseProcessor[Foo] {
val v: Option[Foo] = model.baseVar
}
class BarProcessor(val model: BarModel) extends BaseProcessor[Bar] {
val v: Option[Bar] = model.baseVar
}
For this I have the following traits
trait BaseModel[T <: BaseTrait] {
var baseVar: Option[T] = None
}
trait BaseProcessor[T <: BaseTrait] {
def model: BaseModel[T]
def process(x: T): Unit = model.baseVar = Option(x)
}
The model definitions are the following
class FooModel extends BaseModel[Foo]
class BarModel extends BaseModel[Bar]
Now lets imagine I have the following processors somewhere in my app
val fooProcessor = new FooProcessor(new FooModel)
val barProcessor = new BarProcessor(new BarModel)
I would like to handle them in a somewhat generic way, like this
def func[T <: BaseTrait](p: T) {
val c/*: BaseProcessor[_ >: Foo with Bar <: BaseTrait with Product with Serializable]*/ = p match {
case _: Foo => fooProcessor
case _: Bar => barProcessor
c.process(p)
}
The compiler is not really happy about the last line, it says
type mismatch;
found : T
required: _1
If I understand correctly this is basically the compiler trying to prevent barProcessor.process(Foo()) from happening. I've tried a couple of solutions to get around this and achieve the desired behavior:
the simplest way around this is calling the proper *Processor.process with the proper BaseTrait instance inside the match case, which seems to defy the whole point of handling them in a somewhat generic way
use an abstract type in the BaseModel and BaseProcessor, which one hand got rid of the somewhat unneeded type parameter in BaseModel but the compilers complaint is still valid and I was not able to figure out if it's possible to get that to work
get rid of the type parameter and contraint from the BaseModel, and just do a type cast in the processor to get the proper type, but the explicit type cast also isn't really what I was hoping for
Like so:
trait BaseModel {
var baseVar: Option[BaseTrait] = None
}
trait BaseProcessor[T <: BaseTrait] {
def model: BaseModel
def process(x: T): Unit = model.baseVar = Some(x)
def getBaseValue: T = model.baseVar.map(_.asInstanceOf[T])
}
I guess one could also somehow convince the compiler that the two types (T of the Processor and T of the func parameter p) are equivalent, but that also seems like an overkill (and I'm also not really sure how it can be done).
So my question is the following: is it possible to do what I'm trying to achieve here (managing processors in a uniform way + each processor knows their specific type of BaseTrait) in a somewhat easy fashion? Is there a better model for this which I'm missing?
Update
As per Tim's answer making the controllers implicit solves the problem, however if you want to have a class where you define your controllers + have 'func' on it's interface the compiler no longer seems to properly resolve the implicits. So if I try to do something like this
class ProcessorContainer {
implicit val fooProcessor = new FooProcessor(new FooModel)
implicit val barProcessor = new BarProcessor(new BarModel)
def func[T <: BaseTrait](p: T) = typedFunc(p)
private def typedFunc[T <: BaseTrait](p: T)(implicit processor: BaseProcessor[T]) =
processor.process(p)
}
class Test {
val processorContainer = new ProcessorContainer
processorContainer.func(Foo())
processorContainer.func(Bar())
}
I get the following compile error (one for Foo and one for Bar):
could not find implicit value for parameter processor: BaseProcessor[Foo]
not enough arguments for method
Is there a way around this? I could of course expose the controllers so they can be passed in implicitly, however I'd prefer not doing that.
You can create a simple typeclass by making the processors implicit and passing them as an extra argument to func:
implicit val fooProcessor = new FooProcessor(new FooModel)
implicit val barProcessor = new BarProcessor(new BarModel)
def func[T <: BaseTrait](p: T)(implicit processor: BaseProcessor[T]) =
processor.process(p)
If you pass a Foo to func it will call FooProcessor.process on it, and if you pass a Bar to func it will call BarProcessor on it.
NOTE: if someone can come up with a better title for what I am trying to ask - please mention or edit.
Given a wrap method:
trait MyWrapperBound {
val message: String
}
def wrap[T <: MyWrapperBound](message: String): T
I am looking for a way to describe that all all implementations of MyWrapperBound should have a constructor that takes a message: String so I can construct and return it from my wrap method.
I can think of a couple of ways to do this:
Method 1 - using an implicit:
def wrap[T <: MyWrapperBound](message: String)(implicit factory: String => T): T
This would mean that any MyWrapperBound impl. would also have to create the implicit:
case class SimpleBound(message: String) extends MyWrapperBound
object SimpleBound {
implicit def factory(message: String): SimpleBound = SimpleBound(message)
}
This would result in a fair amount of boilerplate - which I'd like to avoid.
Method 2 - macro:
def wrap[T <: MyWrapperBound](message: String): T = macro ...
The macro would take the type, assert there is a valid constructor, constructing the type if its there and throw a nice compile error if not present for the developer to go and fix (by adding a valid constructor)
My question is - being fairly new to scala, is there a simpler option that I am missing? or another option that makes more sense?
If you're amenable to typeclasses there is a slightly simpler answer involving implicits. You can accomplish what you're trying to do rather easily by adding a type parameter to MyWrapperBound and enumerating the types of messages you'd like to support using the Show typeclass. For instance, if you knew everything that you were attempting to wrap supported a map A => String, you could supply a Show[A] implicit to your wrap method like so:
trait Show[A] {
def show(a: A): String
}
trait MyWrapperBound[A] {
val message: String
}
object MyWrapperBound {
def wrap[A](a: => A)(implicit ev: Show[A]): MyWrapperBound[A] =
new MyWrapperBound[A] {
override val message: String = ev.show(a)
}
}
object ShowInstances {
case class MyDS(someInformation: List[String])
implicit val simpleShow: Show[String] = new Show[String] {
override def show(a: String): String = a
}
implicit val slightlyMoreComplexShow: Show[MyDS] = new Show[MyDS] {
override def show(a: MyDS): String = a.someInformation.mkString("[", ",", "]")
}
}
As always, the code compiles and produces the desired output. Adding more support is as easy as adding more instances to ShowInstances. This allows you to decouple the map A => String from the wrapper logic itself, so that wrap becomes a simple constructor for MyWrapperBound.
If you don't like the idea of parametrizing your MyWrapperBound with a type parameter, it's not even necessary if you're not planning to have instances of it indexed by some message type.
In a Scala typeclass, there will be a trait on which operations are defined, e.g. NumberLike with plus() and minus(), Transformer with transform(), or AddressLabelMaker with toLabel(). It's then possible to extend the trait with typeclass members.
Typically the operations will have the same number of parameters for different members, i.e. the signatures will look very similar. My question is: what happens if a member needs what is essentially the same operation, but with an extra parameter (maybe just an implicit one: something that modifies the operation based on the context) ?
Is there a way to do this without defining a whole new (similar) typeclass?
With an extra explicit parameter? No. Each typeclass instance must have the same interface, that of the typeclass. With an implicit parameter? Yes. You can declare an implicit def that returns the required implicit but itself requires an implicit. Here is an example to explain:
case class Cat(name: String)
case class Person(name: String)
case class Silverware(kind: String)
implicit object GoodSilver extends Silverware("the good silver")
trait AnimalFeeder[A] {
def feed(animal: A): Unit
}
implicit object CatFeeder extends AnimalFeeder[Cat] {
def feed(cat: Cat) = println(cat.name + " eats cat food!")
}
implicit def personFeeder(implicit silverware: Silverware) =
new AnimalFeeder[Person] {
def feed(person: Person) =
println(person.name + " eats people food with " + silverware.kind)
}
def feedAnimal[A](a: A)(implicit feeder: AnimalFeeder[A]) = feeder.feed(a)
CatFeeder provides an implicit that cat feed any Cat. personFeeder is a def that can create an implicit to feed a Person, but requires an implicit Silverware. So in an invocation like:
feedAnimal(Person("John"))
The compiler will search for an implicit AnimalFeeder[Person], will find personFeeder, and then will search for an implicit Silverware, finally finding GoodSilver.
It is important to note that personFeeder is not an implicit conversion. Despite being a method from Silverware to AnimalFeeder[Person] it will never implicitly convert Silverware. This is because its parameter is marked implicit, implicit conversions must have their parameter explicit.
I'm not sure what you mean to question, but if it's about changing what a typeclass' instance's methods do, I think it should be possible, by changing the instance's condition somehow before you call the methods.
Given a type class Printer[A]:
trait Printer[A] {
def print(a: A): Unit
}
def print[A: Printer](a: A) = implicitly[Printer[A]].print(a)
Defining an implicit Printer[Int], named IntPrinter:
implicit object IntPrinter extends Printer[Int] {
def print(a: Int) = s"integer $a"
}
print(3) //=> integer 3
Modifying IntPrinter so it can change the text to print:
implicit object IntPrinter extends Printer[Int] {
var text: String = "integer "
def print(a: Int) = s"$text$a"
}
print(3) //=> integer 3
IntPrinter.text = ":"
print(3) //=> :3
Thus you can control the behavior of typeclass` methods.
The way I am solving this is to wrap the parameters in a type Params, which has subtypes as necessary. Params becomes the second type parameter of the typeclass. So now members of the typeclass can have the same signature for operations.
Wonder if this is a common solution?
Here is what an example of what I am getting at. I'm not sure though, maybe this code can be improved.
trait Animal
case class Cat(name: String) extends Animal
case class Person(name: String) extends Animal
case class Silverware(kind: String)
trait FeederParams
case class CatFeederParams() extends FeederParams
case class PersonFeederParams(val silverware: Silverware) extends FeederParams
trait AnimalFeeder[A <: Animal, P <: FeederParams] {
def feed(animal: A)(implicit params: P): Unit
}
implicit object CatFeeder extends AnimalFeeder[Cat, CatFeederParams] {
def feed(cat: Cat)(implicit params: CatFeederParams) =
println(cat.name + " eats cat food!")
}
implicit object PersonFeeder extends AnimalFeeder[Person, PersonFeederParams] {
def feed(person: Person)(implicit params: PersonFeederParams) =
println(person.name + " eats people food with " + params.silverware.kind)
}
def feedAnimal[A <: Animal, P <: FeederParams](a: A)(implicit feeder: AnimalFeeder[A, P], params: P) =
feeder.feed(a)
implicit object personParams extends PersonFeederParams(Silverware("the good silver"))
implicit object catParams extends CatFeederParams()
feedAnimal(Person("John"))
feedAnimal(Cat("Garfield"))
I'm trying to achieve F-bounded polymorphism without using generics. I also need to use self-typing as I will be referencing this and expecting it to be typed as the subtype.
trait MyTrait[T] { self: Self => // Compilation error: cannot reference 'Self'
type Self <: MyTrait[T]
def doSomethingWithSubtype() {
...
}
}
I can achieve this quite easily using type parameters (i.e. generics), but would like to know if I'm missing something to make the above compile. Can you use abstract types in this way?
Similar questions:
These provide workarounds for similar problems, leading me to believe the above is impossible?
F-Bound Polymorphism with Abstract Types instead of Parameter Types?
F-bounded quantification through type member instead of type parameter?
You can self-type to an abstract type, with one tricky limitation: it has to be defined outside of your trait, but still in scope in a way that allows implementations to implement it with some type. You can do that by wrapping the whole thing into a trait:
trait MyTraitSystem {
type TraitImpl <: MyTrait
trait MyTrait { self: TraitImpl =>
def doSomething(t: TraitImpl): String
}
}
// with an example implementation of the trait:
object MyImpl extends MyTraitSystem {
case class TraitImpl(data: String) extends MyTrait {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
}
This is equivalent to this version using a type parameter:
trait MyTrait[T <: MyTrait[_]] { self: T =>
def doSomething(t: T): String
}
// with an example implementation of the trait:
case class TraitImpl(data: String) extends MyTrait[TraitImpl] {
def doSomething(t: TraitImpl): String = t.data + " " + data
}
Apart from an import MyImpl._ for the abstract-type version, they can be used the same way:
scala> import MyImpl._
import MyImpl._
scala> val a = TraitImpl("hello")
a: MyImpl.TraitImpl = TraitImpl(hello)
scala> val b = TraitImpl("world")
b: MyImpl.TraitImpl = TraitImpl(world)
scala> b.doSomething(a)
res0: String = hello world
The abstract-type version is more verbose, but it works. You also need to carry around a MyTraitSystem in any method/class/... that needs to use TraitImpl so as to provide the type:
object SomewhereElse {
def doSomethingElse(s: MyTraitSystem)(t: s.TraitImpl) =
??? // s.TraitImpl is the implementation type
}
Compared to the type parameter version:
object SomewhereElse {
def doSomethingElse[T <: MyTrait[_]](t: MyTrait[T]) =
??? // T is the implementation type
}
This is probably only one of several ways to do this, but I don't think any way can match the conciseness of the type-parameter-based version.
In Scala v 2.7.7
I have a file with
class Something[T] extends Other
object Something extends OtherConstructor[Something]
This throws the error:
class Something takes type parameters
object Something extends OtherConstructor[Something] {
However, I can't do this
object Something[T] extends OtherConstructor[Something[T]]
It throws an error:
error: ';' expected but '[' found.
Is it possible to send type parameters to object? Or should I change and simply use Otherconstructor
You could use:
object Something extends OtherConstructor[Something[_]]
You will of course be restricted by having an existential type with no upper bound in place instead of a concrete type. This solution may not make sense and you might need one object per concrete type T, for those T's which you care about, e.g.
object StringSomething extends OtherConstructor[Something[String]]
But then this has the (possible) disadvantage that StringSomething is not the companion object of Something.
However, my advice would be don't start messing about designing generic APIs (especially self-referential ones like the above) unless you really, really know what you are doing. It will almost certainly end in tears and there are plenty of CORE Java API's which are terrible because of the way generics have been added (the RowSorter API on JTable being one example)
You can solve the general problem of needing object Foo[T] by moving the type parameter to the methods in object Foo:
class Foo[T](t1: T, t2: T)
object Foo {
def apply[T](x: T): Foo[T] = new Foo(x, x)
def apply[T](x: T, y: T): Foo[T] = new Foo(x, y)
}
If you really need one object per T, you can make a class, and have the type-free companion return it from apply.
class Foo[T](t1: T, t2: T)
class FooCompanion[T] {
def apply(x: T): Foo[T] = new Foo(x, x)
def apply(x: T, y: T): Foo[T] = new Foo(x, y)
}
object Foo {
def apply[T] = new FooCompanion[T]
}
object demo extends App {
val x: Foo[Double] = Foo.apply.apply(1.23) // this is what is really happening
val y: Foo[Int] = Foo[Int](123) // with the type both apply calls are automatic
}
Note this will re-construct the Foo[T] companion on each call so you would want to keep it light and stateless.
An explicit solution the the problem above:
class Other
class OtherConstructor[O <: Other] {
def apply(o: O): O = o // constructor 1 in base class
}
class Something[T](value: T) extends Other
class SomethingConstructor[T] extends OtherConstructor[Something[T]] {
def apply(o: T, s: String) = new Something[T](o) // constructor 2 in subclass
}
object Something {
def apply[T] = new SomethingConstructor[T] // the "constructor constructor" method
}
object demoX extends App {
val si = new Something(123)
val sd = new Something(1.23)
val si1: Something[Int] = Something[Int](si) // OtherConstructor.apply
val sd1: Something[Double] = Something[Double](1.23, "hello") // SomethingConstructor[Double].apply
}
An object has to have a concrete type. The Scala object contruct is not a exception to this rule.
A valid definition is
object Something extends OtherConstructor[Something[T]] { }
where T is some concrete type.
Thanks for the answers
object Something extends OtherConstructor[Something[_]]
seems to be compiling (although I have yet to run/test that :-))
#oxbow_lakes, I've followed your advice - of avoiding the type system - till now but I've got to do it!!!
I've been studying existential types, type-erasure and all that but its still not in my grasp :-(