0

me again, newbie to scala and downvote is welcome if this question is stupid to you...

ok, I have a case class called "ListNode", and below is the error I got:

scala> case class ListNode[Int](vl: Int, nt: ListNode[Int] = null) {
     |     def value: Int = vl
     |     def next: ListNode[Int] = nt
     | }
defined class ListNode

scala> var a = ListNode(1)
a: ListNode[Int] = ListNode(1,null)

scala> var b = ListNode(2)
b: ListNode[Int] = ListNode(2,null)

scala> a.next = b
<console>:11: error: value next_= is not a member of ListNode[Int]
       a.next = b
         ^

I've read this and this and this and this and this, but still not really understand what it means...

Why cannot I just set the node next to be another node, just like in Java?

Thank you very much.

Community
  • 1
  • 1
keypoint
  • 2,268
  • 4
  • 31
  • 59

3 Answers3

2

I see two problems (there may be more).

1 - Your type parameter should be a parameter not an Int specification.

2 - If you're going to reassign the value of next then it needs to be a var.

case class ListNode[T](vl: T, nt: ListNode[T] = null) { 
    val value: T = vl
    var next: ListNode[T] = nt
} 

scala> val a = ListNode(1)
a: ListNode[Int] = ListNode(1,null)

scala> val b = ListNode(2)
b: ListNode[Int] = ListNode(2,null)

scala> a.next = b
a.next: ListNode[Int] = ListNode(2,null)

Of course, being a case class, it can be greatly simplified.

// this is all you need
case class ListNode[T](value: T, var next: ListNode[T] = null)
jwvh
  • 50,871
  • 7
  • 38
  • 64
1

That's because you're using def, which is a function. You might want to define the case class using vars.

The below code will work, but you might want to reconsider the whole idea of mutable case classes.

case class ListNode[Int](v1:Int, nt:ListNode[Int]=null) {
  var _nt = nt
  def value: Int = v1
  def next: ListNode[Int] = _nt
  def next_=( newNext:ListNode[Int] ) = { _nt = newNext }
}
scala> val a = ListNode(1,null)
a: ListNode[Int] = ListNode(1,null)

scala> a.next = ListNode(2,null)
a.next: ListNode[Int] = ListNode(2,null)

Note that mutating case classes is ideally done via copy:

scala> a.copy( v1=500 )
res0: ListNode[Int] = ListNode(500,null)

Additionally, if something may be null you can consider wrapping it in an Option... but I assume this is a "kick-the-tires" code, not a production one :-).

Michael Bar-Sinai
  • 2,729
  • 20
  • 27
  • thanks for the explanation, you are right it's not for production...just playing around...excuse me but here "def next_" what is the underscore? shouldn't overloading just use the same name "next" with no underscore in scala? – keypoint Dec 17 '15 at 22:30
  • This is Scala's way of creating a property. What's actually happening is that in the expression `foo.next=bar` you invoke `foo`'s method `next_=` with `bar` as a parameter. Which makes a lot of sense when you think about it, except that it's not intuitive after coming from almost any other language... That's the Scala state of things, I think :-) – Michael Bar-Sinai Dec 17 '15 at 23:34
  • Thanks a lot Michael! – keypoint Dec 17 '15 at 23:45
1

Case classes in Scala are immutable, which means you can't change their values. In this case, even if you weren't using a case class, next is a function (it is defined with def) so it does not make sense to attempt to assign a value to it.

As an additional point, it is not good practice to use null in Scala. Better to use the Option class. There are several ways to you could alter your code to solve your problem. If you want to use mutable classes, consider the following:

class ListNode[Int](value: Int, nt: Option[ListNode[Int]] = None) {
  var next = nt
}

object ListNode {

  def apply(value: Int, nt: Option[ListNode[Int]] = None) = new ListNode[Int](value, nt)
}

var a = ListNode(1)

var b = ListNode(2)

a.next = Some(b)
mattinbits
  • 10,370
  • 1
  • 26
  • 35