Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  • bitPosition0b : ULong - means position, measured in bits, first bit is at position 0, type unsigned long.
  • mCharWidthInBits: MaybeInt - measured in bits, but note that sizes, lengths, widths, don't have 0 or 1 base stuff. Note also use of MaybeInt type.
  • childIndex1b - child index, first child is at index 1.

Exercise for Reader!

Create a scala ZeroBased and OneBased AnyVal wrapper type with explicit (or some implicit) conversions.

The point is to let the scala compiler give you an error when you mix zero and one-based things, or pass a zero-based thing to an argument that wants a 1 based thing.

So the type of bitPosition0b (which is ULong currently) would

...

be 

Code Block
var bitPosition0b = ZeroBased[ULong]

var bitPosInByte1b = OneBased[UInt]

 

 

For examples on how to do number types along these lines, look at UInt which is an AnyVal type.

Identifier Naming Conventions

...

length/len = limit - position

width = a length that is usually smaller. We commonly use width for characters, e.g., 7 bit width, 8-bit width,, 16 bit width, etc.

length limit = a length that bounds the maximum length

...

It is almost always wrong to catch Exception, RuntimeException, Error and especially wrong to catch Throwable.

We have a specific class UnsuppressableException, which you should never catch. To be sure you are not, you should write:

...

Code Block
languagescala
val x = g(a)
val y = h(b)
val res = f(x, y)
res // good place for a breakpoint

Another example that comes up a lot in Daffodil is

If you really want that code to stay spread out like that, use a comment like the one above about wanting a place for a breakpoint. Otherwise someone might reorganize the code for clarity.

Another example that comes up a lot in Daffodil is

Code Block
Code Block
languagescala
processor(a, b, c, d, e) match {
 case A(x) => f(x)
 case B(y) => g(y)
}

...

evaluates a + b when lv is first called/used, and saves the value, so that it is only computed once.

Use 'lazy val' and 'def' to Avoid Object Initialization Headaches

In many situations when an object is being created and initialized, if anything goes wrong the error is hard to figure out because, well, the object isn't an object yet.

In general it is bad style to do anything at object initialization (in 'val' members) that might throw an exception or otherwise fail.

Furthermore, members that are computed at initialization time can't depend on other methods of the class (especially members of parent classes and traits).

If your 'val' members are changed to lazy val, then they're not computed until the object is fully constructed, so they can do things like throw exceptions, etc.

So instead of

Code Block
class myClass {
 val foo : FooType = ....complex calculation.....
}

Just use lazy val

Code Block
class myClass {
 lazy val foo : FooType = ....complex calculation....not done until after object is created....
}

There is a small amount of overhead for lazy val, so in the most performance critical situations you may want to just use an explicit initialization. Here's the baggage that implies though....

Code Block
class myClass {

  private val isInitialized =  false

  @inline private def checkInitialized {
    assert isInitialized
  }

  private var foo_ : FooType = null

  @inline def foo = checkInitialized ; foo_

  def init {
    foo_ = ....complex calculation...
    isInitialized = true
  }

  def initErr {
    throw new InvalidStateException("not initialized")
  }

Use Typed Equality

Subtle bugs can arise when comparing a == b, when a and b turn out to be different types. The == operator is "natural" equality, which simply returns false if a and b are different types.

...