Why does DummyImplicit not disambiguate [String](a: A) from (a: String) - scala

Given the following piece of code:
final case class Attr[A](name: String)(implicit conv: String To A) {
def apply(value: A)(implicit dummy: DummyImplicit) = Attribute(name, value)
def apply(value: String) = Attribute[A](name, value)
}
The Scala compiler complains with "ambiguous reference to overloaded definition" when it sees the values hereafter:
1| val FooAttr = Attr[String]("foo")
2| val catch22 = FooAttr("bar")
Line 1: My intent is it to pass to the factory "Attr" producing "Attributes" the value type "String" as well as the name "foo" for all the attributes it ever produces.
Line 2: Using the previously configured attribute factory I am actually producing an attribute named "foo" with the value "bar" of type "String".
My conclusion: Because the parameterized type "A" for this factory object is "String" the Scala compiler deduces the same parameter signatures of method "apply" being "(value: String)" which are ambiguous. Therefore I tried to make a difference in signature by adding an implicit parameter list.
After having read an article about type erasure and DummyImplicit and consulting the Scala reference section "7.2 Implicit parameters" I thought "(implicit dummy: DummyImplicit)" would do the trick.
For the moment my solution is to have the minimal wrapper:
final case class Txt(str: String) {
override def toString = str
}
Given that an implicit value of type "Str To Txt", i.e. a suitable conversion function, could be found, the second line from above compiles, i.e.:
2| val catch22 = FooAttr("bar")
It seems I was thinking too complicated. Instead to overload the apply method with a parameter list of (value: String), I simply got rid of it. The version that lives up to my full expectations now looks like:
final case class Attr[A](name: String)(implicit conv: String To A) {
def apply(value: A) = Attribute(name, value)
}

How about this?
case class Attribute[A](name: String, value: A)
case class AttrBuilder[A](name: String)(implicit conv: String => A) {
def apply[B](value: B)(implicit conv: B => A) = Attribute(name, conv(value))
}
val bldr = new AttrBuilder[String]("MyAttrs")
bldr("hello") // Attribute(MyAttrs, hello)
implicit def int2string(x: Int) = x.toString
bldr(2) // Attribute(MyAttrs, 2), using int2string implicit
bldr(false) // fails; cannot find implicit Boolean => String
The attribute builder bldr will take any value of type B that's convertable to A == String, including strings themselves (the implicit conversion Predef.conforms is used in that case).

Related

Updating case classes from field-name strings and values

Is there a less-verbose way to achieve this?
case class MyClass(
a: A,
b: B,
c: C,
...
)
def updatedFromString(m: MyClass, field: String, value: String) = field match {
case "A" => m.withA(value)
case "B" => m.withB(value)
case "C" => m.withC(value)
...
}
implicit class FromStrings(m: MyClass) {
def withA(v: String) = m.copy(a = A.fromString(v))
def withB(v: String) = m.copy(b = B.fromString(v))
def withC(v: String) = m.copy(c = C.fromString(v))
...
}
MyClass has a lot of fields - a,b,c, etc - all of which are instances of different case classes.
This leads to a lot of case statements above and a lot of updater methods named withXXX, which look fairly repetitive.
You could extract the logic:
// repetitive and generic enough to make it easier to generate
val setters: Map[String, String => MyClass => MyClass] = Map(
"A" -> (v => _.copy(a => A.fromString(v)),
"B" -> (v => _.copy(b => B.fromString(v)),
"C" -> (v => _.copy(c => C.fromString(v)),
...
)
def updatedFromString(m: MyClass, field: String, value: String) =
setters(field)(value)(m)
If it is still too much, you could generate setters using macros or runtime reflection, but I am not sure it is worth the effort.
EDIT: An alternative solution which changes how you deal with code:
sealed trait PatchedField
object PatchedField {
// field names corresponding to names from MyClass
case class FieldA(a: A) extends PatchedField
case class FieldB(b: B) extends PatchedField
...
}
// removed stringiness and creates some type-level information
def parseKV(key: String, value: String): PatchedField = key match {
case "A" => FieldA(A.fromString(v))
case "B" => FieldB(B.fromString(v))
...
}
import io.scalaland.chimney.dls._
def updatedFromString(m: MyClass, field: String, value: String) =
parse(field, value) match {
// performs exhaustivity check
case fieldA: FieldA => m.patchUsing(fieldA)
case fieldB: FieldB => m.patchUsing(fieldB)
...
}
If you don't like it... well, then you have to write you own macro, very obscure shapeless and/or codegen:
there is no way you can generate x.copy(y = z) without a macro, even if some library does it, it does it using a macro underneath. At best you could use some lens library, but AFAIK no lens library out of the box would provide you a Setter for a field by singleton type of the field name (that is without writing something like Lens[Type](_.field) explicitly) - that I believe would be doable with some Shapeless black magic mapping over LabelledGenerics
you might still need to convert a singleton type into A singleton type in compile time - that I am not sure if it is possible in Shapeless so you might need to push it down to value level, summoning a Witness, and then .toUpperCaseing it
you would have to make each field aware of Type.fromString functionality - is it different for each field by its name or my its type? If the latter - you could use a normal parser typeclass. If the former, this typeclass would have to be dependently typed for a singleton type with a field name. Either way you would most likely have to define these typeclasses yourself
then you would have to combine all of that together
It could be easier if you did it in runtime (scanning classes for some method and fields) instead of compile time... but you would have no checks that conversion actually exists for a field string to its value, type erasure would kick in (Option[Int] and Option[String] being the same thing, null no being anything).
With compile time approach you would have to at least define a typeclass per type, and then manually create the code that would put it all together. With some fast prototyping I arrived at:
import shapeless._
import shapeless.labelled._
trait StringParser[A] { def parse(string: String): A }
object StringParser {
implicit val string: StringParser[String] = s => s
implicit val int: StringParser[Int] = s => java.lang.Integer.parseInt(s).toInt
implicit val double: StringParser[Double] = s => java.lang.Double.parseDouble(s).toDouble
// ...
}
trait Mapper[X] { def mapper(): Map[String, StringParser[_]] }
object Mapper {
implicit val hnilMapper: Mapper[HNil] = () => Map.empty
implicit def consMapper[K <: Symbol, H, Repr <: HList](
implicit
key: Witness.Aux[K],
parser: StringParser[H],
mapper: Mapper[Repr]
): Mapper[FieldType[K, H] :: Repr] = () => mapper.mapper() + (key.value.name -> (parser : StringParser[_]))
implicit def hlistMapper[T, Repr <: HList](
implicit gen: LabelledGeneric.Aux[T, Repr],
mapper: Mapper[Repr]
): Mapper[T] = () => mapper.mapper()
def apply[T](implicit mapper: Mapper[T]): Map[String, StringParser[_]] = mapper.mapper()
}
val mappers = Mapper[MyClass]
Which you could use like:
convert a field String to an actual field name
extract a parser from the map using field name
pass the value to the parser
use runtime reflection to simulate copy or generate copy calls using macros
The last part simply cannot be done "magically" - as far as I am aware, there is no library where you would require an implicit Lens[Type, fieldName] and obtain Lens[Type, fieldName] { type Input; def setter(input: Input): Type => Type }, so there is nothing which would generate that .copy for you. As a result it would require some form of manually written reflection.
If you want to have compile-time safety at this step, you might as well do the rest compile-time safe as well and implement everything as a macro which verifies the presence of the right typeclasses and things.

Leveraging a generic return type in Scala

So I would like to use a generic return type and be able to use the info of that type within the function. Not sure this is possible but here is what I would like:
def getStuff[A](a: MyObj, b: String): Option[A] = {
// do some stuff
A match {
case String => Some(a.getString(b))
case Integer => Some(a.getInt(b))
...
case _ => None
}
}
However, as you know, A match is not a possibility. Any ideas on how I could achieve this ?
This is a classic case for using a typeclass:
trait StuffGetter[T] { // typeclass
def get(obj: MyObj, s: String): Option[T]
}
implicit val stringGetter = new StuffGetter[String] {
def get(o: MyObj, s: String): Option[String] = ???
}
implicit val intGetter = new StuffGetter[Int] {
def get(o: MyObj, s: String): Option[Int] = ???
}
def getStuff[A](a: MyObj, b: String)(implicit ev: StuffGetter[A]): Option[A] =
ev.get(a, b)
val stuff0 = getStuff[String](obj, "Hello") // calls get on stringGetter
val stuff1 = getStuff[Int](obj, "World") // call get on intGetter
val stuff2 = getStuff[Boolean](obj, "!") // Compile-time error
The StuffGetter trait defines the operations that you want to perform on the generic type, and each implicit value of that trait provides the implementation for a specific type. (For a custom type these are typically place in the companion object for the type; the compiler will look there for them)
When getStuff is called the compiler will look for an implicit instance of StuffGetter with the matching type. This will fail if no such instance exists, otherwise it will be passed in the ev parameter.
The advantage of this is that the "match" is done at compile time and unsupported types are also detected at compile time.
Conceptually we can differentiate between pattern matching at run-time which looks something like this
def getStuff[A](...) =
A match {
...
}
and pattern matching at compile-time which looks something like this
def getStuff[A](...)(implicit ev: Foo[A]) = {
ev.bar(...)
}
Key concept to understand is that types do not exists at run-time because they get "erased" after compilation so there is not enough information to pattern match on types once the program is running. However at compile-time, that is before the program runs, types do exist and Scala provides means to ask the compiler to effectively pattern match on them via implicit/givens mechanism which looks something like so
// type class requirements for type A
trait StringConverter[A] {
def getOptValue(b: String): Option[A]
}
// evidence which types satisfy the type class
implicit val intStringConverter: StringConverter[Int] = (b: String) => b.toIntOption
implicit val strStringConverter: StringConverter[String] = (b: String) => Some(b)
implicit def anyStringConverter[A]: StringConverter[A] = (b: String) => None
// compile-time pattern matching on type A
def getStuff[A](b: String)(implicit ev: StringConverter[A]): Option[A] = {
ev.getOptValue(b)
}
getStuff[Int]("3") // : Option[Int] = Some(value = 3)
getStuff[String]("3") // : Option[String] = Some(value = "3")
getStuff[Double]("3") // : Option[Double] = None
This compile-time pattern matching is called type class pattern.
Understanding the distinction between types and classes is one of the fundamental concepts in Scala https://docs.scala-lang.org/tutorials/FAQ/index.html#whats-the-difference-between-types-and-classes and gorking it will help understand how to write type classes.
Using custom typeclass similar to Getter:
trait KeyedGetter[S, K, A]:
def get(s: S, key: K): Option[A]
case class MyObj(ints: Map[String, Int], strs: Map[String, String])
object MyObj:
given KeyedGetter[MyObj, String, Int] with
def get(m: MyObj, k: String) = m.ints.get(k)
given KeyedGetter[MyObj, String, String] with
def get(m: MyObj, k: String) = m.strs.get(k)
def getStuff[A](m: MyObj, key: String)(using g: KeyedGetter[MyObj, String, A]): Option[A] =
g.get(m, key)
Using class tags:
case class MyObj(ints: Map[String, Int], strs: Map[String, String])
import reflect._
def getStuff[A](m: MyObj, key: String)(using ct: ClassTag[A]): Option[A] = (ct match
case _ if ct == classTag[String] => m.strs.get(key)
case _ if ct == classTag[Int] => m.ints.get(key)
case _ => None
).asInstanceOf[Option[A]]
If the erased types are insufficient, for a similar approach with type tags see this answer (and ignore the rest).

How can I dynamically construct a Scala class without knowing types in advance?

I want to build a simple library in which a developer can define a Scala class that represents command line arguments (to keep it simple, just a single set of required arguments -- no flags or optional arguments). I'd like the library to parse the command line arguments and return an instance of the class. The user of the library would just do something like this:
case class FooArgs(fluxType: String, capacitorCount: Int)
def main(args: Array[String]) {
val argsObject: FooArgs = ArgParser.parse(args).as[FooArgs]
// do real stuff
}
The parser should throw runtime errors if the provided arguments do not match the expected types (e.g. if someone passes the string "bar" at a position where an Int is expected).
How can I dynamically build a FooArgs without knowing its shape in advance? Since FooArgs can have any arity or types, I don't know how to iterate over the command line arguments, cast or convert them to the expected types, and then use the result to construct a FooArgs. Basically, I want to do something along these lines:
// ** notional code - does not compile **
def parse[T](args: Seq[String], klass: Class[T]): T = {
val expectedTypes = klass.getDeclaredFields.map(_.getGenericType)
val typedArgs = args.zip(expectedTypes).map({
case (arg, String) => arg
case (arg, Int) => arg.toInt
case (arg, unknownType) =>
throw new RuntimeException(s"Unsupported type $unknownType")
})
(klass.getConstructor(typedArgs).newInstance _).tupled(typedArgs)
}
Any suggestions on how I can achieve something like this?
When you want to abstract over case class (or Tuple) shape, the standard approach is to get the HList representation of the case class with the help of shapeless library. HList keeps track in its type signature of the types of its elements and their amount. Then you can implement the algorithm you want recursively on the HList. Shapeless also provides a number of helpful transformations of HLists in shapeless.ops.hlist.
For this problem, first we need to define an auxiliary typeclass to parse an argument of some type from String:
trait Read[T] {
def apply(str: String): T
}
object Read {
def make[T](f: String => T): Read[T] = new Read[T] {
def apply(str: String) = f(str)
}
implicit val string: Read[String] = make(identity)
implicit val int: Read[Int] = make(_.toInt)
}
You can define more instances of this typeclass, if you need to support other argument types than String or Int.
Then we can define the actual typeclass that parses a sequence of arguments into some type:
// This is needed, because there seems to be a conflict between
// HList's :: and the standard Scala's ::
import shapeless.{:: => :::, _}
trait ParseArgs[T] {
def apply(args: List[String]): T
}
object ParseArgs {
// Base of the recursion on HList
implicit val hnil: ParseArgs[HNil] = new ParseArgs[HNil] {
def apply(args: List[String]) =
if (args.nonEmpty) sys.error("too many args")
else HNil
}
// A single recursion step on HList
implicit def hlist[T, H <: HList](
implicit read: Read[T], parseRest: ParseArgs[H]
): ParseArgs[T ::: H] = new ParseArgs[T ::: H] {
def apply(args: List[String]) = args match {
case first :: rest => read(first) :: parseRest(rest)
case Nil => sys.error("too few args")
}
}
// The implementation for any case class, based on its HList representation
implicit def caseClass[C, H <: HList](
implicit gen: Generic.Aux[C, H], parse: ParseArgs[H]
): ParseArgs[C] = new ParseArgs[C] {
def apply(args: List[String]) = gen.from(parse(args))
}
}
And lastly we can define some API, that uses this typeclass. For example:
case class ArgParser(args: List[String]) {
def to[C](implicit parseArgs: ParseArgs[C]): C = parseArgs(args)
}
object ArgParser {
def parse(args: Array[String]): ArgParser = ArgParser(args.toList)
}
And a simple test:
scala> ArgParser.parse(Array("flux", "10")).to[FooArgs]
res0: FooArgs = FooArgs(flux,10)
There is a great guide on using shapeless for solving similar problems, which you may find helpful: The Type Astronaut’s Guide to Shapeless

What does HList#foldLeft() return?

I'm trying to play with HList's from Shapeless.
This is my first try:
trait Column[T] {
val name: String
}
case class CV[T](col: Column[T], value: T)
object CV {
object columnCombinator extends Poly2 {
implicit def algo[A] = at[(String, String, String), CV[A]] { case ((suffix, separator, sql), cv) ⇒
(suffix, separator, if (sql == "") cv.col.name+suffix else sql+separator+cv.col.name+suffix)
}
}
def combine[A <: HList](columns: A, suffix: String, separator: String = " and ")
(implicit l: LeftFolder[A, (String, String, String), columnCombinator.type]): String =
columns.foldLeft((suffix, separator, ""))(columnCombinator)._3
}
The problem is I don't know what foldLeft does return in this example.
I expect it to return (String, String, String), but the compiler tells me that returns l.Out. What is l.Out?
The source code is a little complicated to guess it.
There isn't much information in the web about this.
Some information I've consulted:
Shapeless Tests
Shapeless documentation
Your combine method returns what's called a "dependent method type", which just means that its return type depends on one of its arguments—in this case as a path-dependent type that includes l in its path.
In many cases the compiler will statically know something about the dependent return type, but in your example it doesn't. I'll try to explain why in a second, but first consider the following simpler example:
scala> trait Foo { type A; def a: A }
defined trait Foo
scala> def fooA(foo: Foo): foo.A = foo.a
fooA: (foo: Foo)foo.A
scala> fooA(new Foo { type A = String; def a = "I'm a StringFoo" })
res0: String = I'm a StringFoo
Here the inferred type of res0 is String, since the compiler statically knows that the A of the foo argument is String. We can't write either of the following, though:
scala> def fooA(foo: Foo): String = foo.a
<console>:12: error: type mismatch;
found : foo.A
required: String
def fooA(foo: Foo): String = foo.a
^
scala> def fooA(foo: Foo) = foo.a.substring
<console>:12: error: value substring is not a member of foo.A
def fooA(foo: Foo) = foo.a.substring
^
Because here the compiler doesn't statically know that foo.A is String.
Here's a more complex example:
sealed trait Baz {
type A
type B
def b: B
}
object Baz {
def makeBaz[T](t: T): Baz { type A = T; type B = T } = new Baz {
type A = T
type B = T
def b = t
}
}
Now we know that it's not possible to create a Baz with different types for A and B, but the compiler doesn't, so it won't accept the following:
scala> def bazB(baz: Baz { type A = String }): String = baz.b
<console>:13: error: type mismatch;
found : baz.B
required: String
def bazB(baz: Baz { type A = String }): String = baz.b
^
This is exactly what you're seeing. If we look at the code in shapeless.ops.hlist, we can convince ourselves that the LeftFolder we're creating here will have the same type for In and Out, but the compiler can't (or rather won't—it's a design decision) follow us in this reasoning, which means it won't let us treat l.Out as a tuple without more evidence.
Fortunately that evidence is pretty easy to provide thanks to LeftFolder.Aux, which is just an alias for LeftFolder with the Out type member as a fourth type parameter:
def combine[A <: HList](columns: A, suffix: String, separator: String = " and ")(
implicit l: LeftFolder.Aux[
A,
(String, String, String),
columnCombinator.type,
(String, String, String)
]
): String =
columns.foldLeft((suffix, separator, ""))(columnCombinator)._3
(You could also use the type member syntax with plain old LeftFolder in l's type, but that would make this signature even messier.)
The columns.foldLeft(...)(...) part still returns l.Out, but now the compiler statically knows that that's a tuple of strings.
After having read the complete answer from Travis, here is a little variation of his solution:
type CombineTuple = (String, String, String)
def combine[A <: HList](columns: A, suffix: String, separator: String = " and ")(
implicit l: LeftFolder[
A,
CombineTuple,
columnCombinator.type
]
): String =
columns.foldLeft((suffix, separator, ""))(columnCombinator).asInstanceof[CombineTuple]._3
In this way, the implicit signature is shorter, as it is needed in many methods that call this one.
UPDATED: As Travis has explained in comments, it is bestter to use LeftFolder.Aux.

What is the Scala identifier "implicitly"?

I have seen a function named implicitly used in Scala examples. What is it, and how is it used?
Example here:
scala> sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:8: error: could not find implicit value for evidence parameter of type
Foo[Double]
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.
Also see How to investigate objects/types/etc. from Scala REPL? and Where does Scala look for implicits?
implicitly is avaliable in Scala 2.8 and is defined in Predef as:
def implicitly[T](implicit e: T): T = e
It is commonly used to check if an implicit value of type T is available and return it if such is the case.
Simple example from retronym's presentation:
scala> implicit val a = "test" // define an implicit value of type String
a: java.lang.String = test
scala> val b = implicitly[String] // search for an implicit value of type String and assign it to b
b: String = test
scala> val c = implicitly[Int] // search for an implicit value of type Int and assign it to c
<console>:6: error: could not find implicit value for parameter e: Int
val c = implicitly[Int]
^
Here are a few reasons to use the delightfully simple method implicitly.
To understand/troubleshoot Implicit Views
An Implicit View can be triggered when the prefix of a selection (consider for example, the.prefix.selection(args) does not contain a member selection that is applicable to args (even after trying to convert args with Implicit Views). In this case, the compiler looks for implicit members, locally defined in the current or enclosing scopes, inherited, or imported, that are either Functions from the type of that the.prefix to a type with selection defined, or equivalent implicit methods.
scala> 1.min(2) // Int doesn't have min defined, where did that come from?
res21: Int = 1
scala> implicitly[Int => { def min(i: Int): Any }]
res22: (Int) => AnyRef{def min(i: Int): Any} = <function1>
scala> res22(1) //
res23: AnyRef{def min(i: Int): Int} = 1
scala> .getClass
res24: java.lang.Class[_] = class scala.runtime.RichInt
Implicit Views can also be triggered when an expression does not conform to the Expected Type, as below:
scala> 1: scala.runtime.RichInt
res25: scala.runtime.RichInt = 1
Here the compiler looks for this function:
scala> implicitly[Int => scala.runtime.RichInt]
res26: (Int) => scala.runtime.RichInt = <function1>
Accessing an Implicit Parameter Introduced by a Context Bound
Implicit parameters are arguably a more important feature of Scala than Implicit Views. They support the type class pattern. The standard library uses this in a few places -- see scala.Ordering and how it is used in SeqLike#sorted. Implicit Parameters are also used to pass Array manifests, and CanBuildFrom instances.
Scala 2.8 allows a shorthand syntax for implicit parameters, called Context Bounds. Briefly, a method with a type parameter A that requires an implicit parameter of type M[A]:
def foo[A](implicit ma: M[A])
can be rewritten as:
def foo[A: M]
But what's the point of passing the implicit parameter but not naming it? How can this be useful when implementing the method foo?
Often, the implicit parameter need not be referred to directly, it will be tunneled through as an implicit argument to another method that is called. If it is needed, you can still retain the terse method signature with the Context Bound, and call implicitly to materialize the value:
def foo[A: M] = {
val ma = implicitly[M[A]]
}
Passing a subset of implicit parameters explicitly
Suppose you are calling a method that pretty prints a person, using a type class based approach:
trait Show[T] { def show(t: T): String }
object Show {
implicit def IntShow: Show[Int] = new Show[Int] { def show(i: Int) = i.toString }
implicit def StringShow: Show[String] = new Show[String] { def show(s: String) = s }
def ShoutyStringShow: Show[String] = new Show[String] { def show(s: String) = s.toUpperCase }
}
case class Person(name: String, age: Int)
object Person {
implicit def PersonShow(implicit si: Show[Int], ss: Show[String]): Show[Person] = new Show[Person] {
def show(p: Person) = "Person(name=" + ss.show(p.name) + ", age=" + si.show(p.age) + ")"
}
}
val p = Person("bob", 25)
implicitly[Show[Person]].show(p)
What if we want to change the way that the name is output? We can explicitly call PersonShow, explicitly pass an alternative Show[String], but we want the compiler to pass the Show[Int].
Person.PersonShow(si = implicitly, ss = Show.ShoutyStringShow).show(p)
Starting Scala 3 implicitly has been replaced with improved summon which has the advantage of being able to return a more precise type than asked for
The summon method corresponds to implicitly in Scala 2. It is
precisely the same as the the method in Shapeless. The difference
between summon (or the) and implicitly is that summon can return a
more precise type than the type that was asked for.
For example given the following type
trait F[In]:
type Out
def f(v: Int): Out
given F[Int] with
type Out = String
def f(v: Int): String = v.toString
implicitly method would summon a term with erased type member Out
scala> implicitly[F[Int]]
val res5: F[Int] = given_F_Int$#7d0e5fbb
scala> implicitly[res5.Out =:= String]
1 |implicitly[res5.Out =:= String]
| ^
| Cannot prove that res5.Out =:= String.
scala> val x: res5.Out = ""
1 |val x: res5.Out = ""
| ^^
| Found: ("" : String)
| Required: res5.Out
In order to recover the type member we would have to refer to it explicitly which defeats the purpose of having the type member instead of type parameter
scala> implicitly[F[Int] { type Out = String }]
val res6: F[Int]{Out = String} = given_F_Int$#7d0e5fbb
scala> implicitly[res6.Out =:= String]
val res7: res6.Out =:= String = generalized constraint
However summon defined as
def summon[T](using inline x: T): x.type = x
does not suffer from this problem
scala> summon[F[Int]]
val res8: given_F_Int.type = given_F_Int$#7d0e5fbb
scala> summon[res8.Out =:= String]
val res9: String =:= String = generalized constraint
scala> val x: res8.Out = ""
val x: res8.Out = ""
where we see type member type Out = String did not get erased even though we only asked for F[Int] and not F[Int] { type Out = String }. This can prove particularly relevant when chaining dependently typed functions:
The type summoned by implicitly has no Out type member. For this
reason, we should avoid implicitly when working with dependently typed
functions.
A "teach you to fish" answer is to use the alphabetic member index currently available in the Scaladoc nightlies. The letters (and the #, for non-alphabetic names) at the top of the package / class pane are links to the index for member names beginning with that letter (across all classes). If you choose I, e.g., you'll find the implicitly entry with one occurrence, in Predef, which you can visit from the link there.