On 03/29/2011 03:49 PM, Cristi Cobzarenco wrote:
To David:
Ok, right now, I got two working versions, one sorting by .mangleof and one
performing a double-inclusion test on the tuples. Both work, I can't see any
performance increase in the .mangleof one, but if .mangleof returns unique
string, I say we use it this way.
Regarding my string little DSL. I have 3 solutions right now:
1. Drop the DSL altogether, right now my system would work perfectly fine
with boost-like tuples (a list of units alternating with exponents):
Quantity!(Metre,1,Second,-1) speed = distance/time;
While less readable, this doesn't have the disadvantages of the following 2.

2. Use a mixin template to declare the expression parser in the current
scope:
mixin DeclareExprQuantity!();

struct Metre {}
struct Second {}
struct Kg {}

void f() {
        ExprQuantity!("Metre/Second * Kg^-1") q = speed / mass;
}
This works, is readable, but it uses C-preprocessor like behaviour (read:
black vodoo) - a library declaring something in your scope isn't very nice.

3. Abandon using types as units and just use strings all the way. This
doesn't guarantee unit name uniqueness and a misspelled unit name is a new
unit. One could use an algorithm to convert all strings to a cannonical form
(like Andrei suggested) and then use string equality for unit equality.

What do you think, I'm personally quite divided:
1. I like that this is simple and it works. It make writing derived units
unnatural though.
2. I actually like this one, despite the obvious ugliness. It's just one
extra line at the beginning of your code and you can the use arithmetic
operations and use type-uniqueness to guarantee unit-uniqueness.
3. This is a bit dangerous. It works very well as long as there isn't more
than one system of units. I still like it a bit.

Have you considered
0. Derived units are declared?

After all, relative to the size of an app, and the amount of work it represents, declaring actually used derived units is very a small burden.

This means instead of:

    struct meter {}
    struct second {}

    auto dist = Quantity!"meter"(3.0);
    auto time = Quantity!"second"(2.0);
    auto speed = Quantity!"meter/second"(dist/time);
    auto surface = Quantity!"meter2"(dist*dist);

one would write:

    struct meter {}
    struct second {}
    alias FractionUnit!(meter,second) meterPerSecond;
    alias PowerUnit!(meter,2) squareMeter;

    auto dist = Quantity!meter(3.0);
    auto time = Quantity!second(2.0);
    auto speed = Quantity!meterPerSecond(dist/time);
    auto surface = Quantity!squareMeter(dist*dist);

This means you use struct templates as unit-id factories, for user's convenience. The constructor would then generate the metadata needed for unit-type checking, strored on the struct itself (this is far more easily using such struct templates than by parsing a string).
In addition to the 2 struct templates above, there should be
    struct ProductUnit(Units...) {...}
(accepting n base units); and I guess that's all, isn't it?
The only drawback is that very complicated derived units need be constructed step by step. But this can also be seen as an advantage. An alternative may be to have a single, but more sophisticated and more difficult to use, struct template.

I find several advantages to this approach:
* Simplicity (also of implementation, I guess).
* Unit identifiers are structs all along (both in code and in semantics).
* No string mixin black voodoo.

I guess even if this is not ideal, you could start with something similar, because it looks easier and cleaner (to me).

A similar system may be used for units of diff scales in the same dimension:
    alias ScaleUnit!(mm,1_000_000) km;

By the way, have you considered unit-less (pseudo-)magnitudes (I mean ratios, including %). I would have one declared and exported as constant. then,
    alias ScaleUnit!(voidUnit,0.001) perthousand;


To Don:
* Choosing one unit and using it is still a very good idea. As I said there
are to be no implicit conversions, so this system would ensure you don't, by
mistake, adhere to this convention. Also, if somebody else uses your library
maybe they assume everything is in meters when in fact you use milimeters.
Sure they should check the documentation, but it's better if they get a nice
error message "Inferred unit Meter doesn't match expected Milimeter", or
something like that.

I agree with this.

Denis
--
_________________
vita es estrany
spir.wikidot.com

Reply via email to