Wednesday, April 27, 2011

How-to In Scala: Share Implicit Type Conversions between Classes and Objects

In Scala, one of the most powerful features is implicit type conversions. The article at http://www.codecommit.com/blog/scala/scala-for-java-refugees-part-6 does a pretty good job of explaining implicits. Essentially, you can define functions for the compiler to automatically insert to convert between two types and you can then use one type of object as another. It is extremely powerful!
One of the challenges with implicits is that they must be declared in a type. You cannot declare a "global implicit" conversion to be used across all code compiled with it. Therefore, it would seem that you must redeclare implicits in every class that you want to use them in.
Actually, you don't. You can place them in a common trait, the Scala equivalent of Java's interface. A trait implements mixins, which (in Java terms) are like not-completely-abstract classes. This enables pseudo-multiple inheritance to be used in Scala! Example (taken from exprtreelib code):

// ExpressionNodeTypes.scala; org.nathanmoos.magnificalc.exprtreelib
trait Implicits
{
implicit def closure2Function[T <: { def apply(x:Double):Double }](closure:T) = new Function() {
override def evaluate(x:Double):Double = closure.apply(x)
}
}
...
object Functions
{
...
def register(name:String, func:Function) = ...
...
}
// InternalFunctions.scala; org.nathanmoos.magnificalc.exprtreelib.functions
object InternalFunctions extends Implicits
{
...
def registerAll() = {
Functions.register("ln", log _)
Functions.register("log", log10 _)
Functions.register("sqrt", sqrt _)
Functions.register("sin", sin _)
Functions.register("cos", cos _)
Functions.register("tan", tan _)
Functions.register("csc", csc _)
Functions.register("sec", sec _)
Functions.register("cot", cot _)
Functions.register("sinh", sinh _)
Functions.register("cosh", cosh _)
Functions.register("tanh", tanh _)
Functions.register("acos", acos _)
Functions.register("asin", asin _)
Functions.register("atan", atan _)
}
}
Example 2:
object MyNewFunctions extends BaseClass with Implicits
{
def plusFour(arg:Double):Double = arg + 4

def registerAll() = {
Functions.register("plusFour", plusFour _)
}
}
This example, while quite useless, demonstrates that the new Implicits trait can be used to share implicit type conversions across classes. Look for more in this new series: How-to in Scala!

Friday, April 22, 2011

Symbol Tables, Scala-ifying legacy code, and other design decisions

Symbol Tables

It's come time to write a symbol table for Magnificalc. It will allow user-defined functions, a function-registration mechanism, and multiple variables. It will also enable undefined variable solving (!) something useful for a CAS. There are many options with writing symbol tables:
  • Binary Tree
  • Binary Tree with Red-Black autobalancing algorithm
  • Hash Table
  • Linked List of name, value, and type sets
These all have their positives and negatives. Binary Trees must stay balanced to be fast, but if a binary tree is balanced, lookups are very fast (O(log n) time, O(n) space). The Red-Black tree algorithm keeps binary trees balanced with simple and quick algorithms to keep a set of stringent properties true. Those algorithms run in O(log n) time for insertions and deletions.

A Hash Table would have to have a bucket size large enough that there would not be any hash collisions, if not, the worst-case scenario is O(n) time. This is unacceptable if many variables and functions are present.

A Linked List would be a very poor choice, because a linked list's average lookup time is O(n). It would work for a small table, but not for many variables and functions.

Scala-ifying legacy code
This is the process of converting legacy Java code to Scala to take advantage of Scala features like traits and implicit type conversions. I have a significant amount of legacy code developed in a programming class in Java that I am reusing for this project, but I would like to be able to take advantage of Scala's features. Short of a full rewrite (which will happen eventually), I am starting with something like the following:
(Java) public class ExpressionTree implements ExpressionNode
{
...
public ExpressionNode getRoot()
{
return root;
}
...
}
(Scala) class SExpressionTree(tree:ExpressionTree)
{
def root() = tree.getRoot()
}
implicit def exprTree2ScalaExprTree(tree:ExpressionTree) = new SExpressionTree(tree)

This will enable the ExpressionTrees to be used as if they were native Scala objects. This is a stopgap measure until the whole library is ported to Scala, and then the symbol table will be implemented.

Thursday, April 21, 2011

Announcing Magnificalc!! (Logo released, too!)



This is my first post to the Magnificalc developer's log. Here, I provide in-depth technical updates as to how Magnificalc is coming along.
For those who don't know, Magnificalc is a project that will accomplish the following goals:
  • An advanced graphing calculator (equivalent to TI-89 in terms of functionality)
  • An Android app (>= 2.1 Eclair, or API level 7) to make it portable
  • Modularity in a calculator. Functions will be able to be added and removed, making it a completely modular, do-it-all calculator.
The Magnificalc logo consists of a bay-leaf with a large letter "M" and several mathematical symbols.

Magnificalc will be written in Java and Scala programming languages. The Gradle build system is also used to make the development nice and agile. There will be lots posted about Scala and Gradle, and I hope to eventually write an e-book: Learning the Java Virtual Machine through Practical Technologies: Gradle, Scala, Spring Framework, and SWT. Follow this blog's posts through the Atom feed if you want to track the progress, and don't forget to like it on Facebook too!