Skip to content

Instantly share code, notes, and snippets.

@glesica
Last active August 29, 2015 14:17
Show Gist options
  • Save glesica/ccb86f4d5ad3eb076d58 to your computer and use it in GitHub Desktop.
Save glesica/ccb86f4d5ad3eb076d58 to your computer and use it in GitHub Desktop.
Rudimentary implementation of units of measure in Julia.
import Base.show, Base.convert
abstract Unit
abstract ScalarUnit <: Unit
abstract CompoundUnit <: Unit
abstract LinearUnit <: ScalarUnit
macro defunit(name::Symbol, parent::Symbol)
quote
immutable $name <: $parent
value::Float64
end
$(esc(name))(x::Unit) = convert($name, x)
end
end
macro defbase(name::Symbol, parent::Symbol)
quote
$(esc(:baseunit)){T <: $parent}(::Type{T}) = $name
end
end
macro defconv(left::Symbol, right::Symbol, ltor::Expr, rtol::Expr)
quote
function $(esc(:convert))(::Type{$right}, a::$left)
local x = a.value
$right($ltor)
end
function $(esc(:convert))(::Type{$left}, a::$right)
local x = a.value
$left($rtol)
end
end
end
@defunit Cm LinearUnit
@defbase Cm LinearUnit
@defunit In LinearUnit
@defconv In Cm (x * 2.54) (x / 2.54)
@defunit Ft LinearUnit
@defconv Ft Cm (x * 30.48) (x / 30.48)
convert{T <: Unit}(::Type{T}, x::T) = x
convert{T <: Unit, J <: Unit}(::Type{T}, x::J) = convert(T, convert(baseunit(J), x))
baseunit{T <: Unit}(::Type{T}) = error("No base unit defined for $(T)")
show{T <: Unit}(io::IO, x::T) = print(io, "$(x.value)$(lowercase(string(typeof(x))))")
*{T <: Unit}(x::Real, ::Type{T}) = T(x)
+{T <: Unit}(a::T, b::T) = (a.value + b.value) * T
-{T <: Unit}(a::T, b::T) = (a.value - b.value) * T
*{T <: Unit}(a::T, b::Real) = (a.value * b) * T
*{T <: Unit}(a::Real, b::T) = b * a
/{T <: Unit}(a::T, b::Real) = (a.value / b) * T
/{T <: Unit}(a::Real, b::T) = b * a
# Testing...
a = 2.0Cm
b = 2.0In
c = 2.0Ft
println("a = ", a)
println("b = ", b)
println("\nArithmetic...")
println("a + a = ", a + a)
println("a * 2 = ", a * 2)
println("2 * a = ", 2 * a)
println("\nFancy conversions...")
println("a -> In: ", a |> In)
println("a -> Cm: ", a |> Cm)
println("b -> Cm: ", b |> Cm)
println("c -> In: ", c |> In)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment