Paul Phillips | 10 Feb 23:07

scare-quoted "type-safe" contains method for covariant collections

class MyCovariantCollection[+T, +CC[X] <: Seq[X]](xs: CC[T]) {
  // Oops, our "evidence" seems to be useless, as what we want
  // to know is that T1 <:< T, but of course we can't do that because
  // of the variance position.
  def contains[T1](x: T1)(implicit ev: T <:< T1): Boolean = xs contains x
}

// But wait! Unspecified implementation vagaries to the rescue!
object Test extends App {
  val xs = new MyCovariantCollection(List(1, 2, 3))
  assert(xs contains "abc", "I'm sure it's in there somewhere")
}

// Thank-you type inference algorithm! Pick the most specific
// type while resolving the first parameter list without regard
// for the fact that we are doomed once you see the second
// parameter list.  That's what we want today.
% scalac ./covariance-contains.scala 
./covariance-contains.scala:11: error: Cannot prove that Int <:< java.lang.String.
  assert(xs contains "abc", "I'm sure it's in there somewhere")
            ^
one error found

/*
Yes, of course this works:

  xs.contains[Any]("abc")

I don't know about you guys but people going that far out of their way
to look for Strings in a list of Ints is not my most pressing concern.
*/

Daniel Sobral | 11 Feb 00:49
Picon
Gravatar

Re: scare-quoted "type-safe" contains method for covariant collections

There's a lot of merit on this just in the decreased noise level from
the detractors. Granted, they'll pick up on something else if they are
bull-headed enough, but _some_ of them are bound not to be bull-headed
enough! :-)

On Fri, Feb 10, 2012 at 20:07, Paul Phillips <paulp <at> improving.org> wrote:
> class MyCovariantCollection[+T, +CC[X] <: Seq[X]](xs: CC[T]) {
>   // Oops, our "evidence" seems to be useless, as what we want
>   // to know is that T1 <:< T, but of course we can't do that because
>   // of the variance position.
>   def contains[T1](x: T1)(implicit ev: T <:< T1): Boolean = xs contains x
> }
>
> // But wait! Unspecified implementation vagaries to the rescue!
> object Test extends App {
>   val xs = new MyCovariantCollection(List(1, 2, 3))
>   assert(xs contains "abc", "I'm sure it's in there somewhere")
> }
>
> // Thank-you type inference algorithm! Pick the most specific
> // type while resolving the first parameter list without regard
> // for the fact that we are doomed once you see the second
> // parameter list.  That's what we want today.
> % scalac ./covariance-contains.scala
> ./covariance-contains.scala:11: error: Cannot prove that Int <:<
> java.lang.String.
>   assert(xs contains "abc", "I'm sure it's in there somewhere")
>             ^
> one error found
>
> /*
> Yes, of course this works:
>
>   xs.contains[Any]("abc")
>
> I don't know about you guys but people going that far out of their way
> to look for Strings in a list of Ints is not my most pressing concern.
> */
>

--

-- 
Daniel C. Sobral

I travel to the future all the time.

Miles Sabin | 11 Feb 10:28
Gravatar

Re: scare-quoted "type-safe" contains method for covariant collections

On Fri, Feb 10, 2012 at 10:07 PM, Paul Phillips <paulp <at> improving.org> wrote:
> class MyCovariantCollection[+T, +CC[X] <: Seq[X]](xs: CC[T]) {
>   // Oops, our "evidence" seems to be useless, as what we want
>   // to know is that T1 <:< T, but of course we can't do that because
>   // of the variance position.
>   def contains[T1](x: T1)(implicit ev: T <:< T1): Boolean = xs contains x
> }
>
> // But wait! Unspecified implementation vagaries to the rescue!
> object Test extends App {
>   val xs = new MyCovariantCollection(List(1, 2, 3))
>   assert(xs contains "abc", "I'm sure it's in there somewhere")
> }
>
> // Thank-you type inference algorithm! Pick the most specific
> // type while resolving the first parameter list without regard
> // for the fact that we are doomed once you see the second
> // parameter list.  That's what we want today.
> % scalac ./covariance-contains.scala
> ./covariance-contains.scala:11: error: Cannot prove that Int <:<
> java.lang.String.
>   assert(xs contains "abc", "I'm sure it's in there somewhere")
>             ^
> one error found
>
> /*
> Yes, of course this works:
>
>   xs.contains[Any]("abc")
>
> I don't know about you guys but people going that far out of their way
> to look for Strings in a list of Ints is not my most pressing concern.
> */

Maybe I'm being a bit dim, but why is this preferable to just pimping
away the variance altogether?

scala> :paste
// Entering paste mode (ctrl-D to finish)

class InvariantContains[T, CC[X] <: Seq[X]](xs: CC[T]) {
  def invarContains(x : T) : Boolean = xs contains x
}

// Exiting paste mode, now interpreting.

defined class InvariantContains

scala> implicit def invar[T, CC[X] <: Seq[X]](xs: CC[T]) = new
InvariantContains(xs)
invar: [T, CC[X] <: Seq[X]](xs: CC[T])InvariantContains[T,CC]

scala> List(1, 2, 3) invarContains "foo"
<console>:10: error: type mismatch;
 found   : java.lang.String("foo")
 required: Int
              List(1, 2, 3) invarContains "foo"
                                          ^
Cheers,

Miles

--

-- 
Miles Sabin
tel: +44 7813 944 528
gtalk: miles <at> milessabin.com
skype: milessabin
g+: http://www.milessabin.com
http://twitter.com/milessabin
http://www.chuusai.com/

Paul Phillips | 11 Feb 15:52

Re: scare-quoted "type-safe" contains method for covariant collections



On Sat, Feb 11, 2012 at 1:28 AM, Miles Sabin <miles <at> milessabin.com> wrote:
Maybe I'm being a bit dim, but why is this preferable to just pimping
away the variance altogether?

It's interesting because it's possible to do it without an intermediate structure (which is surprising) not because it's appealing.

That said, it might be cheaper (but I'm not sure.)

Miles Sabin | 11 Feb 16:38
Gravatar

Re: scare-quoted "type-safe" contains method for covariant collections

On Sat, Feb 11, 2012 at 2:52 PM, Paul Phillips <paulp <at> improving.org> wrote:
> On Sat, Feb 11, 2012 at 1:28 AM, Miles Sabin <miles <at> milessabin.com> wrote:
>>
>> Maybe I'm being a bit dim, but why is this preferable to just pimping
>> away the variance altogether?
>
>
> It's interesting because it's possible to do it without an intermediate
> structure (which is surprising) not because it's appealing.

Oh, so the idea would be to replace the existing definition of
contains with your one with the type constraint, rather than use that
MyConvariantCollection type (which looks a lot like an intermediate
structure to me)? In which case my only quibble would be that using
=:= rather than <:< would have the same effect and be a bit more
transparent.

Cheers,

Miles

--

-- 
Miles Sabin
tel: +44 7813 944 528
gtalk: miles <at> milessabin.com
skype: milessabin
g+: http://www.milessabin.com
http://twitter.com/milessabin
http://www.chuusai.com/

Paul Phillips | 11 Feb 17:35

Re: scare-quoted "type-safe" contains method for covariant collections



On Sat, Feb 11, 2012 at 7:38 AM, Miles Sabin <miles <at> milessabin.com> wrote:
In which case my only quibble would be that using
=:= rather than <:< would have the same effect and be a bit more
transparent.

You can't, for the same reason you can't reverse the operands.  (Except instead of "covariant type in contravariant position" you have "covariant type in invariant position".)
Paul Phillips | 11 Feb 17:36

Re: scare-quoted "type-safe" contains method for covariant collections



On Sat, Feb 11, 2012 at 7:38 AM, Miles Sabin <miles <at> milessabin.com> wrote:
rather than use that
MyConvariantCollection type (which looks a lot like an intermediate
structure to me)?

Yes, "MyCovariantCollection" was supposed to be read as "List".
Chris Marshall | 11 Feb 19:21
Picon
Gravatar

Re: scare-quoted "type-safe" contains method for covariant collections

What will the value of the implicit parameter be? Won't it be a new instance of an identity function?

Chris

On 11 Feb 2012, at 14:52, Paul Phillips <paulp <at> improving.org> wrote:



On Sat, Feb 11, 2012 at 1:28 AM, Miles Sabin <miles <at> milessabin.com> wrote:
Maybe I'm being a bit dim, but why is this preferable to just pimping
away the variance altogether?

It's interesting because it's possible to do it without an intermediate structure (which is surprising) not because it's appealing.

That said, it might be cheaper (but I'm not sure.)

Paul Phillips | 11 Feb 19:28

Re: scare-quoted "type-safe" contains method for covariant collections



On Sat, Feb 11, 2012 at 10:21 AM, Chris Marshall <oxbowlakes <at> gmail.com> wrote:
What will the value of the implicit parameter be? Won't it be a new instance of an identity function?

There is only one instance.

  private[this] final val singleton_<:< = new <:<[Any,Any] { def apply(x: Any): Any = x }
  implicit def conforms[A]: A <:< A = singleton_<:<.asInstanceOf[A <:< A]


Gmane