Explanation of scala "double definition" fix using by-name params or DummyImplicit

Solution 1:

The relevant section of compiled code for option-1 looks like

def apply(subfield1: Function0, subfield2: Option): Field1 = scala.Predef.???();
def apply(subfield1: Option, subfield2: Function0): Field1 = scala.Predef.???();

As you can see by-name parameters are converted to Function0, so reusing the name is possible.

For option-2 the implicit curried parameters are added as extra parameters to functions, thus making it possible to use the same name.

def apply(subfield1: Option, subfield2: Option, i: DummyImplicit): Field1 = scala.Predef.???();
def apply(subfield1: Option, subfield2: Option, i: DummyImplicit, i2: DummyImplicit): Field1 = scala.Predef.???();

You can also see that type erasure does happen.

EDIT - Using TypeTag to overcome type erasure

def apply[T: TypeTag](subfield1: => Option[T], subfield2: Option[T]): Field1 =
  typeOf[T] match {
    case tpe if tpe =:= typeOf[String]  => new Field1(subfield1.asInstanceOf[Option[String]], subfield2.asInstanceOf[Option[String]])
    case tpe if tpe =:= typeOf[Int]  => ???
    case _  => new Field1(subfield1.map(_.toString), subfield2.map(_.toString))
  }