4

Apparently Range has a method that checks if it contains a value of type Any. I understand that it is from SeqLike, but causes some problems.

For instance, i was matching hours from joda.DateTime:

DateTime.now match {
    case d if 0 to 12 contains d.hourOfDay() => ...

Here d.hourOfDay() returns DateTime.Property, not Int, but code still compiles, because of contains(elem: Any). Is there any way to check for such calls at compile time?

F0RR
  • 1,590
  • 4
  • 16
  • 30

3 Answers3

7

You can use Scalaz's typesafe equals (===) in conjunction with exists method on TraversableOnce.

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> 1 to 5 exists { _ === 2 }
res1: Boolean = true

scala> 1 to 5 exists { _ === "Hullo" }
<console>:14: error: type mismatch;
 found   : java.lang.String("Hullo")
 required: Int
       1 to 5 exists { _ === "Hullo" }
                             ^
missingfaktor
  • 90,905
  • 62
  • 285
  • 365
6

You can pimp Range to add a type-safer contains method:

class SafeRange( range: Range ) {
  def safeContains( i: Int ) = range contains i
}

object SafeRange {
  implicit def safer( range: Range ) = new SafeRange( range )
}

Import the implicit and call safeContains on any range instance:

scala> import SafeRange._
import SafeRange._

scala> (0 until 10) safeContains 3
res2: Boolean = true

scala> (0 until 10) safeContains 100
res3: Boolean = false

scala> (0 until 10) safeContains "foo"
<console>:18: error: type mismatch;
 found   : java.lang.String("foo")
 required: Int
          (0 until 10) safeContains
paradigmatic
  • 40,153
  • 18
  • 88
  • 147
3

Based on the scaladocs for Range it looks like there's not a better Range method you could use. Your options seem to be

Use an explicit type signature:

 case d if 0 to 12 contains (d.hourOfDay(): Int) => ...

Make your own method:

 def containsInt(r: Range, i: Int) = ...

This seems to be a holdover from Java equals being pre-generics, and is only one of the inconveniences this fact causes for Scala.

Owen
  • 38,836
  • 14
  • 95
  • 125
  • 1
    Yeah... But maybe there should be some sort of compiler warning for calls to such methods. It seems wrong to have such runtime errors in a type-safe language. – F0RR Sep 12 '11 at 08:09
  • I would love to have a plugin that generates more/better warnings. Is there such a thing? – ziggystar Sep 12 '11 at 09:06
  • @ziggystar I'm not aware of one. I'm not sure how the compiler could even tell this isn't what you want, short of deprecating the method (which might be the right solution, but it has other problems...) – Owen Sep 12 '11 at 09:14
  • @Owen There are other situations where I am unhappy with the std lib because it makes it easy to make a mistake. See http://stackoverflow.com/questions/7040806/when-applying-map-to-a-set-you-sometimes-want-the-result-not-to-be-a-set-but – ziggystar Sep 12 '11 at 10:12