Here someone says that star is underscore from scala 3, but I've seen some code like this in scala 2.13:
def make[F[_]: ContextShift: MonadError[*[_], Throwable]: Effect: Logging](): ...
Does it have a same meaning and just specify that type in * is not the same as in _?
_denotes (depending on context)Here we want to understand the type constructor.
Type constructor would be (simplifying) that
Fof something, that doesn't yet have that something defined, but we can applyAto it and make it aF[A]. E.g.Listcould be passed asF[_]because it has a gap, if we fill it with e.g.Stringit could becomeList[String]Optioncould be passed asF[_]as well, it has a gap, if we filled it with e.g.Intit would becomeOption[Int]Doublecannot be used asF[_], because it doesn't have a gapTypes with a "gap" are often denoted as
* -> *, while types without them as*. We could read*simply as a type, while* -> *as "type that takes another type to form a type" - or a type constructor.(Higher-kinded types like one just mentioned are complex thing on its own, so it would be better for you to learn about them more outside of that question).
*(from kind projector plugin) is used for kind projection - the syntax is inspired from the notation above to show where type would be passed if we wanted to create a new type:is really like:
except that it works without a type alias.
If it was Dotty, it could be better expressed with a type lambda:
In your example:
F[_]is defined as type constructor - so you cannot pass thereString,IntorByte, but you could pass thereList,FutureorOption(because they take one type parameter)F[_]: ContextShiftis a shortcut for[F[_]](implicit sth: ContextShift[F])- we can see thatContextShifttakes as a parameter something that takes a type parameter on its own (likeF[_])[F[_]: MonadError[*[_], Throwable]could be expanded to: which in turn could be rewritten as or using a type lambdaIt would probably be easier to read if it was written as:
Thing is, that
*would suggest that expected type ismeanwhile kindness of
*should be* -> *instead of*. So this*[_]means "we want to create a new type constructor here by making this thing in place of*a parameter, but we want to denote that this parameter is of kind* -> *instead of*so we'll add
[_]to show the compiler that it is a type constructor.It is quite a lot to absorb, and it should be easier, I can only feel sorry and say that in Dotty it will be clearer.