ProductPromotion
Logo

Elixir

made by https://0x3d.site

GitHub - meadsteve/unit_fun: 📏 Dimension based safety in elixir
📏 Dimension based safety in elixir. Contribute to meadsteve/unit_fun development by creating an account on GitHub.
Visit Site

GitHub - meadsteve/unit_fun: 📏 Dimension based safety in elixir

GitHub - meadsteve/unit_fun: 📏 Dimension based safety in elixir

UnitFun

Build Status

Attempt to add units to numbers in elixir to give some added type saftey when dealing with numeric quantities.

Why?

One good example: pounds(dollars) should never be accidentally added to pence(cents) without conversion. Both are numeric. Wrapping the numeric data in a tuple with unit information seems like a good idea. This library gives a neat way of expressing this.

Example - Basic

First define some units:

defmodule Pounds do
  use UnitFun.Unit
end

defmodule Pence do
  use UnitFun.Unit
end

Then do something with them:

use UnitFun.MathsOperators
import UnitFun.UnitTypes

item_cost = 5 <~ Pounds # UnitFun.with_units(5, Pounds)
item_tax = 100 <~ Pence # UnitFun.with_units(100, Pence)

# The following will throw an error as the units mismatch:
item_cost + item_tax # UnitFun.add(item_cost, item_tax)

Example - Conversions

Conversions can be defined:

defimpl UnitFun.Convertor, for: Pence do
  def convert(_, Pounds, value), do: (value * 100)
end

defimpl UnitFun.Convertor, for: Pounds do
  #Note: please don't actually do a divison for any financial maths
  # You're going to lose data and have a bad time.
  def convert(_, Pence, value), do: (value / 100)
end

And now the following:

# returns: %UnitFun.Value{value: 6, units: Pounds}
total = item_cost + item_tax # UnitFun.add(item_cost, item_tax)

# returns: %UnitFun.Value{value: 600, units: Pence}
total_in_pence = total <~ Pence # UnitFun.with_units(total, Pence)

Example - Assertion

Errors can be raised if units aren't what they are expected to be:

UnitFun.assert_units(total_money, Miles)

Example - Composite units

New units can also be composed by multiplying existing units together:

  use UnitFun.MathsOperators
  import UnitFun.UnitTypes

  km_squared = Kilometers * Kilometers # UnitFun.multiply(Kilometers, Kilometers)

These newly defined units can then be used as with all previous examples

  edge = 4 <~ Kilometers # UnitFun.with_units(4, Kilometers)

  area = edge * edge # UnitFun.multiply(edge, edge)

  expected_area = 16 <~ km_squared # UnitFun.with_units(16, km_squared)
  assert area == expected_area # UnitFun.equals(area, expected_area)

Dividing/multiplying by united types returns values with new types so correctness can be asserted on.

  miles_per_hour = Miles / Hours # UnitFun.divide(Miles, Hours)

  speed = 40 <~ miles_per_hour # UnitFun.with_units(40, miles_per_hour)
  time_spent_travelling = 2 <~ Hours # UnitFun.with_units(2, hours)

  #the distance will be in Miles as the hours cancel out
  distance_travelled_in_two_hours = time_spent_travelling * speed  # UnitFun.multiply(time_spent_travelling, speed)

  assert distance_travelled_in_two_hours == 80 <~ Miles # UnitFun.with_units(80, Miles)

Example - Composite unit conversions

If there's a single unit way of representing some composite units this conversion can also be defined (N.B. there's currently no way of defining a conversion from a simple unit to a composite one):

defimpl UnitFun.Convertor, for: UnitFun.ConvertorComplexTest.Pascals do
  alias UnitFun.ConvertorComplexTest.Meters
  alias UnitFun.ConvertorComplexTest.Newtons
  alias UnitFun.Units.CompositeUnit

  def convert(_, %CompositeUnit{numerators: [%Newtons{}], denominators: [%Meters{}]}, value) do
    value
  end
end

Example - Custom mathematic functions.

All the maths is controlled by protocols. So for example if you decided pence should only be handled as integers (so rounding isn't an issue) the following protocol could be defined:

defimpl UnitFun.Maths.AddSubtractMaths, for: UnitFun.ExampleTest.Pence do
  def add(_, left, right) when is_integer(left) and is_integer(right) do
     left + right
  end
  def subtract(_, left, right) when is_integer(left) and is_integer(right) do
    left - right
  end
end

Now any addition using non integer quantities will raise a FunctionClauseError. For convinience if nothing is defined then the kernel +-/* are used.

Example - Facts about units

It's possible to define units with facts that must always hold true. This is handled by defining a list of functions that return true or false.

defmodule UnitFun.Examples.PositiveUnit do
  @moduledoc false
  use UnitFun.Unit

  defp greater_than_zero(x), do: x >= 0

  facts [
    &greater_than_zero/1
  ]

end

Now whenever a PositiveUnit value is constructed the greater_than_zero callback will be executed. If this returns False then an InvalidValueError will be raised.

Articles
to learn more about the elixir concepts.

Resources
which are currently available to browse on.

mail [email protected] to add your project or resources here 🔥.

FAQ's
to know more about the topic.

mail [email protected] to add your project or resources here 🔥.

Queries
or most google FAQ's about Elixir.

mail [email protected] to add more queries here 🔍.

More Sites
to check out once you're finished browsing here.

0x3d
https://www.0x3d.site/
0x3d is designed for aggregating information.
NodeJS
https://nodejs.0x3d.site/
NodeJS Online Directory
Cross Platform
https://cross-platform.0x3d.site/
Cross Platform Online Directory
Open Source
https://open-source.0x3d.site/
Open Source Online Directory
Analytics
https://analytics.0x3d.site/
Analytics Online Directory
JavaScript
https://javascript.0x3d.site/
JavaScript Online Directory
GoLang
https://golang.0x3d.site/
GoLang Online Directory
Python
https://python.0x3d.site/
Python Online Directory
Swift
https://swift.0x3d.site/
Swift Online Directory
Rust
https://rust.0x3d.site/
Rust Online Directory
Scala
https://scala.0x3d.site/
Scala Online Directory
Ruby
https://ruby.0x3d.site/
Ruby Online Directory
Clojure
https://clojure.0x3d.site/
Clojure Online Directory
Elixir
https://elixir.0x3d.site/
Elixir Online Directory
Elm
https://elm.0x3d.site/
Elm Online Directory
Lua
https://lua.0x3d.site/
Lua Online Directory
C Programming
https://c-programming.0x3d.site/
C Programming Online Directory
C++ Programming
https://cpp-programming.0x3d.site/
C++ Programming Online Directory
R Programming
https://r-programming.0x3d.site/
R Programming Online Directory
Perl
https://perl.0x3d.site/
Perl Online Directory
Java
https://java.0x3d.site/
Java Online Directory
Kotlin
https://kotlin.0x3d.site/
Kotlin Online Directory
PHP
https://php.0x3d.site/
PHP Online Directory
React JS
https://react.0x3d.site/
React JS Online Directory
Angular
https://angular.0x3d.site/
Angular JS Online Directory