Scala: Multiple type parameters for implicit class - scala

I'm trying to port parts of a Haskell library for datatype-generic programming to Scala. Here's the problem I've run into:
I've defined a trait, Generic, with some container-type parameter:
trait Generic[G[_]] {
// Some function declarations go here
}
Now I have an abstract class, Collect, with three type parameters, and a function declaration (it signifies a type than can collect all subvalues of type B into a container of type F[_] from some structure of type A):
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
In order to make it extend Generic, the first two type parameters F[_] and B are given, and A is curried (this effect is simulated using type lambdas):
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
The problem is that I need the last class definition to be implicit, because later on in my code I will need to be able to write functions like
class GUnit[G[_]](implicit gg: Generic[G]) {
// Some definitions
}
When I simply prepend implicit to the class definition, I get the an error saying implicit classes must accept exactly one primary constructor parameter. Has anyone encountered a similar problem? Is there a known way to work around it? I don't currently see how I could refactor my code while keeping the same functionality, so any advice is welcome. Thanks in advance!

Implicit classes don't work that way. They are a shorthand for implicit conversions. For instance implicit class Foo(i: Int) is equal to class Foo(i: Int); implicit def Foo(i: Int) = new Foo(i). So it only works with classes that have exactly one parameter in their constructor. It would not make sense for most 0 parameter (type-)classes.
The title of your question also seems to suggest that you think the compilation error is talking about type parameters of the type constructor, but I hope the above paragraph also makes clear that it is actually talking about value parameters of the value constructor.
For what (I think) you are trying to do, you will have to provide an implicit instance of CollectC yourself. I suggest putting it in the companion object of Collect. But you can choose an alternative solution if that fits your needs better.
scala> :paste
// Entering paste mode (ctrl-D to finish)
trait Generic[G[_]] {
// Some function declarations go here
}
abstract class Collect[F[_],B,A] {
def collect_ : A => F[B]
}
object Collect {
implicit def mkCollectC[F[_],B]: CollectC[F,B] = new CollectC[F,B]
}
class CollectC[F[_],B] extends Generic[({type C[A] = Collect[F,B,A]})#C] {
// Function definitions go here
}
// Exiting paste mode, now interpreting.
warning: there were four feature warnings; for details, enable `:setting -feature' or `:replay -feature'
defined trait Generic
defined class Collect
defined object Collect
defined class CollectC
scala> implicitly[Generic[({type C[X] = Collect[List,Int,X]})#C]]
res0: Generic[[X]Collect[[+A]List[A],Int,X]] = CollectC#12e8fb82

Related

Context Bound on a Generic Class Using Implicits

I am learning Scala in order to use it for a project.
One thing I want to get a deeper understanding of is the type system, as it is something I have never used before in my other projects.
Suppose I have set up the following code:
// priority implicits
sealed trait Stringifier[T] {
def stringify(lst: List[T]): String
}
trait Int_Stringifier {
implicit object IntStringifier extends Stringifier[Int] {
def stringify(lst: List[Int]): String = lst.toString()
}
}
object Double_Stringifier extends Int_Stringifier {
implicit object DoubleStringifier extends Stringifier[Double] {
def stringify(lst: List[Double]): String = lst.toString()
}
}
import Double_Stringifier._
object Example extends App {
trait Animal[T0] {
def incrementAge(): Animal[T0]
}
case class Food[T0: Stringifier]() {
def getCalories = 100
}
case class Dog[T0: Stringifier]
(age: Int = 0, food: Food[T0] = Food()) extends Animal[String] {
def incrementAge(): Dog[T0] = this.copy(age = age + 1)
}
}
So in the example, there is a type error:
ambiguous implicit values:
[error] both object DoubleStringifier in object Double_Stringifier of type Double_Stringifier.DoubleStringifier.type
[error] and value evidence$2 of type Stringifier[T0]
[error] match expected type Stringifier[T0]
[error] (age: Int = 0, food: Food[T0] = Food()) extends Animal[String]
Ok fair enough. But if I remove the context bound, this code compiles. I.e. if I change the code for '''Dog''' to:
case class Dog[T0]
(age: Int = 0, food: Food[T0] = Food()) extends Animal[String] {
def incrementAge(): Dog[T0] = this.copy(age = age + 1)
}
Now I assumed that this would also not compile, because this type is more generic, so more ambiguous, but it does.
What is going on here? I understand that when I put the context bound, the compiler doesn't know whether it is a double or an int. But why then would an even more generic type compile? Surely if there is no context bound, I could potentially have a Dog[String] etc, which should also confuse the compiler.
From this answer: "A context bound describes an implicit value, instead of view bound's implicit conversion. It is used to declare that for some type A, there is an implicit value of type B[A] available"
Now I assumed that this would also not compile, because this type is more generic, so more ambiguous, but it does.
The ambiguity was between implicits. Both
Double_Stringifier.DoubleStringifier
and anonymous evidence of Dog[T0: Stringifier] (because class Dog[T0: Stringifier](...) is desugared to class Dog[T0](...)(implicit ev: Stringifier[T0])) were the candidates.
(Int_Stringifier#IntStringifier was irrelevant because it has lower priority).
Now you removed the context bound and only one candidate for implicit parameter in Food() remains, so there's no ambiguity. I can't see how the type being more generic is relevant. More generic doesn't mean more ambiguous. Either you have ambiguity between implicits or not.
Actually if you remove import but keep context bound the anonymous evidence is not seen in default values. So it counts for ambiguity but doesn't count when is alone :)
Scala 2.13.2, 2.13.3.
It seems to me (and if I'm wrong I'm hoping #DmytroMitin will correct me), the key to understanding this is with the default value supplied for the food parameter, which makes class Dog both a definition site, requiring an implicit be available at the call site, as well as a call site, requiring an implicit must be in scope at compile time.
The import earlier in the code supplies the implicit required for the Food() call site, but the Dog constructor requires an implicit, placed in ev, from its call site. Thus the ambiguity.

In Scala, How to perform compile-time type check on companion object?

An easy thing to do in many languages but not in Scala is:
Define archetype 'Super', such that all implementations of 'Super' has to define a constructor 'create()'.
I found this constraint very important and is able to identify a lot of problems before runtime. However this feature is only partially enforced in Java (by defining an 'abstract' static method that always throws an error) and completely missing in Scala (companion object is completely detached from class and cannot be enforced in archetype).
is there a macro or tool that allows me to do this?
UPDATE Sorry my question was missing context and examples. Here is a formal use case in scala:
In project A, we define an interface that can be extended by all subprojects:
trait AbstractFoo {}
This interface should always have a default 0-parameter builder/constructor, so project A can initialize it on-demand, however, the implementation of each constructor is unknown to project A:
object AbstractFoo {
def default[T <: AbstractFoo: ClassTag](): T
}
So the problem becomes: How to rigorously define AbstractFoo, such that for all subprojects of A, any implementation(s) of AbstractFoo:
case class Foo(...) extends AbstractFoo
must satisfy:
'Foo' must have a 0-parameter builder/constructor defined (presumably in its companion object)
calling AbstractFoo.defaultFoo can invoke this 0-parameter builder/constructor
It should be noted that in an alternative conditions, a solution exists which is to define every companion object as an implicit type class:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
}
object AbstractFoo {
implicit object Foo extends FooBuilder[Foo] {
def default() = {...}
}
def default[T <: AbstractFoo: FooBuilder](): T = {
implicitly[FooBuilder[T]].default
}
}
Such that if the implicit object is undefined the compiler will give an implicit not found error (my code snippet may have some syntax error, the idea is from http://www.cakesolutions.net/teamblogs/demystifying-implicits-and-typeclasses-in-scala)
Unfortunately it's not always convenient, because this subproject of A is usually unknown to project A. Yet the default implicit builder cannot be redefined, this makes every invocation of default() more covoluted.
I believe scala is a very extendable language, so there should be at least 1 way to enforce it whether if using macro, annotation or other metaprogramming techniques. Is my question clear enough now?
UPDATE2: I believe I found the solution after carefully study Scaladoc, there is a comment hidden in a corner:
if there are several eligible arguments which match the implicit parameter’s type, a most specific one will be chosen using the rules of static overloading resolution (see Scala Specification §6.26.4):
...
Implicit scope of type arguments (2.8.0)
...
So all I need is to write an implicit function in FooBuilder:
trait FooBuilder[T <: AbstractFoo] {
def default(): T
implicit def self = this
}
object Foo extends FooBuilder[Foo]
So everytime someone call:
default[Foo]
scala will refer to the scope of class Foo, which include object Foo, which contains the implicit value Foo, and eventually find the 0-parameter constructor.
I think this definition is better than defining it under object FooBuilder, since you can only define FooBuilder once, thus its not quite extendable. Would you agree with me? If so, could you please revise your answer so I can award you point?
I don't understand why an abstract class or even a Trait won't allow this to be done?
abstract class DefineCreate{
def create(): Unit
}
case class Foo(one: Int)
object Foo extends DefineCreate{
def create(): Unit = { Console.out.println("side-effect") }
}
Thus I force a user to make a create method on the object in question because all implementations of DefineCreate must do so in order to compile.
Update Following Comments
Well, without having to resort to macros and the like, you could achieve the same sort of thing with type classes:
trait Constructor[A]{
def create(): A
}
object Construct{
def create[A](implicit cr: Constructor[A]): A = cr.create()
}
Which doesn't explicitly force the companion object to sprout methods but it does force a user to make the type class if they want to use the Constructor.create[Foo] pattern.

Is using Any for Union type a good idea?

I want to create a class generator (for Avro models). I have a problem because sometime the field of the class I generate could be one of many different types, let's say it could be an Int or a String or whatever. The simple idea is to create that field with the type Any and check at runtime that it is ok.
The problem is that using Any discard some of the powerfull features of the scala type system. Some bug in the code will not be caught at compile time (if I give a List to a function expecting a String or Int covered by an Any).
For example :
Let's I have this description of my class :
{"className" : "MyClass", "fields" : [
{ "fieldName" : "myField", "type" : ["String", "Int"]}
]}
From this description, I create this class :
class MyClass(myField: Any)
I want to create something like this :
class MyClass(myField: String or Int)
Should I stop using Any ? Is using Any generally considered a good idea in the scala community ?
Is using Any generally considered a good idea in the scala community?
Nope. Any means no type information, so it's generally considered a bad practice.
In Scala you can express a union type using Either, although it gets cumbersome if you have a lot of possible types in the union. Example:
class MyClass(myField: Either[String, Int]) {
def doSomething = myField match {
case Left(myStringField) => ???
case Right(myIntField) => ???
}
}
Another viable approach would be to make MyClass generic in its type:
class MyClass[A](myField: A)
However this is not setting any constraint on the type of A.
In order to place a constraint, e.g. make it a finite subset of types, you can use ad-hoc polymorphism:
trait MyConstraint[A]
class MyClass[A: MyConstraint](myField: A)
Now new MyClass(myValue) won't compile unless there is an implicit MyConstraint[A] in scope. Now you can whitelist the types you want to allow using implicit values
implicit object IntConstraint extends MyConstraint[Int]
implicit object StringConstraint extends MyConstraint[String]
Example:
new MyClass(42) // ok, there's implicit evidence of MyConstraint[Int]
new MyClass("foo") // ok, there's implicit evidence of MyConstraint[String]
new MyClass(false) // won't compile, no implicit evidence of MyConstraint[Boolean]
In technical terms, MyConstraint is a type class, used to refine the type A in the constructor of MyClass.
You can characterize a type class even further, by requiring that a set of operations are defined for each of its instances. E.g.
trait MyConstraint[A] {
def mandatoryOp: A
}
implicit object IntConstraint extends MyConstraint[Int] {
def mandatoryOp = 42
}
implicit object StringConstraint extends MyConstraint[String] {
def mandatoryOp = "foo"
}
class MyClass[A](myField: A)(implicit ev: MyConstraint[A]) {
def doSomething: A = ev.mandatoryOp
}
Please note that A: MyConstraint is just syntactic sugar for requiring an implicit parameter of type MyConstraint[A]. In the last example I chose the explicit syntax in order to have the implicit parameter ev available in scope.

Union types as bound for type parameters of a trait (scala)

How can I constrain the type parameters of a trait to be among a distinct set of types (eg., bound by union type)?
As a concrete example, I'd like to create a trait IntegralIndex[T] where T must Int or Long.
I tried the first answer to this question on union types :
sealed abstract class NumericIndex[T]
object NumericIndex {
implicit object IntWitness extends NumericIndex[Int]
implicit object LongWitness extends NumericIndex[Long]
}
trait IntegralIndex[T : NumericIndex]
but that doesn't work; I get traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'
Any other suggestions? Admittedly, I didn't understand the other solutions to the question on union types, so I'd appreciate if the answer is just to use a different answer there, or even to know that it can't be done.
The type class approach is probably the cleanest way to accomplish what you want here, and you're on the right track with your version. It doesn't work in its current form because context bounds are just syntactic sugar for implicit parameters. The following trait definition, for example:
trait IntegralIndex[T: NumericIndex]
Would be desugared to something like this:
trait IntegralIndex[T](implicit num: NumericIndex[T])
But traits don't have constructors, so this isn't valid Scala syntax. You can, however, write something like this:
trait IntegralIndex[T] {
implicit def num: NumericIndex[T]
}
This ensures that you can't create a IntegralIndex[T] unless you have evidence that there's an instance of the NumericIndex type class for T.
Now when you're implementing IntegralIndex, you'd write either:
case class MyIndex[T](whatever: String)(implicit val num: NumericIndex[T])
Or:
case class MyIndex[T: NumericIndex](whatever: String) {
implicit val num = implicitly[NumericIndex[T]]
}
Now all the implicit plumbing is invisible to anyone using MyIndex.

Implementing '.clone' in Scala

I'm trying to figure out how to .clone my own objects, in Scala.
This is for a simulation so mutable state is a must, and from that arises the whole need for cloning. I'll clone a whole state structure before moving the simulation time ahead.
This is my current try:
abstract trait Cloneable[A] {
// Seems we cannot declare the prototype of a copy constructor
//protected def this(o: A) // to be defined by the class itself
def myClone= new A(this)
}
class S(var x: String) extends Cloneable[S] {
def this(o:S)= this(o.x) // for 'Cloneable'
def toString= x
}
object TestX {
val s1= new S("say, aaa")
println( s1.myClone )
}
a. Why does the above not compile. Gives:
error: class type required but A found
def myClone= new A(this)
^
b. Is there a way to declare the copy constructor (def this(o:A)) in the trait, so that classes using the trait would be shown to need to provide one.
c. Is there any benefit from saying abstract trait?
Finally, is there a way better, standard solution for all this?
I've looked into Java cloning. Does not seem to be for this. Also Scala copy is not - it's only for case classes and they shouldn't have mutable state.
Thanks for help and any opinions.
Traits can't define constructors (and I don't think abstract has any effect on a trait).
Is there any reason it needs to use a copy constructor rather than just implementing a clone method? It might be possible to get out of having to declare the [A] type on the class, but I've at least declared a self type so the compiler will make sure that the type matches the class.
trait DeepCloneable[A] { self: A =>
def deepClone: A
}
class Egg(size: Int) extends DeepCloneable[Egg] {
def deepClone = new Egg(size)
}
object Main extends App {
val e = new Egg(3)
println(e)
println(e.deepClone)
}
http://ideone.com/CS9HTW
It would suggest a typeclass based approach. With this it is possible to also let existing classes be cloneable:
class Foo(var x: Int)
trait Copyable[A] {
def copy(a: A): A
}
implicit object FooCloneable extends Copyable[Foo] {
def copy(foo: Foo) = new Foo(foo.x)
}
implicit def any2Copyable[A: Copyable](a: A) = new {
def copy = implicitly[Copyable[A]].copy(a)
}
scala> val x = new Foo(2)
x: Foo = Foo#8d86328
scala> val y = x.copy
y: Foo = Foo#245e7588
scala> x eq y
res2: Boolean = false
a. When you define a type parameter like the A it gets erased after the compilation phase.
This means that the compiler uses type parameters to check that you use the correct types, but the resulting bytecode retains no information of A.
This also implies that you cannot use A as a real class in code but only as a "type reference", because at runtime this information is lost.
b & c. traits cannot define constructor parameters or auxiliary constructors by definition, they're also abstract by definition.
What you can do is define a trait body that gets called upon instantiation of the concrete implementation
One alternative solution is to define a Cloneable typeclass. For more on this you can find lots of blogs on the subject, but I have no suggestion for a specific one.
scalaz has a huge part built using this pattern, maybe you can find inspiration there: you can look at Order, Equal or Show to get the gist of it.