Good pattern for a unit of measure?

I need to work with time (milliseconds), angles (degrees), and distance (millimeters), and dimensionless numbers. I want to write methods in terms of these, not just numbers.

In Opaque Types | Scala 3 — Book | Scala Documentation I see how I can use opaque types to do it. That makes sense, and looks very efficient. (The processor I’m using is pretty limited; 32-bit, not a lot of memory, slow IO, in a feedback loop) Is this the best way? What will the pitfalls be?

The system I’ll be talking to only knows Ints. Floats might make for fewer edge cases. Are there any pitfalls with opaque types backed by Ints vs Floats?

I’ll need to express angular velocity (degrees per second) (not degrees per millisecond), and speed. Will the combinations of units and methods to manipulate them get out of hand? Is there a way to avoid that growth that also resolves everything at compile time?

A “go read …” answer is fine.

Thanks,

David

1 Like

You might want to take a look at

An open-source scalar package and associated software tools have been developed in the Scala programming language, including plotting tools based on the free GRACE plotting package. The scalar package represents physical scalars and can help to prevent errors involving physical units in engineering and scientific computation. The scalar package includes a complete implementation of the standard SI metric system of units and many common non-metric units. The design also allows users to easily define a specialized or reduced set of physical units for any particular application or domain. The scalar package can be used in two different modes: one mode provides unit compatibility checking but is slower, and the other mode bypasses the compatibility checks but is much faster and still prevents the most common type of unit error. Switching between the two modes requires no changes in the user’s code, making it convenient and usable with no significant performance penalty for even the most computationally intensive applications.

1 Like

You might want to take a look at my work here, particularly in the Geom module. Overall its very orientated towards geometry and graphics. I have certainly found opaque types to be inadequate and have continued to use AnyVals. There is a strong focus on efficient mapping and transformations performed on underlying arrays of Doubles.

In the Tiling module integer coordinates are used allowing efficient mapping on underlying arrays of Ints.

Rich - why did you chose to use AnyVals for value types instead of the opaque types?

Well they were originally written in Scala 2, but having switched to Scala 3 I discovered that opaque types can’t inherit traits so they were a complete non starter.

Thanks Russ. I’ll give that a deep read.

Is it possible to switch between the imports using a combination of config, namespace, and a higher-order function? (I do this with slick database drivers at my day job. )

Thanks,

David

For opaque types or value classes - is there some graceful, efficient way to access all the arithmetic operations of the underlying (Int or Float) type? I don’t want to go down the full path in the Logarithm example in opaque types.

Not that I am aware.

As explained in the user guide, the way I switch modes is to swap the key file (Scalar.scala) and do a clean recompile. The other way is to swap the entire jar file. The package includes scripts and aliases to do these conveniently.

This method of switching modes is a trick I came up with to get the best of both worlds. Most packages that represent physical units are slow, which makes them undesirable for computationally intensive applications. My scheme allows the user to switch back and forth between the fast and slow modes with NO CHANGE REQUIRED to their source code.

I am not aware of any other software that uses this method, so I’d be interested in knowing what others think about it. One potential pitfall that I am aware of is that it can cause inconsistencies if, for example, a library is used that was compiled in the opposite mode as the client code. If it has other potential pitfalls, please let me know.

There are scala libraries exactly for this purpose:

1 Like

Thanks! There’s a big overlap in contributors. Looks like neither is using Scala3 yet.

Any overt reason to prefer one (of coulomb or libra) over the other?

Not sure. I know there is an effort to modify coulomb for Scala 3.