I have
trait Foo:
def foo: Int
trait Bar:
def bar: Int
given Foo with
def foo = 1
given Bar with
def bar = 1
And I have a function foobar
type FooBar = Foo & Bar
def foobar(using FooBar) = ...
What is the simplest way to create given for A & B
type if I already have given A and given B
CodePudding user response:
You could get Foo & Bar
by nesting using
clause in given
instances but once you start to modify the values in FooBar
the results might not be what you expect because a FooBar
is also a Foo
and Bar
and things starts to get recursive:
trait FooBar extends Foo with Bar
given (using f: Foo, b: Bar): FooBar with
def foo = f.foo 1
def bar = b.bar 2
def fooBar(using fb: Foo & Bar) = (fb.foo, fb.bar)
def foo(using f: Foo) = f.foo
def bar(using b: Bar) = b.bar
@main def main() =
println(foo) //2
println(bar) //3
println(fooBar) //(3, 5)
IMO you should avoid subtyping relationship with typeclasses and define FooBar
without extending Foo
and Bar
:
trait FooBar:
def foo: Int
def bar: Int
given (using f: Foo, b: Bar): FooBar with
def foo = f.foo 1
def bar = b.bar 2
CodePudding user response:
Admittedly I have no direct Scala 3 experience, but the simplest solution will boil down to something like:
given aAndB(using a: A, b: B): A & B with {
def foo: Int = a.foo
def bar: Int = b.bar
}
You're effectively gluing together an A and a B and dispatching appropriately.
It's possible that one could implement a macro which dispatches (when there are no collisions) automatically.
AFAICT, this would be the equivalent of the Scala 2:
implicit def aAndB(implicit a: A, b: B) = new A with B {
def foo: Int = a.foo
def bar: Int = b.bar
}