jangoolie
jangoolie

Reputation: 125

Any with type context bound

Disclaimer: I'm not sure I really understand type context bounds... or anything.

Is it possible to define a type in scala that is an instance of a TypeClass where the type can be Any, so long as that type obeys a type context bound.

For example I have some typeclass Printable[T]

Printable is a typeclass for things that can be printed, and it's useful as a type context bound because I might want to have typeclass that can take any type as long as it's printable, like this:

class SomeContainer[T: Printable](value: T)

From what I understand the collections library uses type context bounds like this for things that can be ordered, summed etc.

But what I want is type PrintableAnyCollection = SomeCollection[_: Printable]

That is a collection of values that can be of different types, as long as all those types all obey to type context bound that there exists a Printable[T] for w/e that type.

TLDR:

Collection[Any] almost does what I want because it can hold different types

Collection[T: Printable] Almost does what I want because it enforces that the things in the collection are printable but has the consequence that the collection stores only the one type.

Collection[_: Printable] and/or Collection[Any: Printable] look like they sort of describe what I want but aren't valid syntax.

Upvotes: 2

Views: 149

Answers (1)

badcook
badcook

Reputation: 3739

You're presumably looking for something like this:

// Doesn't work
Collection[T forSome {type T: Printable}]

This doesn't work though and the reason is because context bounds are just sugar for implicit parameters, which are resolved at compile time. In particular, the above type would imply that the implicit resolutions the compiler did would depend on the runtime value of the above type (each different T would need another implicit resolution). In effect you would create a method whose arity in its implicit parameters list could change at runtime.

Suffice it to say that doesn't play nice with Scala.

An alternative is to proactively bundle the implicit parameter in some sort of wrapper type and parameterize your collection on the wrapper as an existential. Thus implicit resolution occurs before the collection is created. Miles Sabin covers it well here.

To briefly summarize that approach, it looks something like the following:

case class PrintableWrapper[T](unwrap: T)(implicit ev: Printable[T])

Collection[PrintableWrapper[T] forSome {type T}]

Actually using the entries of the collection is cumbersome (a spurious pattern match is required to appease Scala's typechecker). The desugared context bound is also required to have an explicit instance of Printable to actually print the entry. See Miles Sabin's answer for more details.

This happens to be one spot where implicits are a slightly cumbersome way of encoding typeclasses.

Upvotes: 1

Related Questions