Acorn

The Acorn language allows users to combine numeric and Boolean values using standard arithmetic and logical operators.

Design

The Expression-Value Duality is expressed as two traits. Literal extends both. Numbers and Booles are traits that encapsulate Scala Doubles and Booleans, respectively:

 

Here are all of the Expression classes that must be implemented and tested:

Like many Expression classes, Sum has two Expression fields:

Traits

Scala doesn't have interfaces, instead it has traits:

trait Value


trait Expression {
  def execute: Value
}

Unlike interfaces, traits may include implemented methods.

A class, trait, or object may extends several traits:

class Literal extends Expression with Value {
  def execute = this
}

Case Study

The following declaration demonstrates: overriding methods, companion objects, operator overloading, the apply method,

class Number(val value: Double) extends Literal {
  def +(other: Number) = Number(this.value + other.value)
  def *(other: Number) = Number(this.value * other.value)
  def -(other: Number) = Number(this.value - other.value)
  def /(other: Number) = Number(this.value / other.value)
  def <(other: Number) = Boole(this.value < other.value)
  def ==(other: Number) = Boole(this.value == other.value)
  override def toString  = value.toString
}

object Number {
  def apply(value: Double) = new Number(value)
}

Notice what happens if val is removed.

Case Study: casting

class Sum(val operand1: Expression, val operand2: Expression) extends Expression {
 
  def execute() = {
    val value1 = operand1.execute
    val value2 = operand2.execute
    if (!value1.isInstanceOf[Number] || !value2.isInstanceOf[Number])
      throw new Exception("type mismatch: only numbers can be added")
    else {
      val num1 = value1.asInstanceOf[Number]
      val num2 = value2.asInstanceOf[Number]
      num1 + num2
    }

  }
 
  override def toString = "(" + operand1.toString + " + " + operand2.toString + ")"
}

object Sum {
  def apply(operand1: Expression, operand2: Expression) =
    new Sum(operand1, operand2)
}

Case Study: Singletons

object AcornTest extends App {
 
  def execute(exp: Expression) {
    try {
      print(exp.toString + " = ")
      val value = exp.execute
      println(value.toString)
    } catch {
      case e: Exception => println(e)
    }
  }
 
  execute(Sum(Number(3.1), Number(4.2)))
  execute(And(Boole(true), Boole.TRUE))
  execute(And(Boole.FALSE, Number(3.1)))
  execute(And(Number(3.1), Boole.FALSE))
  execute(Sum(Number(3.1), Boole.FALSE))
  execute(Sum(Sum(Number(3.1), Number(4.2)), Sum(Number(3.5), Number(2.8))))
  //execute(Less(Product(Number(10), Sum(Number(3), Number(5)))))
  // etc.
}