paK0
paK0

Reputation: 2588

Scala: value :: is not a member of Int

I recently started using scala and I can't make anything of the error messages. For the following code I get the stated message(using eclipse):

def helper: Int => List[Int] = x =>  x match  {
    case 2 => 2::1
    ...
}

I can fix it by using List(2,1), but souldn't that be the same thing as 2::1? I have similar problems where the List(...) approach would be harder to use, so I really want to know where my thinking mistake is.

Upvotes: 7

Views: 18793

Answers (4)

Alireza
Alireza

Reputation: 104680

If you want to use :: operator, on Int or other types like string, just add Nil to the end of the list, otherwise you get this error:

value :: is not a member of Int

this won't be compiled:

println(0::1::2::3::4::5)

but this will get compiled:

 println(0::1::2::3::4::5::Nil)

value :: is not a member of Int

Upvotes: 0

godfatherofpolka
godfatherofpolka

Reputation: 1673

The expression 2::1 is interpreted in Scala as:

{ val x = 2; 1.::(x) }

because operators ending in a colon : are right-associative and if op is right-associative, then e1 op e2 is interpreted as { val x = e1; e2.op(x) } (see Scala Language Reference, Section 6.12.3, p. 84, which is p. 92 of the PDF).

For the purposes here, basically the following simplified version is called

1.::(2)

However, 1 is of type Int and Int does not have a method with name :: (and there is also no implicit conversion to another type that has such a method), hence the error.

As ayvango has pointed out above, you could use

2::1::Nil

which is interpreted as

Nil.::(2).::(1)

Now this works perfectly well, because Nil is of type List[Nothing] and does have a method ::, see scala.collection.immutable.List Furthermore, :: returns something of type List[Int], so the subsequent call .::(1) is also fine.

Another way is

2::List(1)

which becomes List(1).::(2) and works for the same reason as above.

Your confusion might be due to the fact that you consider List(2,1) to be the same as 2::1, however, it is actually 2::1::Nil. Think of lists as being built inductively as follows:

  • Nil is a list
  • if head is an element and tail is a list, then head::tail is a list

as witnessed by the implementation of lists (simplified version, omitting traits)

sealed abstract class List[+A]
final case class ::[B](head: B, tl: List[B]) extends List[B]
object Nil extends List[Nothing]

Thus, lists always "end with" Nil in the :: form of presentation.

On a sidenote, you could also try to automatically wrap Int into List[Int] by using something like

implicit def wrap(x : Int) : List[Int] = List(x)

or use similar functionalities provided by libraries such as Scalaz but this might not always be desirable and probably is a bit beyond the scope of this question.

Upvotes: 3

Sudheer Aedama
Sudheer Aedama

Reputation: 2144

:: is a method defined on List. You are trying to use this operator with Int type. Take a look at: http://www.scala-lang.org/api/current/index.html#scala.collection.immutable.List

As @ayvango pointed out, you could do:

def helper: Int => List[Int] = x =>  x match  {
  case 2 => 2 :: 1 :: Nil
}

Upvotes: 2

sepp2k
sepp2k

Reputation: 370132

Infix operators are interpreted as method calls in Scala. If the infix operators ends with a colon, it's a method call on the right operand with the left operand as its argument. Otherwise it's a method call on the left operand with the right operand as its argument.

In other words, if you do x + y, it's the same as x.+(y), i.e. you're calling the method + on the object x, with y as the argument. And if you do x :: y it's the same as y.::(x), calling the method :: on the object y.

So in your example you're calling the method :: on the object 1, which is an Int. However the class Int does not have a :: method, so this does not work and you get an error message telling you that the :: method does not exist for the Int class.

To make :: work, the right operand needs to be a list (or something else that has a :: method), so 2 :: 1 :: Nil would work. However in this case using List() seems like the cleaner alternative.

Upvotes: 19

Related Questions