4

I have the following code. When compiling I get an error saying

value email is not a member of Player

class Player(email: String)
{
  override def equals(player: Any): Boolean = {
    player match {
      case p: Player => email.equals(p.email)
      case _ => false
    }
  }
}

I am a Java programmer trying out Scala and can't figure out why this error is occuring (From what I understand email is a member of player instance). Can someone give an explanation and how to solve this problem?

Can't Tell
  • 12,714
  • 9
  • 63
  • 91
  • 2
    It'd be easier with case class http://stackoverflow.com/questions/2312881/what-is-the-difference-between-scalas-case-class-and-class – Przemek Dec 29 '14 at 15:54

2 Answers2

16

email is only a constructor parameter and not a member of the class itself. You can make it as such by preceding it with val

class Player(val email: String) {
  override def equals(player: Any): Boolean = {
    player match {
      case p: Player => email.equals(p.email)
      case _ => false
    }
  }
}

For completeness, you could also manually make email a member of Player:

class Player(e: String) {
  val email: String = e
  ...
}

Or a def (if you for some reason want to):

class Player(e: String) {
   def email: String = e
   ...
}

As mentioned by @srgfed01, you can include access modifiers in the constructor as well. For instance:

class Player(private val email: String) 

A case class will generate getters for your class automatically, though they are all public by default.

I prefer the first method for declaring a constructor parameter a class member, as it's clear, concise, and reduces code clutter (imagine if you had 10 params you wanted accessors for).

Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
  • Or 'private val' if you don't want 'email' to be visible – user5102379 Dec 29 '14 at 16:07
  • Thanks for the answer. I have another question. To me there seems to be another option, which is add a private method to the class which returns the value of the constructor parameter. What difference is there between that and what you have suggested? Is one better than the other? `class Player(p_email: String) { private def email:String = p_email override def equals(player: Any): Boolean = { player match { case p: Player => email.equals(p.email) case _ => false } } }` – Can't Tell Dec 29 '14 at 17:43
  • Seems longer without benefit, functionality wise the same. Even if email was public, "information hiding" like this does not make sense as email is immutable and can be exposed directly. Curious thought: I had some issues with a private val in a constructor parameter as well because it looked weird coming from Java, but after a few years I don't even think about it anymore, I just now consciously remember making something a private val because it was a compiler error as well, without ever thinking about it as a not so good solution. – Elmar Weber Dec 29 '14 at 18:19
  • Since you asked: IMHO The first one is better for two reasons: More concise and also will potentially be slower at runtime because it will have at least one more method invocation in between (but which will be inline through JIT probably). – Elmar Weber Dec 29 '14 at 18:21
  • @Can'tTell The only difference is that with `Player(private val email: String)`, that same method/member is compiler generated. The `def` might be slightly slower.. but you could also make that `private val`. – Michael Zajac Dec 29 '14 at 18:21
  • Note that the *uniform access principle* applies; declaring `val email` does not prevent you from refactoring access to be via a method in the future. So there's no need to write accessors for everything in the name of future compatibility. – lmm Dec 29 '14 at 20:28
7

Instead of using a normal class and writing your own equals method, use a case class, like this:

case class Player(email: String)

The equals and hashCode methods are generated automatically for you. The extra benefit is that if you change the fields, equals/hashCode are guaranteed to be kept in sync. If you're going to do any kind of serialization, most libraries expect case classes anyway.

tddmonkey
  • 20,798
  • 10
  • 58
  • 67