Bounds: A View over your Context…*

Has it ever happened to you that you’re with your colleagues and you feel the need of expressing better parameterizing your methods and classes?

Context bounds

Context bounds allow defining constraints about parameter types inheritance.
For example, let’s suppose the classical inheritance:

```trait Animal
trait Cat extends Animal
trait Dog extends Animal
```

If we want to define a method with an any-kind-of-animal argument, we could define that method as follows:

```def myMethod(animal: Animal): Unit =
println(animal)
```

But, using parameter types, we could also do it this way:

```def myMethod[T<:Animal](animal: T): Unit =
println(animal)
```

With <: notation, we force the type T to be a subtype of Animal.
So now, what’s the benefit of using the second notation instead of using the first one? Let’s free our minds a little bit…

What happens if our method receives a Set[Animal] instead of an Animal?

Well, we have to admit, due to invariance, that a Set[Animal] is not the same as a Set[_<:Animal], and we would have to declare our method using one of the following options:

```def myMethod[T<:Animal](animals: Set[T]): Unit =
animals.foreach(println)

def myMethod(animals: Set[_<:Animal]): Unit =
animals.foreach(println)
```

We can also define constraints so that the expressed type is a supertype of Dog, for example:

```def myType[T>:Dog](animals:Set[T]): Unit =
animals.foreach(println)
myType(Set(new Animal{})) //ok!
```

View bounds

If we don’t need to define inheritance constraints, but we want a way to convert the parameter type to something else, then what we’re looking for are view bounds. Their notation is <%.
For example:

```def myMethod[T<%Double](doubleLikes: Set[T]): Unit=
douleLikes.foreach(d => println(d + 2.0))
```

It means that our method is parameterized by a type T and, in current scope, there must exist a conversion function from T to Double. It’s just syntactic sugar for:

```def myMethod[T](doubleLikes: Set[T])(implicit ev: T => Double): Unit =
douleLikes.foreach(d => println(ev(d) + 2.0))
```

This way, we could invoke our method like this:

```myMethod(Set(1,2,3))//ok
myMethod(Set(true,false))//fail!
<console>:9: error: No implicit view available from Boolean => Double.
myMethod(Set(true,false,true))
^
```

If there is no view for a concrete type, like in this case for Boolean, we can define one:

```implicit def toD(b: Boolean):Double =
if (b) 1.0 else 2.0
myMethod(Set(true,false))//ok
```

And that’s all folks! Easy peasy lemon squeezy 🙂

Peace out.

Anuncios