0

One is able to define methods without paranthesis if they have no arguments. A special use-case is to use this to get values. Should I do this, or rather directly get the value?

So

class Complex(real: Double, imaginary: Double) {
  def re = real
  def im = imaginary
  override def toString() =
    "" + re + (if (im < 0) "" else "+") + im + "i"
}

or

class Complex(real: Double, imaginary: Double) {
  val re = real
  val im = imaginary
  override def toString() =
    "" + re + (if (im < 0) "" else "+") + im + "i"
}
Make42
  • 12,236
  • 24
  • 79
  • 155
  • Why have these defs or vals separate from the constructor args at all? Why not just `class Complex(val re: Double, val im: Double) { override def toString() = ... }` – Jesper Oct 04 '16 at 09:52
  • @Jesper: Frankly, I am not sure: I am coming from http://docs.scala-lang.org/tutorials/scala-for-java-programmers.html – Make42 Oct 04 '16 at 09:59
  • Ok, that tutorial doesn't show that feature of Scala. If you put `val` in front of the constructor args, you get effectively the same thing as your second example. – Jesper Oct 04 '16 at 10:01

2 Answers2

2

You can put val in front of the constructor arguments to make it a bit shorter, which is effectively the same as your second piece of code:

class Complex(val re: Double, val im: Double) {
  override def toString() = "" + re + (if (im < 0) "" else "+") + im + "i"
}

Note that def defines a method, while val defines a final member variable. Since the return value of these two methods is fixed, there's not really a reason to make them methods. So, in this case, use val instead of def.

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • "there's not really a reason to make them methods", unless you want to override them with `def`s in a subclass – Victor Moroz Oct 04 '16 at 11:57
  • @VictorMoroz Yes, but in this specific case with a class `Complex` that represents complex numbers that seems unlikely. – Jesper Oct 04 '16 at 14:13
1

Even better: make it a case class:

case class Complex(re: Double, im: Double) {
   override def toString() = "%f%+fi".format(re,im)
}

This gives you re and im as members, plus some additional perks, such as copy:

val a = Complex(1,2)
val realA = a.copy(im = 0)

and unapply:

def isImaginary(a: Complex) = a match {
   case Complex(0, _) => true
   case _ => false
}

def abs(a: Complex) = a match {
   case Complex(re, im) => re*re + im*im
}

and also equals, hashCode, etc.

Dima
  • 39,570
  • 6
  • 44
  • 70
  • One last thing: `case class`es already provide an implementation of `toString`, which would render, for example, to something like `"Complex(4.2, 4.7)"`. Furthermore, if you want to override the `toString` method you can also override it with a `val` instead of a `def` so that its value is not recomputed each time you ask for it (you may want to this if you happen to have individual instances of your class rendered as a string multiple times throughout the code - for logging purposes, for example). – stefanobaghino Oct 04 '16 at 11:29