0

Given a type which has a "converter", I would like to have automatic conversion on method call using this type's companion object. That is, given the following definition,

case class Converted(name: String)

trait Converter[A] {
  def perform: Converted
}

implicit val StringConverter = new Converter[String] {
  def perform = Converted("String")
}

make the following code to work:

implicit def toConverter(a: String.type): Converted = 
  implicitly[Converter[String]].perform // Error: `Found String.type, required AnyRef`

def f(needsConverted: Converted) = ???

f(String) // <- That's what I would like to be able to write.

But this fails and both attempts for conversion fail. Note that I cannot change f because it is provided by a third-party library and there are many of them.

  1. Can I make f(String) compile using implicits?

If not possible for Strings, what about classes which do have a companion object, can I do this generically like:

object TheClass

case class TheClass()

implicit val TheClassConverter = new Converter[TheClass] {
  def perform = Converted("TheClass")
}

implicit def toConverter[A: Converter](a: A.type): Converted =
  implicitly[Converter[A]].perform // Error: `Not found value A`

implicit def toConverter(a: TheClass.type): Converted = 
  implicitly[Converter[TheClass]].perform // This works but is not generic

f(TheClass) // This works.
  1. Can I make the first toConverter to compile ?
Mikaël Mayer
  • 10,425
  • 6
  • 64
  • 101
  • I suppose there's a good reason, but why don't you do `implicit val TheClassConverter: Converter[TheClass.type] = ???` ? – Jasper-M Mar 29 '17 at 09:36
  • Thanks that answers my second question. Can I now write something for `String`? – Mikaël Mayer Mar 29 '17 at 12:14
  • ok I found for `String`. I just need to define an `object String`... If you provide your comment as an answer, I can accept it. – Mikaël Mayer Mar 29 '17 at 12:17
  • If your `Converter[A]` really doesn't use `A` anywhere in its body, why does it have the type parameter? If it does, having a `Converter[MyClass.type]` when you need a `Converter[MyClass]` doesn't help. – Alexey Romanov Mar 30 '17 at 06:35
  • Please note that the above question had a simplified example to reproduce the problem with implicits, but don't worry in my case I do use the type parameter `A` in the body. – Mikaël Mayer Mar 30 '17 at 10:15

3 Answers3

1

Can I make f(String) compile using implicits?

No. You can define a value called String, of course, but it won't be related to the type String.

implicit toConverter[A: Converter](a: A.type): Converted =
    implicitly[Converter[A]].perform

A in A.type must be a value; it is not related to the type parameter A.

In fact, so far as Scala's type system is concerned, there is no relationship between a class/trait and its companion object. So you can't do what you want generically.

Of course, if you don't insist on using () instead of [], it becomes trivial:

def f1[A: Converter] = f(implicitly[Converter[A]].perform)

f1[String]
f1[TheClass]
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
1

Instead of defining an implicit instance for the type MyClass you can define an implicit instance for the companion type MyClass.type.

implicit val TheClassConverter: Converter[MyClass.type] = new Converted[MyClass.type] {
  def perform = Converted("MyClass")
}
Jasper-M
  • 14,966
  • 2
  • 26
  • 37
0

Not sure, what are you trying to accomplish, but following works for me

case class Converted(name: String)

trait Converter[A] {
  def perform: Converted
}

implicit def toConverted(name: String) = Converted("String")
implicit def toIntConverted(int: Int) = Converted("Int")

def f(needsConverted: Converted): String = needsConverted.name

f("some")
f(5)
mavarazy
  • 7,562
  • 1
  • 34
  • 60
  • No, I'm really looking to be able to pass the *type* as an input to `f`, not a value of the `type`. For now, I'm only able to write something like `f(TheClass)` the last example of my second question, and only if I have an implicit from `TheClass.type` to `Converter`. I would like to do the same for `String` and also generically if I have a type that can be converted to a `Converter` – Mikaël Mayer Mar 29 '17 at 12:06