Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updated. Added OKOrError

...

Built-in Scala libraries often make heavy use of the Option type. See section about HashMap below.

For Error vs. OK situations

A common pattern where Either[L, R] types are used is where Right(()) means "OK", and Left("error message") indicates a problem. This is most commonly used as a return type. To avoid allocation we have the OKOrError class. This is much like the Maybe[T] class in that it is a value class (derived from AnyVal), so it doesn't require allocation when passed around as argument or returned as a value. If you store these in a collection; however, then they do get allocated. But normally that's not the case with these OK/Error situations.

OKOrError is like Maybe[T] except that Maybe often has method names that would be misleading. If you represented error or ok states with a Maybe[String] then isDefined would be true for errors, and isEmpty would be true for "ok". Because that gets instantly confusing we have OKOrError with isError and isOK predicates.

Avoid Boxing/Unboxing Numbers

Scala's Int, Long, Short, Byte are all value types, so are passed and returned without allocating. Specialized collections like Array[Byte] also avoid allocating a boxed byte. But generic collections such as ListBuffer[T] are going to allocate a box every time a number of primitive type is inserted.

There is no idea fix for this. But consider carrying around number objects instead, so that the box gets allocated once, and then the code just carries around the number in its boxed form. So instead of allocating and discarding boxes for numbers all the time the code just carries around an object reference to a single boxed object.

The way to do this is to explicitly use the Java boxed number types. The way we do this that makes the intention clear is

Code Block
import java.lang.{Integer => JInt, Long => JLong, Short => JShort, Byte => JByte, Float => JFloat, Double => JDouble}
import java.math.{BigInteger => JBigInt, BigDecimal => JBigDecimal}

Then the prefix "J" on the name makes it clear that a boxed numeric type is being used.

Avoid Generic Collections of Unboxed Types

Code Block
val boxedInts = new ArrayBuffer(len)  // adding an Int allocates a box every time. 
var unboxedInts = new Array[Int](len) // Non allocating - note var idea - in case you need to resize it.

Avoid match-case with Pattern Matching

...

This provides the map functionality of the java-provided map class, recast as Scala's types.

Avoid Generic Collections of Unboxed Types

...

...

val boxedInts = new ArrayBuffer(len)  // adding an Int allocates a box every time. Accessing an Int discards the box.
var unboxedInts = new Array[Int](len) // Non allocating - note var idea - in case you need to resize it.

Use MStack, avoid mutable.Stack

...

Allocate on "the stack" Using OnStack and LocalStack

TBD: See the definitions of these. These make it convenient to reuse objects in recursive code, as is common in Daffodil. A small pool of reusable objects is maintained per thread. Accessing one causes it to either be created, or an existing one initialized. They get put back on exit of scope, and Scala 2.11's macros are used to avoid allocating closure objects as well.

What these achieve is some of the efficiency one sees in programming languages like C or C++  where most data structures are stack allocated and never require heap allocation nor garbage collection. There is more overhead to OnStack because it uses a thread-local to insure thread safety. if you have a per-thread data structure (such as a per-thread state block) being passed around, then you can use a LocalStack in the state block, which has less overhead.

Use Reusable Pools of Stored Objects

When reusable objects do not follow a stack discipline, then you can still reuse them by pooling them.

TBD: See Pool.scala for a common pooling idiom

Iteration Patterns - Avoid Iterators - Use Cursors and Accessors

...

If you consider that we have to avoid scala's nice generic collection functional operations like foreach and map, one might be tempted to just use the Iterator[T] class.

...