Here is my proposal to make working with type classes easier, “using the bounded type as if it had a companion object” (better name TBD).

### Currently

So imagine you have the type-class:

```
trait Summable[T]:
def zero: T
extension (x: T)
def + (y: T): T
```

An instance would then look like:

```
given [U]: Summable[List[U]] with
override def zero = List()
extension (x: List[U])
override def + (y: List[U]) = x ++ y
```

Okay, now let’s try to use it to make a `sum`

method:

```
def sum[T : Summable](seq: Seq[T]) =
seq.fold(???.zero)(_ + _)
```

As you can see, we can’t access `zero`

, it’s not in scope, unlike `+`

.

We can solve this by … not using a context bound:

```
def sum[T](seq: Seq[T])(using ev: Summable[T]) =
seq.fold(ev.zero)(_ + _)
```

Or by cleverly *not using a context bound*:

```
def zero[T](using ev: Summable[T]) = ev.zero
def sum[T : Summable](seq: Seq[T]) =
seq.fold(zero)(_ + _)
```

And it’s hard to be sure visually that that `zero`

is really related to `Summable`

.

This is especially the case since we could have a `val`

named `zero`

, and overloading would pick for us.

As I’ve hopefully demonstrated, the current solution works, but is not very satisfying, adding potentially confusing boilerplate.

### My proposal

Here is my proposal; to be able to access the members defined by case classes by using their argument type as if it was a companion object:

```
def sum[T](seq: Seq[T])(using Summable[T]) =
seq.fold(T.zero)(_ + _)
// or
def sum[T : Summable](seq: Seq[T]) =
seq.fold(T.zero)(_ + _)
```

It is also possible to restrict that feature to only context bounded types.

This avoid cases where the type is not just an identifier, for example:

```
def sum[T](p: Seq[(T,T)])(using Summable[(T,T)]) =
seq.fold((T,T).zero)(_ + _)
```

And the downside is minimal, as if we’re already using a `using`

parameter, we can name it to access it’s fields.

For these reasons, I feel restricting the feature thusly is advisable.

If I remember correctly, it is possible to do `[List[_] : Summable]`

, as I’m not sure what to do in that case, it might be better to forbid that feature on these cases.

### Alternative

It is also possible to automatically create synthetic forwarders like:

```
def zero[T](using ev: Summable[T]) = ev.zero
```

But not having any prefix on the members makes it hard to track where they come from, with the “type as companion object”, we know it has to come from a context bound (or potentially a `using`

).