This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Re: about method ::

24 replies
dcsobral
Joined: 2009-04-23,
User offline. Last seen 38 weeks 5 days ago.
First of all, ":+" (which exists, by the way) and "::" have a very important distinction, which is that the former does not end in ":", and the latter does.  Besides that, what do you intend to gain with such a method?
On Thu, Feb 3, 2011 at 09:04, SkyTiger <darktemplarster@gmail.com> wrote:
Dear all,
        I recently read the source code of Scala. I Found one doubt
about the method :: which defined in List[+A].
        The singnature of this method is   def ::[B >: A](x : B) :
List[B]=....,   that is ok.
        But i think such method can also work,we can give is another
name for name collision :
                                                            def :+[B
<: A](x : B) : List[A]=.....
        Or, if i really have a instance of B, which is the subclass
of A. So i can call :+ method and return a new List[A], all looks
fine.
        But why not such method does exist?

Regards



--
Daniel C. Sobral

I travel to the future all the time.
ichoran
Joined: 2009-08-14,
User offline. Last seen 2 years 3 weeks ago.
Re: about method ::
Type inference generally works by starting with the most restrictive type and working to the least restrictive.  Having :: typed the way it is allows you to do stuff like 1 :: Nil, where Nil is typed as List[Nothing].  With your operation, you could only place items in the list that were already okay in the initial list--so you'd have to do things like (Nil: List[Int]) :+ 1.  Awkward!

  --Rex

On Thu, Feb 3, 2011 at 6:04 AM, SkyTiger <darktemplarster@gmail.com> wrote:
Dear all,
        I recently read the source code of Scala. I Found one doubt
about the method :: which defined in List[+A].
        The singnature of this method is   def ::[B >: A](x : B) :
List[B]=....,   that is ok.
        But i think such method can also work,we can give is another
name for name collision :
                                                            def :+[B
<: A](x : B) : List[A]=.....
        Or, if i really have a instance of B, which is the subclass
of A. So i can call :+ method and return a new List[A], all looks
fine.
        But why not such method does exist?

Regards

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Transitivity of <:
Hi, list.
I feel extremely stupid right now, the reason being:
scala> def f[A, B, C >: A <: B] = implicitly[A <:< B]<console>:7: error: Cannot prove that A <:< B.       def f[A, B, C >: A <: B] = implicitly[A <:< B]                                            ^A <: C and C <: B, therefore A <: B, right?
Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Transitivity of <:

On Wed, Apr 6, 2011 at 2:24 PM, Mikhail Vorozhtsov
wrote:
> Hi, list.
> I feel extremely stupid right now, the reason being:
> scala> def f[A, B, C >: A <: B] = implicitly[A <:< B]
> :7: error: Cannot prove that A <:< B.
>        def f[A, B, C >: A <: B] = implicitly[A <:< B]
>                                             ^
> A <: C and C <: B, therefore A <: B, right?

You have to connect the dots yourself. Predef.<:< isn't composable
[1], but you can try to sidestep this with a cast.

scala> def trans[A, B, C](implicit ab: A <:< B, bc: B <:< C) =
| ab.asInstanceOf[A <:< C]
trans: [A,B,C](implicit ab: <:<[A,B],implicit bc: <:<[B,C])<:<[A,C]

scala> def f[A, B, C >: A <: B] = trans[A, C, B]
f: [A,B,C >: A <: B]=> <:<[A,B]

If you try to make `trans` itself you get a diverging implicit
failure. Maybe if this were defined as a low-priority implicit,
relative to Predef.conforms, you could avoid the divergence, but it
seems a stretch to think the type checker will cross the chasm.

BTW, Scalaz provides a composable alternative to <:<, scalaz.Liskov
[2] (It's close cousin, scalaz.Leibniz might also be of interest [3])

E:\tools\scala-2.9.0.RC1\bin>scala
Welcome to Scala version 2.9.0.RC1 (Java HotSpot(TM) Client VM, Java 1.6.0_21).
Type in expressions to have them evaluated.
Type :help for more information.

scala> :cp E:\code\scalaz-core_2.9.0.RC1-6.0-SNAPSHOT.jar
Added 'E:\code\scalaz-core_2.9.0.RC1-6.0-SNAPSHOT.jar'. Your new classpath is:
".;E:\code\scalaz-core_2.9.0.RC1-6.0-SNAPSHOT.jar"

scala> import scalaz._, Liskov._
import scalaz._
import Liskov._

scala> def f[A, B, C >: A <: B] =
| implicitly[A <~< C] andThen implicitly[C <~< B]
f: [A,B,C >: A <: B]=> scalaz.Liskov[A,B]

-jason

[1] http://lampsvn.epfl.ch/trac/scala/ticket/4040
[2] https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/...
[3] https://github.com/scalaz/scalaz/blob/master/core/src/main/scala/scalaz/...

Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Transitivity of <:

On Wed, Apr 6, 2011 at 3:05 PM, Jason Zaugg wrote:
> If you try to make `trans` itself you get a diverging implicit
> failure.

`trans` itself *implicit* ...

-jason

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:
That's not the point here. Let me rephrase:
scala> def g[A, B >: A] {}g: [A,B >: A]=> Unit
scala> def f[A, B, C >: A <: B] = g[A, B]<console>:8: error: type arguments [A,B] do not conform to method g's type parameter bounds [A,B >: A]       def f[A, B, C >: A <: B] = g[A, B]                                   ^
The problem is that the "obvious" A <: B could not be inferred.
Ben Hutchison 3
Joined: 2009-11-02,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

You have a point. The inference appears possible logically.

In practice, Scala's inferencer has all sorts of limitations you
encounter while coding, this being an example. Further, it behavior is
not specified in the Scala spec, so you largely have to accept what
you get.

The upside of this is that it allows the inferencer to improve and
evolve with a minimum of overhead.

-Ben

On Wed, Apr 6, 2011 at 11:18 PM, Mikhail Vorozhtsov
wrote:
> That's not the point here. Let me rephrase:
> scala> def g[A, B >: A] {}
> g: [A,B >: A]=> Unit
> scala> def f[A, B, C >: A <: B] = g[A, B]
> :8: error: type arguments [A,B] do not conform to method g's type
> parameter bounds [A,B >: A]
>        def f[A, B, C >: A <: B] = g[A, B]
>                                    ^
> The problem is that the "obvious" A <: B could not be inferred.

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:
On Wednesday, April 6, 2011 8:51:47 PM UTC+7, Ben Hutchison wrote:
You have a point. The inference appears possible logically.
Moreover, it is explicitly written in the program:def f[A, B, C >: A <: B]
So the compiler doesn't really need to "infer", just "use" it.
Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

The problem is that your bound is on C and not on A. This works:
def f[A <: B, B, C >: A] = implicitly[A <:< B]

On Wed, Apr 6, 2011 at 10:11 AM, Mikhail Vorozhtsov
wrote:
> On Wednesday, April 6, 2011 8:51:47 PM UTC+7, Ben Hutchison wrote:
>>
>> You have a point. The inference appears possible logically.
>
> Moreover, it is explicitly written in the program:
> def f[A, B, C >: A <: B]
> So the compiler doesn't really need to "infer", just "use" it.

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

I know. I'm just pointing out that transitivity makes it possible to read the bound on C as a bound on A and it looks/feels quite natural.And having it would be actually useful. For example, you could express "Upper bound of X and Y", where X is a parameter and Y is a "real" type:trait RealTypeclass My[A] {  // You can't write that  def f[B >: A, B >: RealType]  // But you could write that and compiler would figure out that B >: RealType  def f[B >: A, C >: RealType <: B] }

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:
On Wednesday, April 6, 2011 10:16:03 PM UTC+7, Lex wrote:
You can already express "Upper bound of X and Y" in a much cleaner
fashion. For example:
def foo[A, B >: A with Int] {}
That's not the same thing.B >: A and B >: Int implies B >: (A with Int)But B >: (A with Int) does not imply B >: A and B >: IntConsider B = (A with Int):scala> implicitly[A <:< (A with Int)]<console>:9: error: Cannot prove that A <:< A with Int.       implicitly[A <:< (A with Int)]                 ^
Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

You can already express "Upper bound of X and Y" in a much cleaner
fashion. For example:
def foo[A, B >: A with Int] {}

On Wed, Apr 6, 2011 at 10:51 AM, Mikhail Vorozhtsov
wrote:
> I know. I'm just pointing out that transitivity makes it possible to read
> the bound on C as a bound on A and it looks/feels quite natural.
> And having it would be actually useful. For example, you could express
> "Upper bound of X and Y", where X is a parameter and Y is a "real" type:
> trait RealType
> class My[A] {
>   // You can't write that
>   def f[B >: A, B >: RealType]
>   // But you could write that and compiler would figure out that B >:
> RealType
>   def f[B >: A, C >: RealType <: B]
> }

Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

Sorry, I wasnt paying enough attention to what you are trying to achieve.

> // But you could write that and compiler would figure out that B >: RealType
> def f[B >: A, C >: RealType <: B]

This wont compile, because you are forgetting to specify your A
parameter, sot lets start by fixing it:
def f[A, B >: A, C >: RealType <: B] {}

Ok, now all we have to do is distribute the parameter bounds:
def f[A <: B, B >: RealType, C <: B] {}

Its the same amount of typing.

On Wed, Apr 6, 2011 at 11:39 AM, Mikhail Vorozhtsov
wrote:
> On Wednesday, April 6, 2011 10:16:03 PM UTC+7, Lex wrote:
>>
>> You can already express "Upper bound of X and Y" in a much cleaner
>> fashion. For example:
>> def foo[A, B >: A with Int] {}
>
> That's not the same thing.
> B >: A and B >: Int implies B >: (A with Int)
> But B >: (A with Int) does not imply B >: A and B >: Int
> Consider B = (A with Int):
> scala> implicitly[A <:< (A with Int)]
> :9: error: Cannot prove that A <:< A with Int.
>        implicitly[A <:< (A with Int)]
>                  ^

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

> // But you could write that and compiler would figure out that B >: RealType
>   def f[B >: A, C >: RealType <: B]

This wont compile, because you are forgetting to specify your A
parameter, sot lets start by fixing it:
def f[A, B >: A, C >: RealType <: B] {}

Ok, now all we have to do is distribute the parameter bounds:
def f[A <: B, B >: RealType, C <: B] {}

Its the same amount of typing.

I'm not forgetting about A, it is a class parameter (class My[A]).The point is that you don't always have A being declared in the same parameter list. 
Lex
Joined: 2010-02-28,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

Oh man... two strikes in a row. Alright you have a point.

However I dont think upper bounds work like you expect at all:

object Main {

def main(args: Array[String]) {
val a = new My[RealType]
a.foo("a")
a.foo(1)
a.foo(2.0)
// All valid, but how?
}
}

trait RealType
class My[A] { def foo[B >: A](b: B) { println(b) } }

On Wed, Apr 6, 2011 at 1:08 PM, Mikhail Vorozhtsov
wrote:
>> > // But you could write that and compiler would figure out that B >:
>> > RealType
>> >   def f[B >: A, C >: RealType <: B]
>>
>> This wont compile, because you are forgetting to specify your A
>> parameter, sot lets start by fixing it:
>> def f[A, B >: A, C >: RealType <: B] {}
>>
>> Ok, now all we have to do is distribute the parameter bounds:
>> def f[A <: B, B >: RealType, C <: B] {}
>>
>> Its the same amount of typing.
>
> I'm not forgetting about A, it is a class parameter (class My[A]).
> The point is that you don't always have A being declared in the same
> parameter list.
>

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:
On Thursday, April 7, 2011 5:58:23 AM UTC+7, Lex wrote:

However I dont think upper bounds work like you expect at all:

object Main {

  def main(args: Array[String]) {
    val a = new My[RealType]
    a.foo("a")
    a.foo(1)
    a.foo(2.0)
    // All valid, but how?

B=Any and String/Int/Float <: Any, so they can be passed where B is expected.

  }
}

trait RealType
class My[A] {  def foo[B >: A](b: B) { println(b) } }

My example was very reduced. Let's say you have something like this:
sealed trait OptInput {  type IfNo[U, +T1 <: U, +T2 <: U] <: U  type Unify[LUB <: OptInput, +This <: LUB, +That <: LUB] <: LUB}sealed trait NoInput extends OptInput {  final type IfNo[U, +T1 <: U, +T2 <: U] = T1  final type Unify[LUB <: OptInput, +This <: LUB, +That <: LUB] = That}sealed trait SomeInput[-A] extends OptInput {  final type IfNo[U, +T1 <: U, +T2 <: U] = T2  final type Unify[LUB <: OptInput, +This <: LUB, +That <: LUB] =    That#IfNo[LUB, This, LUB]}
trait Consumer[+I <: OptInput] {  // ok  def >>[I1 >: I <: OptInput, I2 <: I1](f: => Consumer[I2]):        Consumer[I#Unify[I1, I, I2]]  // Rejected because compiler doesn't "see" that SomeInput[E] <: I1  // And yes, I don't want to lose preciseness here (i.e. by using I#Unify[I1, I, I2])  protected def pushBack[E, I1 >: I <: OptInput, I2 >: SomeInput[E] <: I1](input: Stream[E]):                  Consumer[I#Unify[I1, I, SomeInput[E]]]}

Ben Hutchison 3
Joined: 2009-11-02,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

On Wed, Apr 6, 2011 at 11:18 PM, Mikhail Vorozhtsov
wrote:
> That's not the point here. Let me rephrase:
> scala> def g[A, B >: A] {}
> g: [A,B >: A]=> Unit
> scala> def f[A, B, C >: A <: B] = g[A, B]
> :8: error: type arguments [A,B] do not conform to method g's type
> parameter bounds [A,B >: A]
>        def f[A, B, C >: A <: B] = g[A, B]
>                                    ^
> The problem is that the "obvious" A <: B could not be inferred.

Thinking about this some more:

Section 3.5.2 of the Scala Spec states that "The conformance relation
(<:) is ... transitive".

If the <: and >: syntax in the expression f[A, B, C >: A <: B]
denotes a "conformance relation" as per 3.5.2, then yes, I'd say
you've found a bug in the Scala compiler.

If on the other hand, <: and >:, in this context, are "pieces of
syntax for expressing type bounds", then you haven't. The inferencer
has simply not been able to infer the conformance relation from the
provided info, and more explicit type annotations are required.

My money is on the latter interpretation.

-Ben

Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Transitivity of <:

On Thu, Apr 7, 2011 at 9:46 AM, Ben Hutchison wrote:
> Thinking about this some more:
>
> Section 3.5.2 of the Scala Spec states that "The conformance relation
> (<:) is ... transitive".
>
> If the  <: and >: syntax in the expression f[A, B, C >: A <: B]
> denotes a "conformance relation" as per 3.5.2, then yes, I'd say
> you've found a bug in the Scala compiler.
>
> If on the other hand,  <: and >:, in this context, are "pieces of
> syntax for expressing type bounds", then you haven't. The inferencer
> has simply not been able to infer the conformance relation from the
> provided info, and more explicit type annotations are required.

The heart of the inference is in Types#solve [1].

With my "Debugging Scalac in five minutes flat" guide [2], you can see
what's happening.

[1] https://github.com/scala/scala/blob/master/src/compiler/scala/tools/nsc/...
[2] https://gist.github.com/863884

Mikhail Vorozhtsov
Joined: 2011-04-06,
User offline. Last seen 42 years 45 weeks ago.
Re: Transitivity of <:

Yes, I don't think it's a bug. I've filed enhancement ticket.

Ken McDonald
Joined: 2011-02-13,
User offline. Last seen 42 years 45 weeks ago.
Odd problem (to me) with type checking:
I have the following bit of code:
class CustomStyles[R<:Any, T<:StyleValueFetcher[R]] { private val styles = new collection.mutable.HashMap[String, T]()
def marginTop_=(i: Int)  { styles("marginTop") = Fixed(i) }

def marginTop_=(i: StyleValueFetcher[Int]) { styles("marginTop") = i }...}
where
abstract class StyleValueFetcher[R]abstract class NonNumericStyleValueFetcher[R] extends StyleValueFetcher[R]case class Fixed[R](value: R) extends NonNumericStyleValueFetcher[R]
When I try to compile the above code, I get the messages:
[error] /Users/Ken/Documents/Programming/Scala/contextual/src/main/scala/com/digitaldoodles/contextual/style/Style.scala:1265: type mismatch;[error]  found   : com.digitaldoodles.contextual.style.Fixed[Int][error]  required: T[error] def marginTop_=(i: Int)  { styles("marginTop") = Fixed(i) }[error]                                                      ^[error] /Users/Ken/Documents/Programming/Scala/contextual/src/main/scala/com/digitaldoodles/contextual/style/Style.scala:1267: type mismatch;[error]  found   : i.type (with underlying type com.digitaldoodles.contextual.style.StyleValueFetcher[Int])[error]  required: T[error] def marginTop_=(i: StyleValueFetcher[Int]) { styles("marginTop") = i }[error]                                                                   ^
I'm not understanding why it doesn't work, of course, but I'm specifically confused as to why the error message is referring to T as if T is a concrete type.
Help most appreciated. I didn't think such a simple-seeming typing problem would be giving me problems, but it is.
Thanks,Ken
Derek Williams 3
Joined: 2011-08-12,
User offline. Last seen 42 years 45 weeks ago.
Re: Odd problem (to me) with type checking:
On Thu, Sep 8, 2011 at 4:48 PM, Ken McDonald <ykkenmcd@gmail.com> wrote:
I'm not understanding why it doesn't work, of course, but I'm specifically confused as to why the error message is referring to T as if T is a concrete type.

That is kind of the problem. For example, this wouldn't work:
val myStyles = new CustomStyles[String, StyleValueFetcher[String]]()
myStyles.marginTop = 3 // oops, Fixed(3) isn't a StyleValueFetcher[String]
I think you are over complicating things. Without making other changes regarding mutability and type safety, perhaps this would work better for you:
class CustomStyles { private val styles = new collection.mutable.HashMap[String, StyleValueFetcher[Any]]() def marginTop_=(i: Int)  { styles("marginTop") = Fixed(i) } def marginTop_=(i: StyleValueFetcher[Int]) { styles("marginTop") = i }}
--
Derek Williams
Ken McDonald
Joined: 2011-02-13,
User offline. Last seen 42 years 45 weeks ago.
Re: Odd problem (to me) with type checking:
I had tried that originally, but got this error (and one other that shows up as a popup on my IDE, that is similar)
[error] /Users/Ken/Documents/Programming/Scala/contextual/src/main/scala/com/digitaldoodles/contextual/style/Style.scala:1267: type mismatch;[error]  found   : com.digitaldoodles.contextual.style.StyleValueFetcher[Int][error]  required: com.digitaldoodles.contextual.style.StyleValueFetcher[Any][error] Note: Int <: Any, but class StyleValueFetcher is invariant in type R.[error] You may wish to define R as +R instead. (SLS 4.5)[error] def marginTop_=(i: StyleValueFetcher[Int]) { styles("marginTop") = i }
This is the reason for the "T<:" in my original posting--and I still think that should have worked :-)
Ken
Derek Williams 3
Joined: 2011-08-12,
User offline. Last seen 42 years 45 weeks ago.
Re: Odd problem (to me) with type checking:

Make R covariant like it suggests, then it should compile.

Derek Williams

On Sep 8, 2011 6:14 PM, "Ken McDonald" <ykkenmcd@gmail.com> wrote:
> I had tried that originally, but got this error (and one other that shows up
> as a popup on my IDE, that is similar)
>
> [error]
> /Users/Ken/Documents/Programming/Scala/contextual/src/main/scala/com/digitaldoodles/contextual/style/Style.scala:1267:
> type mismatch;
> [error] found :
> com.digitaldoodles.contextual.style.StyleValueFetcher[Int]
> [error] required:
> com.digitaldoodles.contextual.style.StyleValueFetcher[Any]
> [error] Note: Int <: Any, but class StyleValueFetcher is invariant in type
> R.
> [error] You may wish to define R as +R instead. (SLS 4.5)
> [error] def marginTop_=(i: StyleValueFetcher[Int]) { styles("marginTop") = i
> }
>
> This is the reason for the "T<:" in my original posting--and I still think
> that should have worked :-)
>
> Ken
Ken McDonald
Joined: 2011-02-13,
User offline. Last seen 42 years 45 weeks ago.
Re: Odd problem (to me) with type checking:
The better solution turned out to be:
class CustomStyles { private val styles = new collection.mutable.HashMap[String, StyleValueFetcher[_]]()
Thanks!
rodant
Joined: 2009-04-10,
User offline. Last seen 3 years 5 weeks ago.
Re: Re: Re: Re: Re:

HelloI have Order china dear friend:I have Order china 6 Apple MacBook Pro MB991LL / A 13.3w e b: bodysa.comI've received the item today
I believe you will find what you want there and have an good experienceon shopping from them.Regards!

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland