Implicit conversions in the context of a class constructor (case)

I would like the constructors of the apply class for the automatic companion class of the case class to perform implicit conversions for me, but I can't figure out how to do this. I searched everything and the closest answer I could find was for this question (I will explain why this is not what I am looking for below).

I have a case class that looks something like this:

 case class Container(a: Long, b: Long, c: Long) 

I use a container to count instances where certain conditions apply, so I want the constructor to automatically convert the boolean parameters to longs ( if (boolean) 1L else 0L ).

Of course, the real-case class has many parameters, so it would be tiring and terrible to repeat to make my own companion object and overload apply to accept the Boolean parameters. In addition, something like the code below is not ideal (if it was implemented correctly in some way), since it takes only logical arguments:

 object Container { def apply(args: Boolean*) = { // doesn't REALLY work since number of arguments not enforced Container(args map { if (_) 1L else 0L } toArray: _*) } } val c1 = Container(1, 0, 1) // works val c2 = Container(true, false, true) // might be workable if done correctly val c3 = Container(true, 0, 1) // won't work 

I tried adding the implicit conversion to the companion object (below), hoping that it would be automatically used in Container.apply , but it doesn't seem to actually put the implicit conversion in the namespace of the code that invokes the application.

 object Container { implicit def booleanToLong(x: Boolean): Long = if (x) 1L else 0L } 

I can get everything to work using this hacky workaround:

 { import Container.booleanToLong // all of these now work val c1 = Container(1, 0, 1) val c2 = Container(true, false, true) val c3 = Container(true, 0, 1) // works!!! } 

The biggest problem is that I need to import booleanToLong into the code that the Container wants to create and therefore must put it in its own security block ( booleanToLong usually undesirable).

Finally, the decision to use an implicit parameter, which includes implicit conversion, does not work, because it will require an explicit override of apply , defeating the goal of not repeating a long list of parameters and types of marshaling.

Is there a way to do this so that I get implicit conversions for free every time I create a Container , but not otherwise? Or is this impossible due to some technical limitation?

+7
scala implicit implicit-conversion
source share
1 answer

You can use some kind of magnetic pattern option to make it more secure. First for a class like:

 trait ToLong[A] { def apply(a: A): Long } implicit object longToLong extends ToLong[Long] { def apply(l: Long) = l } implicit object booleanToLong extends ToLong[Boolean] { def apply(b: Boolean) = if (b) 1L else 0L } 

Now we need only one additional constructor:

 case class Container(a: Long, b: Long, c: Long) object Container { def apply[A: ToLong, B: ToLong, C: ToLong](a: A, b: B, c: C) = new Container( implicitly[ToLong[A]].apply(a), implicitly[ToLong[B]].apply(b), implicitly[ToLong[C]].apply(c) ) } 

And we can write the following:

 val c1 = Container(1, 0, 1) val c2 = Container(true, false, true) val c3 = Container(true, 0L, 1L) 

No need to introduce a pretty scary general conversion from Boolean to Long .

+6
source share

All Articles