Skip to content

[FEATURE] Units of Measure (Need for elegant, natural and intuitive (Zen) syntax) #320

@general-rishkin

Description

@general-rishkin

Is your feature request related to a problem? Please describe.
I want to create a Unit of Measure library or plugin for Zen C, which can be used for scientific simulations.

This is regarded as one of the killer features of F#:

let distance = 100.0<m>
let time        = 5.0<s>
let speed     = distance / time  // F# automatically infers speed is 20.0<m/s>

printfn "Speed: %f m/s" speed // Output: 20.000000 m/s

// let error = distance + 10.0<s> // This will fail to compile

Nim has the unchained library:

let distance = 100.m
let time        = 5.s
let speed     = distance / time  // Nim automatically infers speed is 20.m/s

echo "Speed: ", speed // Output: 20.000000 m•s⁻¹

// let error = distance + 10.s // This will fail to compile

C++ will most likely have the mp_units library incorporated into it std for C++29:

auto distance = 100.0*m;
auto time       = 5.0*s;    
auto speed    = distance / time; 

std::cout << "Speed: " << speed << '\n';

// auto error = distance + 10*s // This will fail to compile

I have a beginning, rudimentary proof-of-concept implementation in Zen C that sorts of looks like the C++ version but is inverted becuase of how Zen C overloads operators, i.e., 5.0*m is m*5.0 .

This works but is inverted as stated above:

struct Meter {}
struct Second {}
struct Kilogram {}

def m: Meter        = Meter{}
def s: Second       = Second{}
def kg: Kilogram = Kilogram{}

// Core type
struct Quantity<Dim> {
  value: f64
}


impl Meter {
  fn mul(self, scalar: f64) -> Quantity<Meter> {
      return Quantity<Meter> { value: scalar }
  }
}

impl Second {
  fn mul(self, scalar: f64) -> Quantity<Second> {
      return Quantity<Second> { value: scalar }
  }
}

impl Kilogram {
  fn mul(self, scalar: f64) -> Quantity<Kilogram> {
      return Quantity<Kilogram> { value: scalar }
  }
}

impl Quantity<Dim> {
  fn add(self, other: Quantity<Dim>) -> Quantity<Dim> {
      return Quantity<Dim> { value: self.value + other.value }
  }

  fn sub(self, other: Quantity<Dim>) -> Quantity<Dim> {
      return Quantity<Dim> { value: self.value - other.value }
  }

  fn mul(self, scalar: f64) -> Quantity<Dim> {
      return Quantity<Dim> { value: self.value * scalar }
  }
}

fn main() {
  let d1 = m*5.0           // Quantity<Meter> = 5.0 m   BUT NEED/WANT 5.0*m
  let d2 = m*3.0           // Quantity<Meter> = 3.0 m   BUT NEED/WANT 3.0*m
  let total = d1 + d2       

  let doubled = d1*2.0
  let also_doubled = m*2.0

  let t1 = s*10.0

  // let wrong = d1 + t1     // Will fail to compile

  printf("Total distance: %f m\n", total.value)
}

Describe the solution you'd like
I would like to be able to do:

let d1 = 5.0*m

or better.

Could the operator overloading be enhanced to support this!?!

Describe alternatives you've considered
m(5.0) would work but looks weird.
so, does meter(5.0).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions