I think it also could be interesting to take a look on existential types in relation with mathematical concept of natural domain of function definition applied to polymeric/generic method.
In particular - if one have lot of duplicate implicit
arguments in code, one could be interested in newly introduced implicit functions types aka Context Queries (to extract repeating args list into type alias)
Theoretically if one may have similar problem with overcomplicated repeating generic methods definitions one may extract them into existential type.
So for example (formally written based on introduction snippet of this topic), if one have code like
def doSmth0[PKey <: Scoped.ScopingSetting[PKey] with Scoped](key: PKey): Unit = {
println(s"doSmth0: $key")
doSmth1(key)
}
def doSmth1[PKey <: Scoped.ScopingSetting[PKey] with Scoped](key: PKey): Unit = {
println(s"doSmth1: $key")
doSmth2(key)
}
def doSmth2[PKey <: Scoped.ScopingSetting[PKey] with Scoped](key: PKey): Unit = {
println(s"doSmth2: $key")
}
He/she can rewrite it as following (using essentials)
type Key = K forSome { type K <: Scoped.ScopingSetting[K] with Scoped }
def doSmth0(key: Key): Unit = {
println(s"doSmth0: $key")
doSmth1(key)
}
def doSmth1(key: Key): Unit = {
println(s"doSmth1: $key")
doSmth2(key)
}
def doSmth2[PKey <: Scoped.ScopingSetting[PKey] with Scoped](key: PKey): Unit = {
println(s"doSmth2: $key")
}
}
So here theoretically one may significantly reduce boilerplating, if one need only pass that key
of [PKey <: ...]
through multiple methods “transparently” and use that key
“fine grained semantics” only in some very last place.
Basically (in theory) same trick could be made to represent any generic method natural domain of function definition in form of existential type.
So having method like
def doSmth[T1 >: ... <: ... , ... , TN >: ... <: ...](arg1: P1[T1, ... ,TN], argM: PM[T1, ... ,TN]) = ???
One may express its natural domain of function definition like
type DoSmthDomain[T1 >: ... <: ... , ... , TN >: ... <: ...] = (P1[T1, ... ,TN], PM[T1, ... ,TN])
type DoSmthNaturalDomain = DoSmthDomain[T1, ..., TN] forSome {type T1 >: ... <: ... ; ... ; type TN >: ... <: ...}
And this application of forSome
-types looks for me deserving to be supported in some form in upcoming versions of language.
Also in related discussions I could see quite old topic with thoughts that existentiales should gone together with “mandatory generic parameters” (which should be eventually fully replaced with inner abstract types, if I got that correctly).
In that case I could imagine that DoSmthDomain[_, ... , _]
would be somehow expressed fully via abstract types (without generic parameters at all) and then that wildcard would become available just as DoSmthDomain
and we would get that existentiales “for granted” (as I believe was promised in that old topic)
But for now as far as I know one could replace structural holder with abstract types with some parametrised alias, but not wise versa. So it looks like support of such DoSmthDomain[_, ... , _]
still could be useful for now.
Perhaps it could/need to be limited to not participate in further types composition and boundaries - and be only available as a type for defining methods arguments (just to reduce generic methods signatures size in some cases). But I believe that even in such very limited form it still could be quite useful (even knowing that Seq[DoSmthDomain[_, ... , _]]
should be prohibited, as example of types composition)