Is this the correct way of translating Java interface into Scala?

微笑、不失礼 提交于 2019-12-07 00:31:31

For a 1:1 mapping, those vars should be changed to defs.

trait Compiler {
  def printInstruction: String
}

class JavaCompiler extends Compiler {
  def printInstruction = "System.out.print(arg0);"
}

class ScalaCompiler extends Compiler {
  def printInstruction = "print(arg0);"
}

def declares a method. When you don't provide an implementation, it becomes an abstract method.

EDIT:

The technique used here is a valid and useful technique. Alternatively you could use one of the following two techniques to model your problem.

1) Discriminated unions. (aka sum types.)

Refer to this excellent article to learn about this concept. This is how your example would probably look like when modeled this way:

sealed trait Compiler {
  def printInstruction: String = this match {
    case JavaCompiler => "System.out.print(arg0);"
    case ScalaCompiler => "print(arg0);"
  }
}

case object JavaCompiler extends Compiler
case object ScalaCompiler extends Compiler

2) Type class pattern.

Here is a great post by Daniel Sobral on this topic. You can dig up a few more by googling the terms type-class, pattern, Scala, implicits etc. This is how your code might look like if the problem's modeled with type class pattern:

trait Compiler[C] {
  def printInstruction(c: C): String
}

case object JavaCompiler

implicit object JavaCompilerIsCompiler extends Compiler[JavaCompiler.type] {
  def printInstruction(c: JavaCompiler.type): String = "System.out.print(arg0);"
}

case object ScalaCompiler

implicit object ScalaCompilerIsCompiler extends Compiler[ScalaCompiler.type] {
  def printInstruction(c: ScalaCompiler.type) = "print(arg0);"
}

For your problem, the original approach and the discriminated unions approach seem to be the best modeling solutions.

The most idiomatic way is to use a def for abstract properties, and a val for concrete read-only properties. Under the Uniform Access Principle, a val can be used to implement a method:

trait Compiler {
  def printInstruction: String
}

class JavaCompiler extends Compiler {
  val printInstruction = "System.out.print(arg0);"
}

class ScalaCompiler extends Compiler {
  val printInstruction = "print(arg0);"
}

Why do I have to re declare the variable one more time in the class when I have declared it in the trait?

Because you declared the signature of the method printInstruction but you did not say what it did. In a class, as it is not an abstract class all functions should be defined. By the way, you could have defined printInstruction directly in the trait Compilerif it is supposed to do the same in every implementation.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!