Skip to content

Instantly share code, notes, and snippets.

@jasononeil
Last active November 10, 2016 11:16
Show Gist options
  • Save jasononeil/b6b1845824f45f5d19df to your computer and use it in GitHub Desktop.
Save jasononeil/b6b1845824f45f5d19df to your computer and use it in GitHub Desktop.
Demonstration of using Haxe abstracts to take care of explicit conversions between different units of measurement, with no performance overhead.
class Metric {
static function main() {
var coinRadius:Millimeters = 12;
var myHeight:Centimeters = 180;
var raceLength:Meters = 200;
var commuteDistance:Kilometers = 23;
diff( coinRadius, myHeight ); // 1.788 meters
diff( raceLength, commuteDistance ); // 22800 meters
sum( commuteDistance, coinRadius ); // 23000.012 meters
}
static function diff( a:Meters, b:Meters ) {
var d = Math.abs( a-b );
trace( '$d meters' );
}
static function sum( a:Meters, b:Meters ) {
var s = Math.abs( a+b );
trace( '$s meters' );
}
}
abstract Millimeters( Float ) from Float to Float {
@:to function toCentimeters():Centimeters return this/10;
@:to function toMeters():Meters return this/1000;
@:to function toKilometers():Kilometers return this/1000000;
@:op(A+B) function add(rhs:Float):Float return this+rhs;
@:op(A-B) function sub(rhs:Float):Float return this-rhs;
@:op(A-B) function multiply(rhs:Float):Float return this*rhs;
@:op(A-B) function divide(rhs:Float):Float return this/rhs;
}
abstract Centimeters(Float) from Float to Float {
@:to function toMillimeters():Millimeters return this*10;
@:to function toMeters():Meters return this/100;
@:to function toKilometers():Kilometers return this/100000;
@:op(A+B) function add(rhs:Float):Float return this+rhs;
@:op(A-B) function sub(rhs:Float):Float return this-rhs;
@:op(A-B) function multiply(rhs:Float):Float return this*rhs;
@:op(A-B) function divide(rhs:Float):Float return this/rhs;
}
abstract Meters( Float ) from Float to Float {
@:to function toMillimeters():Millimeters return this*1000;
@:to function toCentimeters():Centimeters return this*100;
@:to function toKilometers():Kilometers return this/1000;
@:op(A+B) function add(rhs:Float):Float return this+rhs;
@:op(A-B) function sub(rhs:Float):Float return this-rhs;
@:op(A-B) function multiply(rhs:Float):Float return this*rhs;
@:op(A-B) function divide(rhs:Float):Float return this/rhs;
}
abstract Kilometers( Float ) from Float to Float {
@:to function toMillimeters():Millimeters return this*1000000;
@:to function toCentimeters():Centimeters return this*100000;
@:to function toMeters():Meters return this*1000;
@:op(A+B) function add(rhs:Float):Float return this+rhs;
@:op(A-B) function sub(rhs:Float):Float return this-rhs;
@:op(A-B) function multiply(rhs:Float):Float return this*rhs;
@:op(A-B) function divide(rhs:Float):Float return this/rhs;
}
(function () { "use strict";
var Metric = function() { };
Metric.main = function() {
var coinRadius = 12;
var myHeight = 180;
var raceLength = 200;
var commuteDistance = 23;
Metric.diff(coinRadius / 1000,myHeight / 100);
Metric.diff(raceLength,commuteDistance * 1000);
Metric.sum(commuteDistance * 1000,coinRadius / 1000);
};
Metric.diff = function(a,b) {
var d = Math.abs(a - b);
console.log("" + d + " meters");
};
Metric.sum = function(a,b) {
var s = Math.abs(a + b);
console.log("" + s + " meters");
};
Metric.main();
})();
@jasononeil
Copy link
Author

I wrote this as an example for a Hacker News comment - it shows how "Abstract Types" in Haxe can be used to deal with units of measurement, providing inline, implicit conversion and keeping you from getting your units mixed up.

The best part is, it wraps an ordinary Float, and when you compile, that's all it is. Take a look at how clean the Javascript output is.

It would be great to see a more comprehensive library that deals with many units of measurement (distance, volume, time, speed and more) and provides clean conversion between them.

@larsiusprime
Copy link

Should this line: https://gist.github.com/jasononeil/b6b1845824f45f5d19df#file-metric-hx-L40

@:op(A-B) function multiply(rhs:Float):Float return this*rhs;

instead be:

@:op(A*B) function multiply(rhs:Float):Float return this*rhs;

Or am I missing something?

@ibilon
Copy link

ibilon commented Aug 26, 2014

@larsiusprime I think so too, same for @:op(A/B) function divide(rhs:Float):Float return this/rhs;

@jasononeil I've started working on one: https://github.com/ibilon/units

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment