www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Units of Measurement Library: units-d

reply =?UTF-8?B?Tm9yZGzDtnc=?= <per.nordlow gmail.com> writes:
I've put David Nadlinger work together with my tweaks on top at

https://github.com/nordlow/units-d

to make it easier to experiment with.

PR are very welcome.
Mar 31 2016
next sibling parent reply ag0aep6g <anonymous example.com> writes:
On 01.04.2016 01:58, Nordlöw wrote:
 https://github.com/nordlow/units-d
From there:
  * Example:
  * ---
  * alias BaseUnit!("Ampere", "A") Ampere;
  * enum ampere = Ampere.init;
  * // or
  * enum ampere = baseUnit!("Ampere", "A");
  * ---
I dislike that the type depends only on the given name. This effectively means that the names are in a global namespace. For example: ---- import experimental.units; struct A { alias BaseUnit!("Ampere", "A") Ampere; enum ampere = Ampere.init; } struct B { alias BaseUnit!("Ampere", "A") Ampere; enum ampere = Ampere.init; } ---- A.Ampere and B.Ampere are the same type here. I think it would be more useful if they weren't. When two unrelated sources define a new unit with the same name, then they shouldn't be compatible. Think of all the different kinds of pounds and miles there used to be in the world. I can't think of a truly nice way to accomplish this, though. As far as I see, it needs a mixin of some kind. Like this, for example: ---- enum string baseUnit = q{ { static struct BaseUnit {/* ... */} return BaseUnit.init; }() }; struct A { enum ampere = mixin(baseUnit); } struct B { enum ampere = mixin(baseUnit); } static assert(!is(typeof(A.ampere) == typeof(B.ampere))); ----
Apr 01 2016
parent reply Simen Kjaeraas <simen.kjaras gmail.com> writes:
On Friday, 1 April 2016 at 19:03:03 UTC, ag0aep6g wrote:
 I dislike that the type depends only on the given name. This 
 effectively means that the names are in a global namespace.
[snip]
 I can't think of a truly nice way to accomplish this, though. 
 As far as I see, it needs a mixin of some kind.
The usual way to fix it would be to include __FILE__ and __LINE__ in the template arguments: // In units/package.d: struct BaseUnit(string name, string symbol = null, string file = __FILE__, size_t line = __LINE__) { // ... } // in foo.d: import experimental.units; struct A { // Actual type is BaseUnit!("Ampere", "A", "foo", 5): alias BaseUnit!("Ampere", "A") Ampere; enum ampere = Ampere.init; } struct B { // Actual type is BaseUnit!("Ampere", "A", "foo", 12): alias BaseUnit!("Ampere", "A") Ampere; enum ampere = Ampere.init; } void main() { assert(!is(B.Ampere == A.Ampere)); } -- Simen
Apr 01 2016
parent reply ag0aep6g <anonymous example.com> writes:
On 01.04.2016 22:59, Simen Kjaeraas wrote:
 The usual way to fix it would be to include __FILE__ and __LINE__ in the
 template arguments:
Right, no mixin this way. I wouldn't call this "truly nice", though. It depends on code formatting to work. Put everything on one line and it breaks. Significant whitespace is a pain when generating code. Though this is not nearly as bad as significant indentation, of course. __FILE__ also kind of breaks separate compilation. All object files have to be compiled from the same directory. Otherwise __FILE__ will be different. __LINE__ has a similar (maybe even more obscure) issue. Add or remove a newline before compiling dependent modules and things break. Usually, one recompiles all dependents when a dependency changes, but a significant newline, really?
Apr 01 2016
parent reply Simen Kjaeraas <simen.kjaras gmail.com> writes:
On Friday, 1 April 2016 at 21:46:35 UTC, ag0aep6g wrote:
 On 01.04.2016 22:59, Simen Kjaeraas wrote:
 The usual way to fix it would be to include __FILE__ and 
 __LINE__ in the
 template arguments:
Right, no mixin this way. I wouldn't call this "truly nice", though. It depends on code formatting to work. Put everything on one line and it breaks. Significant whitespace is a pain when generating code. Though this is not nearly as bad as significant indentation, of course. __FILE__ also kind of breaks separate compilation. All object files have to be compiled from the same directory. Otherwise __FILE__ will be different. __LINE__ has a similar (maybe even more obscure) issue. Add or remove a newline before compiling dependent modules and things break. Usually, one recompiles all dependents when a dependency changes, but a significant newline, really?
I kinda agree. And looking at https://dlang.org/spec/traits.html, I see there's __MODULE__, which would probably be a better choice than __FILE__. As for __LINE__, what we'd want is basically something like __CONTEXT__, which doesn't exist, but might be the .mangleof of the surrounding scope: struct S(string ctx = __CONTEXT__) { pragma(msg, ctx); } S!() a; // "3foo" void bar() { S!() b; // "_D3foo3barFZv" } struct S2 { S!() c; // "S3foo2S2" void baz() { S!() d; // "_D3foo2S23bazMFZv" } } That'd remove the problem of significant whitespace. In fact, it'd also eliminate the need for __MODULE__ in this case. Still though, that's not enough if we want this to work: void foo() { alias a = Foo!(); alias b = Foo!(); assert(!isSame!(a, b)); } We could also add __COLUMN__, which would be the horizontal index of the instantiation's beginning: foo(3, Bar!3.baz); // ^Here. Position 11. Next problem: void main() { pragma(msg, __LINE__); mixin("pragma(msg, __LINE__);\npragma(msg, __LINE__);"); pragma(msg, __LINE__); } That prints '4' twice - once for the actual line 4, the other for the second line of the mixin. However, __FILE__ is different, so I guess __CONTEXT__ could also be. -- Simen
Apr 01 2016
next sibling parent reply Meta <jared771 gmail.com> writes:
On Friday, 1 April 2016 at 22:54:53 UTC, Simen Kjaeraas wrote:
 On Friday, 1 April 2016 at 21:46:35 UTC, ag0aep6g wrote:
 On 01.04.2016 22:59, Simen Kjaeraas wrote:
 The usual way to fix it would be to include __FILE__ and 
 __LINE__ in the
 template arguments:
Right, no mixin this way. I wouldn't call this "truly nice", though. It depends on code formatting to work. Put everything on one line and it breaks. Significant whitespace is a pain when generating code. Though this is not nearly as bad as significant indentation, of course. __FILE__ also kind of breaks separate compilation. All object files have to be compiled from the same directory. Otherwise __FILE__ will be different. __LINE__ has a similar (maybe even more obscure) issue. Add or remove a newline before compiling dependent modules and things break. Usually, one recompiles all dependents when a dependency changes, but a significant newline, really?
I kinda agree. And looking at https://dlang.org/spec/traits.html, I see there's __MODULE__, which would probably be a better choice than __FILE__. As for __LINE__, what we'd want is basically something like __CONTEXT__, which doesn't exist, but might be the .mangleof of the surrounding scope: struct S(string ctx = __CONTEXT__) { pragma(msg, ctx); } S!() a; // "3foo" void bar() { S!() b; // "_D3foo3barFZv" } struct S2 { S!() c; // "S3foo2S2" void baz() { S!() d; // "_D3foo2S23bazMFZv" } } That'd remove the problem of significant whitespace. In fact, it'd also eliminate the need for __MODULE__ in this case. Still though, that's not enough if we want this to work: void foo() { alias a = Foo!(); alias b = Foo!(); assert(!isSame!(a, b)); } We could also add __COLUMN__, which would be the horizontal index of the instantiation's beginning: foo(3, Bar!3.baz); // ^Here. Position 11. Next problem: void main() { pragma(msg, __LINE__); mixin("pragma(msg, __LINE__);\npragma(msg, __LINE__);"); pragma(msg, __LINE__); } That prints '4' twice - once for the actual line 4, the other for the second line of the mixin. However, __FILE__ is different, so I guess __CONTEXT__ could also be. -- Simen
What is needed is Lisp's gensym construct.
Apr 01 2016
parent Simen Kjaeraas <simen.kjaras gmail.com> writes:
On Saturday, 2 April 2016 at 01:19:45 UTC, Meta wrote:
 What is needed is Lisp's gensym construct.
That's basically what I said, no? :p One problem of lisp's gensym (if we were to use it in D) is that it's simply a monotonically increasing number with a global prefix. It's perfect for the language it's in, and all but useless in D. For this very reason, I have made a stab at implementing __GENSYM__ in D. It follows basically the ideas I outlined above, and spits out a string on the form MANGLE_#, with # being a counter for the given mangled name: module bar; struct Ham(string gensym = __GENSYM__) { pragma(msg, gensym); } struct Eggs(string gensym = __GENSYM__) { pragma(msg, gensym); } // =========================== module foo; import bar; pragma(msg, __GENSYM__); // 3foo_1 void main() { pragma(msg, __GENSYM__); // _Dmain_1 Ham!() a; // _Dmain_3bar_1 Ham!() b; // _Dmain_3bar_2 assert(!is(typeof(a) == typeof(b))); Eggs!() c; // _Dmain_3bar_3 S2!() d; // _Dmain_3foo_1 } struct Qux { pragma(msg, __GENSYM__); // 3foo3Qux_1 void baz() { pragma(msg, __GENSYM__); // _D3foo3Qux3bazMFZv_1 Ham!() a; // _D3foo3Qux3bazMFZv_3bar_1 } } struct S2(string gensym = __GENSYM__) { pragma(msg, gensym); } Should I file an enhancement for this? -- Simen
Apr 04 2016
prev sibling parent crimaniak <crimaniak gmail.com> writes:
On Friday, 1 April 2016 at 22:54:53 UTC, Simen Kjaeraas wrote:

...
 I kinda agree. And looking at 
 https://dlang.org/spec/traits.html, I see there's __MODULE__, 
 which would probably be a better choice than __FILE__.
I think adding something like __UNIQUE_NAME__ to predefined constants will allow to avoid all these perversions. The only thing to think here about uniqueness scope.
Apr 02 2016
prev sibling parent Jack Stouffer <jack jackstouffer.com> writes:
On Thursday, 31 March 2016 at 23:58:54 UTC, Nordlöw wrote:
 I've put David Nadlinger work together with my tweaks on top at

 https://github.com/nordlow/units-d

 to make it easier to experiment with.

 PR are very welcome.
Nice work. I have yet to play around with it, but this is definitely going to need pre-made symbols for the United States customary system like SI has before it goes into Phobos.
Apr 01 2016