-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
export object.given
does not respect priorities
#15264
Comments
Self-contained version object repro:
// analogous to cats Eq, Hash, Order:
class A[V]
class B[V] extends A[V]
class C[V] extends A[V]
// resolve conflicts with prio trick
object context extends prio1:
given[V]: C[V] = new C[V]
class prio1 extends prio2:
given[V]: B[V] = new B[V]
class prio2:
given[V]: A[V] = new A[V]
object exports:
// this will erase prios and fail
export context.given
import repro.A
import repro.exports.given
def test = summon[A[Int]] |
That cannot work. I propose to use a different scheme to encode priority as outlined in tests/run/implied-priority.scala /* New scheme: dummy implicit arguments that indicate priorities
*/
object Priority {
class Low
object Low { given Low() }
class High extends Low
object High { given High() }
}
object Impl2 {
given t1[T](using Priority.Low): E[T]("low")
given t2[T](using Priority.High)(using Arg[T]): E[T]("norm")
}
def test2 = {
import Impl2.given
assert(summon[E[String]].str == "low") // No Arg available, so only t1 applies
{ given Arg[String]()
assert(summon[E[String]].str == "norm") // Arg available, t2 takes priority
}
} |
@odersky that is very cool, and I'm interested in trying to use it. It seems to work in some cases but not others (which I would need): object priority:
// lower number = higher priority
class Prio0 extends Prio1
object Prio0 { given Prio0() }
class Prio1 extends Prio2
object Prio1 { given Prio1() }
class Prio2
object Prio2 { given Prio2() }
object repro:
// analogous to cats Eq, Hash, Order:
class A[V]
class B[V] extends A[V]
class C[V] extends A[V]
class Q[V]
object context:
// prios work here, which is cool
given[V](using priority.Prio0): C[V] = new C[V]
given[V](using priority.Prio1): B[V] = new B[V]
given[V](using priority.Prio2): A[V] = new A[V]
object exports:
// so will these exports
export context.given
// if you import these don't import from 'context' above
object qcontext:
// base defs, like what you would get from cats
given B[Int] = new B[Int]
given C[Int] = new C[Int]
// these seem like they should work but don't
given[V](using p0: priority.Prio0, c: C[V]): C[Q[V]] = new C[Q[V]]
given[V](using p1: priority.Prio1, b: B[V]): B[Q[V]] = new B[Q[V]]
given[V](using p2: priority.Prio2, a: A[V]): A[Q[V]] = new A[Q[V]]
object test1:
import repro.*
import repro.exports.given
// these will work
val a = summon[A[Int]]
object test2:
import repro.*
import repro.qcontext.given
// this one will fail as ambiguous - prios aren't having an effect
val a = summon[A[Q[Int]]] |
It works if you keep the "priority" parameters using separate from the rest. object priority:
// lower number = higher priority
class Prio0 extends Prio1
object Prio0 { given Prio0() }
class Prio1 extends Prio2
object Prio1 { given Prio1() }
class Prio2
object Prio2 { given Prio2() }
object repro:
// analogous to cats Eq, Hash, Order:
class A[V]
class B[V] extends A[V]
class C[V] extends A[V]
class Q[V]
object context:
// prios work here, which is cool
given[V](using priority.Prio0): C[V] = new C[V]
given[V](using priority.Prio1): B[V] = new B[V]
given[V](using priority.Prio2): A[V] = new A[V]
object exports:
// so will these exports
export context.given
// if you import these don't import from 'context' above
object qcontext:
// base defs, like what you would get from cats
given gb: B[Int] = new B[Int]
given gc: C[Int] = new C[Int]
// these seem like they should work but don't
given gcq[V](using p0: priority.Prio0)(using c: C[V]): C[Q[V]] = new C[Q[V]]
given gbq[V](using p1: priority.Prio1)(using b: B[V]): B[Q[V]] = new B[Q[V]]
given gaq[V](using p2: priority.Prio2)(using a: A[V]): A[Q[V]] = new A[Q[V]]
object test1:
import repro.*
import repro.exports.given
// these will work
val a = summon[A[Int]]
object test2:
import repro.*
import repro.qcontext.given
// this one will fail as ambiguous - prios aren't having an effect
val a = summon[A[Q[Int]]] |
@odersky that is very interesting - is that because the first layer of currying is now all the same form/signature, so the priorities dominate the ordering? |
@odersky also it makes me wonder - if this is an effective "general" way to overlay priorities onto implicit resolutions, maybe it would be a useful addition to |
Compiler version
3.1.2
Minimized code
Output
If you just import
context.given
the prio trick works:BUT if you try to
import exports.given
the priority info is lost:Expectation
Ideally, the priority information would be preserved when importing via
exports.given
,so the
given
definitions could be composed using scala 3's newexport
feature.The text was updated successfully, but these errors were encountered: