10

I have two functions (not these have been edited since the original -- some of the answers below are responding to the original ones which returned a sequence of ()):

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (List(a, b) <- ls sliding 2) yield a

def foo2[A](ls: Iterable[A]) : Iterator[A] =
    for (a::b::Nil <- ls sliding 2) yield a

which I naively thought were the same. But Scala gives this waning only for the first one:

warning: non variable type-argument A in type pattern List[A]
is unchecked since it is eliminated by erasure

I think I understand why it gives that error for the first one: Scala thinks that I'm trying to use the type as a condition on the pattern, ie a match against List[B](_, _) should fail if B does not inherit from A, except that this can't happen because the type is erased in both cases.

So two questions:

1) Why does the second one not give the same warning?

2) Is it possible to convince Scala that the type is actually known at compile time, and thus can't possibly fail to match?

edit: I think this answers my first question. But I'm still curious about the second one.

edit: agilesteel mentioned in a comment that

for (List(a, b) <- List(1,2,3,4) sliding 2) yield ()

produces no warning. How is that different from foo1 (shouldn't the [Int] parameter be erased just the same as the [A] parameter is)?

Community
  • 1
  • 1
Owen
  • 38,836
  • 14
  • 95
  • 125

2 Answers2

4

I'm not sure what is happening here, but the static type of Iterable[A].sliding is Iterator[Iterable[A]], not Iterator[List[A]] which would be the static type of List[A].sliding.

You can try receiving Seq instead of Iterable, and that work too. EDIT Contrary to what I previously claimed, both Iterable and Seq are co-variant, so I don't know what's different. END EDIT The definition of sliding is pretty weird too:

def sliding [B >: A] (size: Int): Iterator[Iterable[A]]

See how it requires a B, superclass of A, that never gets used? Contrast that with an Iterator.sliding, for which there's no problem:

def sliding [B >: A] (size: Int, step: Int = 1): GroupedIterator[B]

Anyway, on to the second case:

for (a::b::Nil <- ls sliding 2) yield a

Here you are decomposing the list twice, and for each decomposition the type of head is checked against A. Since the type of head is not erased, you don't have a problem. This is also mostly a guess.

Finally, if you turn ls into a List, you won't have a problem. Short of that, I don't think there's anything you can do. Otherwise, you can also write this:

def foo1[A](ls: Iterable[A]) : Iterator[A] =
    for (Seq(a, b) <- ls.iterator sliding 2) yield a
Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • Wow, Scala is complicated! (Or rather, I am very unfamiliar with its complications). I would have thought `Iterable` would be covariant. – Owen Aug 22 '11 at 22:03
  • @Owen Scala has depth, but, mostly, you can choose to stay on shallow waters. `Iterable` cannot be co-variant because `Set` is not co-variant, nor is `Map`. And, in fact, you'd arbitrarily limit what can be an `Iterable` by making it co-variant. – Daniel C. Sobral Aug 24 '11 at 14:55
  • The current docs (I can't figure out what version is "current" though) say Iterable is covariant: http://www.scala-lang.org/api/current/scala/collection/Iterable.html – Owen Aug 24 '11 at 21:12
  • @Owen You are right. I'll edit out that portion of my answer, since it is obviously in error. I'm still at loss as to why as soon as you cross from `Iterable` to `Seq` things start working. – Daniel C. Sobral Aug 25 '11 at 12:10
2

1) The second one does not produce a warning probably because you are constructing the list (or the pattern) by prepending elements to the Nil object, which extends List parameterising it with Nothing. And since everything is Nothing, there is nothing to be worried about ;) But I'm not sure, really guessing here.

2) Why don't you just use:

def foo[A](ls: Iterable[A]) =
    for (list <- ls sliding 2) yield ()
agilesteel
  • 16,775
  • 6
  • 44
  • 55
  • (2): Sorry I wasn't actually trying to make a list of all () -- I took out the actual body of the loop so it wouldn't distract. Guess that backfired ;) – Owen Aug 22 '11 at 20:09
  • (1): I'm very new to Scala, so I didn't know enough to say if that's correct or not, but I tried specifying a return type and the warnings remain the same. I'll edit my question to show. – Owen Aug 22 '11 at 20:42