"Ambiguous reference to overloaded definition" when overriding a method in a derived class

I have the following code:

import com.github.nscala_time.time.Imports._

class Account {
    def balance(date: DateTime): Double = {
        /* some logic that calculates balance on given date */
        val calculatedBalance = 42
        calculatedBalance
    }

    def balance: Double = balance(DateTime.now)
}

class Deposit(val interestRate: Double) extends Account {
    override def balance(date: DateTime): Double = {
        /* some logic that calculates balance for deposit account */
        val calculatedBalance = 100 * interestRate;
        calculatedBalance
    }
}

      

I am trying to use these classes like this:

val simpleAccount = new Account
val depositAccount = new Deposit(0.1)

val simpleBalanceOnDate = simpleAccount.balance(DateTime.now + 1.month)   // A
val depositBalanceOnDate = depositAccount.balance(DateTime.now + 1.month) // B
val simpleBalance = simpleAccount.balance   // C
val depositBalance = depositAccount.balance // D

      

Cases A

, B

and C

compiled without any error, but for the line D

I see an error:

Error:(28, 38) ambiguous reference to overloaded definition,
both method balance in class Deposit of type (date: com.github.nscala_time.time.Imports.DateTime)Double
and  method balance in class Account of type => Double
match expected type ?
val depositBalance = depositAccount.balance
                                    ^

      

Could you please explain why there is a compilation error in case D

and why not in case C

?

Thanks in advance!

+3


source to share


2 answers


I guess the compiler is confused about parameterless inheritance, although I can't explain why, honestly, for a quick solution, this should work:

class Account {
  { ... }
  def balance(): Double = balance(DateTime.now)
}

val depositAccount = new Deposit(0.1)
val depositBalance = depositAccount.balance()

      

Why this is happening is not clear to me, maybe someone else knows how the scala compiler sees parameterless inheritance.

We also read, in particular Programming in Scala :



Such parameterless methods are fairly common in Scala. In contrast, methods defined by empty parentheses, such as def height (): Int, are called empty methods. The recommended convention is to use a parameterless method when there are no parameters, and the method accesses mutable state only by reading the fields of the containing object (in particular, it does not change mutable state). This convention supports the Single Access Principle, 1 which states that client code should not be influenced by the decision to implement an attribute as a field or method. For example, we could use width and height as fields instead of methods by simply changing the def in each definition to val:

abstract class Element {
  def contents: Array[String]
  val height = contents.length
  val width = 
    if (height == 0) 0 else contents(0).length
}

      

The two pairs of definitions are completely equivalent from a client point of view. The only difference is that field access can be slightly faster than method calls, because the field values ​​are precomputed when the class is initialized, rather than being evaluated on each method call. On the other hand, each Element requires additional memory space. Thus, it depends on the usage profile of the class whether the attribute is better represented as a field or a method, and this usage profile can change over time. The point is that the clients of the Element class should not be affected by changing its internal implementation.

0


source


Why don't you give a default argument like this:



    class Account {
    def balance(date: DateTime = DateTime.now): Double = {
        /* some logic that calculates balance on given date */
        val calculatedBalance = 42
        calculatedBalance
    }
}

class Deposit(val interestRate: Double) extends Account {
    override def balance(date: DateTime): Double = {
        /* some logic that calculates balance for deposit account */
        val calculatedBalance = 100 * interestRate;
        calculatedBalance
    }
}

val simpleBalanceOnDate = simpleAccount.balance(1)   // A
    val depositBalanceOnDate = depositAccount.balance(1) // B
    val simpleBalance = simpleAccount.balance()   // C
    val depositBalance = depositAccount.balance() // D

      

-2


source







All Articles