October 05, 2009
"language_fan" <foo@bar.com.invalid> wrote in message news:hacm6o$2en$2@digitalmars.com...
> Mon, 05 Oct 2009 11:41:52 +0000, language_fan wrote:
>>
>> There have been several existing implementations of SI unit libraries for D. By Oskar Linde et al. The checking can be built statically without any runtime performance penalty.
>
> The only problem with these was that there was no way to signal the location of the type error in the client code, it always reported the location of the (static) assert in the library, which is pretty much useless.

Yea, that's been a problem for a *lot* of stuff... Although I think it might be fixed now... I could swear there was a patch on bugzilla for that that I had grabbed and made a custom-build of DMD with, and then saw that a newer version of DMD had incorporated it... But in my current sleepless stupor I might be confusing it with something else...


October 05, 2009
Nick Sabalausky wrote:
> I've been thinking it might be nice to have both. Compile-time for obvious reasons but then also run-time ones that could do conversions:
> 
> auto velocity = convert(meter/second)(distance / time); // Actual runtime-conversion

I'm pretty sure Boost.Units already does this, although in general it's probably better to stick with SI units in your code and only perform conversions on input/output.


-- 
Rainer Deyke - rainerd@eldwood.com
October 05, 2009
language_fan wrote:
> The only problem with these was that there was no way to signal the location of the type error in the client code, it always reported the location of the (static) assert in the library, which is pretty much useless.

That's a compiler problem, no?  I don't think this is a big deal either way.  Unit errors should be exceedingly rare.  The purpose of a unit library not to track down unit errors, but to formally prove that correct code is correct.


-- 
Rainer Deyke - rainerd@eldwood.com
October 05, 2009
Nick Sabalausky Wrote:

> "Justin Johansson" <no@spam.com> wrote in message news:ha4qpi$189h$1@digitalmars.com...
> > For the interest of newsgroups readers, I dropped in at the Cafe the other
> > day and
> > the barista had this to say
> >
> > http://cafe.elharo.com/programming/imagine-theres-no-null/
> >
> > Disclaimer: YMMV
> >
> > Cheers
> >
> 
> This is gonna sound trivial (and probably is), but it's been bugging the hell out of me:
> 
> What is the meaning of the "+ Looney Tunes" added to the title of this sub-thread? I don't see a connection...?


Good question.  Next question? :-)

Okay, Nick, this is the twist (warped as it may be).

For starters I'm guessing that you are somewhat younger than me. (Walter said once that D seems to attract a lot of the younger crowd; myself, I'm Walter's vintage.)

I grew up watching a lot of Marx Brothers movies (and, btw, I'm continually surprised by just
how many people, mostly younger, have never heard of the Marx Brothers, so just in case
you are a member of said set, here's his bio: http://en.wikipedia.org/wiki/Groucho_Marx ).

Groucho Marx was the absolute master of wisecracks; IMHO, few comedians have ever come close to matching his undeniable ability to make fast-talking wit out of the even the most subtle of connections.  Alan Alda (in M*A*S*H) often played out Groucho, much to my delight.

I also grew up with eyes glued to every Bugs Bunny cartoon that I could watch and every Looney Tune that accompanied the same. ( http://en.wikipedia.org/wiki/Looney_Tunes )

So now, having mentioned Marx, Alda and Bunny, this explains where my sense of humour comes from.

Now the title of the Elliotte Rusty Harold article,

http://cafe.elharo.com/programming/imagine-theres-no-null/ ,

that started this thread was a play on words from the title of the song
"Imagine there’s no Heaven" by John Lennon, and acknowledged by ERH at the end of the article.
(Also so happens that The Beatles along with Pink Floyd are some of my favourite bands.)

( Lyrics to Imagine written up here - http://www.slymarketing.com/2007/10/imagine-there-is-no-heaven/ )

So at the time I was thinking,

"Hey, that's a good controversial story line to throw in for a bit of Fudd** on the D newsgroup"

and, come to think of it (still saying to myself), it's probably a bit of a Looney Tune.

Now having said all that, several possible interpretations are left open for the amusement of readers.

** Fudd.

Acronym	Definition
FUDD	Functional Description Document
FUDD	Fear Uncertainty Doubt and Disinformation

Also Google on (exactly and typed below)

define:fudd

to get further connection with Looney Tunes

Cheers

-- Justin Johansson

October 05, 2009
bearophile wrote:
> Scala has a powerful type system that allows to implement such things in a good enough way:
> 
> http://www.michaelnygard.com/blog/2009/05/units_of_measure_in_scala.html

So does D:
===============================================
// by Oskar Linde Aug 2006
// This is just a quick hack to test
// IFTI operators opMul and opDel

import std.stdio;
import std.math;
import std.string;

version = unicode;

struct SiQuantity(T,int e1, int e2, int e3, int e4, int e5, int e6, int e7) {
	T value = 0;
	alias T ValueType;
	const exp1 = e1;
	const exp2 = e2;
	const exp3 = e3;
	const exp4 = e4;
	const exp5 = e5;
	const exp6 = e6;
	const exp7 = e7;

	static assert(SiQuantity.sizeof == ValueType.sizeof);

	template AddDimensions(int mul, U) {
		static assert(is(U.ValueType == ValueType) ||
			      is(U == ValueType),
			      "incompatible value types");
		static if (is(U == ValueType))
			alias SiQuantity AddDimensions;
		else
			alias SiQuantity!(T,exp1+mul*U.exp1,exp2+mul*U.exp2,
					  exp3+mul*U.exp3,exp4+mul*U.exp4,
					  exp5+mul*U.exp5,exp6+mul*U.exp6,
					  exp7+U.exp7) AddDimensions;
	}

	SiQuantity opAddAssign(SiQuantity rhs) {
		value += rhs.value;
		return this;
	}

	SiQuantity opSubAssign(SiQuantity rhs) {
		value -= rhs.value;
		return this;
	}

    const
    {

	SiQuantity opAdd(SiQuantity rhs) {
		SiQuantity ret;
		ret.value = value + rhs.value;
		return ret;
	}

	SiQuantity opSub(SiQuantity rhs) {
		SiQuantity ret;
		ret.value = value - rhs.value;
		return ret;
	}

	SiQuantity opNeg() {
		SiQuantity ret;
		ret.value = -value;
		return ret;
	}

	SiQuantity opPos() {
		typeof(return) ret;
		ret.value = value;
		return ret;
	}

	int opCmp(SiQuantity rhs) {
		if (value > rhs.value)
			return 1;
		if (value < rhs.value)
			return -1;
		return 0; // BUG: NaN
	}

	AddDimensions!(+1,Rhs) opMul(Rhs)(Rhs rhs) {
		AddDimensions!(+1,Rhs) ret;
		static if (is(Rhs : T))
			ret.value = value * rhs;
		else
			ret.value = value * rhs.value;
		return ret;
	}

	AddDimensions!(-1,Rhs) opDiv(Rhs)(Rhs rhs) {
		AddDimensions!(-1,Rhs) ret;
		static if (is(Rhs : T))
			ret.value = value / rhs;
		else
			ret.value = value / rhs.value;
		return ret;
	}

	SiQuantity opMul_r(T lhs) {
		SiQuantity ret;
		ret.value = lhs * value;
		return ret;
	}

	SiQuantity!(T,-e1,-e2,-e3,-e4,-e5,-e6,-e7) opDiv_r(T lhs) {
		SiQuantity!(T,-e1,-e2,-e3,-e4,-e5,-e6,-e7) ret;
		ret.value = lhs / value;
		return ret;
	}

	string toString() {
		string prefix = "";
		T multiplier = 1;
		T value = this.value;
		string unit;
		
		static if (is(typeof(UnitName!(SiQuantity))))
			unit = UnitName!(SiQuantity);
		else {
			value *= pow(cast(real)1e3,cast(uint)e2); // convert kg -> g
			// Take mass (e2) first to handle kg->g prefix issue	
			if (e2 != 0) unit ~= format("·g^%s",e2);
			if (e1 != 0) unit ~= format("·m^%s",e1);
			if (e3 != 0) unit ~= format("·s^%s",e3);
			if (e4 != 0) unit ~= format("·A^%s",e4);
			if (e5 != 0) unit ~= format("·K^%s",e5);
			if (e6 != 0) unit ~= format("·mol^%s",e6);
			if (e7 != 0) unit ~= format("·cd^%s",e7);
			if (unit)
				unit = unit[2..$].split("^1").join("");
		}

		if (value >= 1e24) { prefix = "Y"; multiplier = 1e24; }
		else if (value >= 1e21) { prefix = "Z"; multiplier = 1e21; }
		else if (value >= 1e18) { prefix = "E"; multiplier = 1e18; }
		else if (value >= 1e15) { prefix = "P"; multiplier = 1e15; }
		else if (value >= 1e12) { prefix = "T"; multiplier = 1e12; }
		else if (value >= 1e9) { prefix = "G"; multiplier = 1e9; }
		else if (value >= 1e6) { prefix = "M"; multiplier = 1e6; }
		else if (value >= 1e3) { prefix = "k"; multiplier = 1e3; }
		else if (value >= 1) { }
		else if (value >= 1e-3) { prefix = "m"; multiplier = 1e-3; }
		else if (value >= 1e-6) {
			version(unicode)
				prefix = "µ";
			else
				prefix = "u";
			multiplier = 1e-6; }
		else if (value >= 1e-9) { prefix = "n"; multiplier = 1e-9; }
		else if (value >= 1e-12) { prefix = "p"; multiplier = 1e-12; }
		else if (value >= 1e-15) { prefix = "f"; multiplier = 1e-15; }
		else if (value >= 1e-18) { prefix = "a"; multiplier = 1e-18; }
		else if (value >= 1e-21) { prefix = "z"; multiplier = 1e-21; }
		else if (value >= 1e-24) { prefix = "y"; multiplier = 1e-24; }

		return format("%.3s %s%s",value/multiplier, prefix, unit);
	}	
    }
}

//length  			meter  		m
//mass 				kilogram       	kg
//time 				second 		s
//electric current 		ampere 		A
//thermodynamic temperature     kelvin 		K
//amount of substance 		mole 		mol
//luminous intensity 		candela 	cd

// Si base quantities
alias SiQuantity!(real,1,0,0,0,0,0,0) Length;
alias SiQuantity!(real,0,1,0,0,0,0,0) Mass;
alias SiQuantity!(real,0,0,1,0,0,0,0) Time;
alias SiQuantity!(real,0,0,0,1,0,0,0) Current;
alias SiQuantity!(real,0,0,0,0,1,0,0) Temperature;
alias SiQuantity!(real,0,0,0,0,0,1,0) AmountOfSubstance;
alias SiQuantity!(real,0,0,0,0,0,0,1) Intensity;

alias SiQuantity!(real,0,0,0,0,0,0,0) UnitLess;

// Derived quantities
alias typeof(Length*Length) 		Area;
alias typeof(Length*Area) 		Volume;
alias typeof(Mass/Volume) 		Density;
alias typeof(Length*Mass/Time/Time) 	Force;
alias typeof(1/Time) 			Frequency;
alias typeof(Force/Area) 		Pressure;
alias typeof(Force*Length) 		Energy;
alias typeof(Energy/Time) 		Power;
alias typeof(Time*Current) 		Charge;
alias typeof(Power/Current) 		Voltage;
alias typeof(Charge/Voltage) 		Capacitance;
alias typeof(Voltage/Current) 		Resistance;
alias typeof(1/Resistance) 		Conductance;
alias typeof(Voltage*Time) 		MagneticFlux;
alias typeof(MagneticFlux/Area) 	MagneticFluxDensity;
alias typeof(MagneticFlux/Current) 	Inductance;
alias typeof(Intensity*UnitLess) 	LuminousFlux;
alias typeof(LuminousFlux/Area) 	Illuminance;

// SI fundamental units
const Length 		meter 		= {1};
const Mass 		kilogram 	= {1};
const Time 		second 		= {1};
const Current 		ampere 		= {1};
const Temperature 	kelvin 		= {1};
const AmountOfSubstance mole 		= {1};
const Intensity 	candela 	= {1};

// Derived units
const Frequency		hertz		= {1};
const Force		newton		= {1};
const Pressure		pascal		= {1};
const Energy		joule		= {1};
const Power		watt		= {1};
const Charge		coulomb		= {1};
const Voltage		volt		= {1};
const Capacitance	farad		= {1};
const Resistance	ohm		= {1};
const Conductance	siemens		= {1};
const MagneticFlux	weber		= {1};
const MagneticFluxDensity tesla 	= {1};
const Inductance	henry		= {1};
const LuminousFlux	lumen		= {1};
const Illuminance	lux		= {1};

template UnitName(U:Frequency) 	{ const UnitName = "Hz"; }
template UnitName(U:Force) 	{ const UnitName = "N"; }
template UnitName(U:Pressure)	{ const UnitName = "Pa"; }
template UnitName(U:Energy) 	{ const UnitName = "J"; }
template UnitName(U:Power)	{ const UnitName = "W"; }
template UnitName(U:Charge)	{ const UnitName = "C"; }
template UnitName(U:Voltage) 	{ const UnitName = "V"; }
template UnitName(U:Capacitance){ const UnitName = "F"; }
version(unicode) {
	template UnitName(U:Resistance) { const UnitName = "?"; }
} else {
	template UnitName(U:Resistance) { const UnitNAme = "ohm"; }
}	
template UnitName(U:Conductance){ const UnitName = "S"; }
template UnitName(U:MagneticFlux){ const UnitName = "Wb"; }
template UnitName(U:MagneticFluxDensity) { const UnitName = "T"; }
template UnitName(U:Inductance) { const UnitName = "H"; }

void main() {
	Area a = 25 * meter * meter;
	Length l = 10 * 1e3 * meter;
	Volume vol = a * l;
	Mass m = 100 * kilogram;
	assert(!is(typeof(vol / m) == Density));
	//Density density = vol / m; // dimension error -> syntax error
	Density density = m / vol;
	writefln("The volume is %s",vol.toString);
	writefln("The mass is %s",m.toString);
	writefln("The density is %s",density.toString);

	writef("\nElectrical example:\n\n");
	Voltage v = 5 * volt;
	Resistance r = 	1 * 1e3 * ohm;
	Current	i = v/r;
	Time ti = 1 * second;
	Power w = v*v/r;
	Energy e = w * ti;

	// One wishes the .toString was unnecessary...
	writefln("A current of ",i.toString);
	writefln("through a voltage of ",v.toString);
	writefln("requires a resistance of ",r.toString);
	writefln("and produces ",w.toString," of heat.");
	writefln("Total energy used in ",ti.toString," is ",e.toString);

	writef("\nCapacitor time curve:\n\n");
	
	Capacitance C = 0.47 * 1e-6 * farad; 	// Capacitance
	Voltage V0 = 5 * volt;			// Starting voltage
	Resistance R = 4.7 * 1e3 * ohm;		// Resistance

	for (Time t; t < 51 * 1e-3 * second; t += 1e-3 * second) {
		Voltage Vt = V0 * exp((-t / (R*C)).value);

		writefln("at %5s the voltage is %s",t.toString,Vt.toString);
	}
}
October 05, 2009
Rainer Deyke wrote:
> Boost.Units (C++) checks units at compile time.  There is no reason why
> D could not use the same approach.

Oskar's code I posted does it at compile time.
October 05, 2009
bearophile wrote:
> Denis Koroskin:
> 
>> I don't see any reason why if (someComplexNumber) { ... } should be a
> valid code, it hardly makes any sense for me.<
> 
> In general I think adding a boolean-evaluation standard method to D can be positive and handy and not that bug-prone.
> But complex numbers are FP, so you usually test if they are close to zero (test of exactly zero can be useful to know if a value was not changed, etc). So I agree with you that for complex numbers such boolarn-eveluation method isn't very useful.
> Once D has such operator, it can be defined for library complex numbers too, but probably it will not be used often.
> It's useful if you want to write generic code, so if in a templated function you use if(x){... it will work with integers, double, complex values, etc, without special casing.
> 

I'm not buying that. What kind of function would that be? I can't imagine a need for this.
October 05, 2009
downs:

> I'm not buying that. What kind of function would that be? I can't imagine a need for this.

I don't know, sorry.
But I'd like to have such method to define my collections as false when they are empty, this is really handy. And it may be useful to make nullable values false.

Bye,
bearophile
1 2 3 4 5 6 7 8
Next ›   Last »