Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic method with `cannot resolve symbol` errors in Scala

Tags:

generics

scala

I need to get a generic check method that can be used as follows:

check[Int](10, 1, 5) and check[Double](10.0, 1.0, 5.0).

I tried this code:

trait RangeChecker {
  def check[T <: AnyVal](value:T, mini:T, maxi:T) : Boolean = {
    (value >= mini && value <= maxi)
  }
}

However, I get Cannot resolve symbol errors for >=, && and <=. What might be wrong?

enter image description here

like image 312
prosseek Avatar asked Aug 11 '14 17:08

prosseek


3 Answers

When you write

def check[T <: AnyVal] ...

you're defining the method for all the subtypes of AnyVal. However, your implementation uses two methods (<= and >=) which are available only for a subset of types, namely the ones that support ordering.

So you have to specify that the method applies to all types for which an ordering exists, or in other words

def check[T](value: T, min: T, max: T)(implicit ev: T => Ordered[T]): Boolean =
  value >= min && value <= max

This syntax is equivalent to a view bound (<%)

def check[T <% Ordered[T]](value: T, min: T, max: T): Boolean = ...

but, since view bounds are deprecated, you should avoid it.


Another option is to use Ordering in this fashion

def check[T](value: T, mini: T, maxi: T)(implicit ord: Ordering[T]): Boolean = {
  import ord.mkOrderingOps
  value >= mini && value <= maxi
}

where importing ord.mkOrderingOps gives you the ability of using the regular >= and <= methods.

Another equivalent alternative using a context bound directly:

def check[T: Ordering](value: T, mini: T, maxi: T): Boolean = {
  val ord = implicitly[Ordering[T]]
  import ord.mkOrderingOps
  value >= mini && value <= maxi
}
like image 99
Gabriele Petronella Avatar answered Oct 23 '22 17:10

Gabriele Petronella


Try the following:

def check[T <% Ordered[T]](value: T, mini: T, maxi: T): Boolean = {
    (value >= mini && value <= maxi)
  }

The <= and >= operators are defined as part of the Ordered trait, not AnyVal.

EDIT: see the scala API docs here and here

EDIT2: Replaced <: with <%

like image 34
ffxtian Avatar answered Oct 23 '22 18:10

ffxtian


AnyVals are not required to support operations like >=. That's why it won't work like you tried. Unfortunately, there is no superclass of all the orderable AnyVals.

You should use Ordering instead:

def check[T](value: T, low: T, high: T)(implicit ord: Ordering[T]): Boolean = {
  ord.gteq(value, low) && ord.lteq(value, high)
}

You often won't need to define the type T explicitly when you call it, either:

scala> check(1, 2, 3)
res0: Boolean = false
scala> check(3, 2, 3.5)
res1: Boolean = true
like image 26
Dan Getz Avatar answered Oct 23 '22 17:10

Dan Getz