Home

Awesome

Build status Maven Central

Typelevel unboxed compile time dimensional analysis over tagged types.

sbt

Scala: 2.11.11, 2.12.1, 2.12.2

libraryDependencies += "org.rudogma" %% "superquants" % "0.9"

ScalaJS (compiled with 0.6.17)

libraryDependencies += "org.rudogma" %%% "superquants" % "0.9"

Features

Roadmap

This is a snapshot of pre-release. Release planned at July'2017 For now almost all physical rules supported for plain, powered and complex(fractional) units. However there some cases that i didn't test yet. I will check them all in a few weeks. Also I plan to add some more features before release to power up usability.

Usage

###Check out tests for more examples

Basic terms

I think you already know what is Tagged types and how they work ( or U can read some more at: https://github.com/Rudogma/scala-supertagged ). In supertagged I've made new level of tagging and called this OverTagged. TaggedType and OverTagged - are used upon this library heavily.

Define some val(-r)s

import superquants._
import longprecision._
import longprecision.length._
import longprecision.time._
import shapeless.{ ::, HNil, Nat }

val meters:Meters = 5.meters
val seconds:Seconds = Seconds @@ (Time @@ 5L)
val squaredSeconds:Pow[Long, Seconds, PowPlus, Nat._1] = 5L.as[Pow[Long, Seconds, PowPlus, Nat._1]]
// or using alias
val squaredSeconds2:Squared[Seconds] = 5L.as[Squared[Seconds]]

val speed:Complex[Long, Pow[Long, Meters, PowPlus, Nat._1] :: Pow[Long,Seconds,PowMinus, Nat._1]] = 5L.as //as[T] - will auto use explicit type from the left

//aliased
val speed2:Complex[Long, Single[Meters] :: Negative.Single[Seconds] :: HNil] = 5L.as

type Speed = Complex[Long, Single[Meters] :: Negative.Single[Seconds] :: HNil]

val speed22:Speed = 5L.as
/**
* Library based on a simple physical rules. So... 
*/

val metersXseconds = 5.meters ** 5.seconds
val speed3:Speed = 5.meters divide (5.seconds ** 5.seconds)

val plainMeters:Meters = speed3 ** (5.seconds ** 5.seconds)

// annihilate units
val plainLong = speed3 ** (5.seconds ** 5.seconds divide 5.meters)
 
 val meters2:Meters = 5.meters ++ 5.meters
 //but, U can't do it with primitive
 // meters2 = 5.meters ++ 5L // Wil not compile!!! Physicists denied that!
 //but, U can multiply unit with raw primitives
 val meters3:Meters = 5.meters ** 5L

Limitations

The cost of performance: As U see above I've used '**' for multipying. Because our types are tagged on type level(and so unboxed) and have no materialized mixins at runtime we can't overload primitive operators. Supported operators:

Note!

Because our types are primitives. Primitive operators also works and provide raw primitive value

val meters:Meters = 5.meters * 5.seconds // fails, because we got raw Long. But compiler sees Meters at the left and will safe us. 

Physicists agree. If we multiply meters on seconds we will get just number. Not seconds, not meters, not other complex unit. Just Number. These remains all primitive operators.

Aliasing

import superquants._
import longprecision._
import longprecision.length._
import longprecision.time._
import shapeless.{::, HNil}

//Using aliases in  longprecision.package.scala
type Acceleration = Complex[Long, Single[Meters] :: Squared[Seconds] :: HNil]
//Equivalent in a more verbose: type Acceleration = Complex[Long, Pow[Long, Meters, PowPlus, Nat._1] :: Pow[Long, Seconds, PowMinus, Nat._2] :: HNil]

val acc = 5.meters divide (5.seconds ** 5.seconds)

//Or we can explicitly specify alias if we think we could forget something. Let compiler do some work!
val acc2:Acceleration = acc 

// will accept only accelerations
def onlyAcceleration(acc:Acceleration):Unit = {}

Convert

import superquants._
import longprecision._

val mg:Milligrams = 5.kg in Grams // Got: 5000 Milligrams

Prettify

import superquants._
import render._
import longprecision.mass._


10.kg.pretty shouldEqual "10 kg"

//Or U can specify how much details u need
11123456789L.mg.pretty[Tonnes :: Kilograms :: Grams :: Milligrams :: HNil] shouldEqual "11 t 123 kg 456 g 789 mg"
11123456789L.mg.pretty[Tonnes :: Milligrams :: HNil] shouldEqual "11 t 123456789 mg"