June 04, 2014
On Wednesday, 4 June 2014 at 17:06:22 UTC, Meta wrote:
> On Wednesday, 4 June 2014 at 15:51:58 UTC, John Colvin wrote:
>> Assuming hours, minutes and seconds are already declared, you can do this already
>>
>> TypeTuple!(hours, minutes, seconds) = dur.parts;
>>
>> A full working example of the syntax:
>>
>>
>> import std.typetuple;
>> import std.typecons;
>> import std.stdio;
>>
>> void main()
>> {
>> 	int a,b;
>> 	TypeTuple!(a, b) = tuple(5, 8);
>> 	assert(a == 5 && b == 8);
>> }
>
> *Assuming they're already declared* is the thing to note. There's little point in a tuple destructuring syntax if you have to declare the variables beforehand anyway.

I would say it's still quite useful, but I agree it's not ideal.
June 05, 2014
On Wed, 04 Jun 2014 09:12:06 +0200
Sönke Ludwig via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> Just a minor note: What about just .only!"minutes", analogous .total!"minutes"? Removing both the .minutes shortcut and the short "get" method, pretty heavily increases verbosity, so shortening "getOnly" might be a good idea.

Actually, after some further discussion, I think that we've decided to remove get/getOnly entirely. Instead, we'll have a function called split which splits the Duration among the units that you request (rather than just one).  I'll be updating the current pull request with those changes shortly, so we may not end up with exactly what I have at the moment, but these are the currently proposed documentation examples for split:

{
    auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
    long days;
    int seconds;
    short msecs;
    d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
    assert(days == 12);
    assert(seconds == 7 * 60);
    assert(msecs == 501);

    auto splitStruct = d.split!("days", "seconds", "msecs")();
    assert(splitStruct.days == 12);
    assert(splitStruct.seconds == 7 * 60);
    assert(splitStruct.msecs == 501);

    auto fullSplitStruct = d.split();
    assert(fullSplitStruct.weeks == 1);
    assert(fullSplitStruct.days == 5);
    assert(fullSplitStruct.hours == 0);
    assert(fullSplitStruct.minutes == 7);
    assert(fullSplitStruct.seconds == 0);
    assert(fullSplitStruct.msecs == 501);
    assert(fullSplitStruct.usecs == 223);
    assert(fullSplitStruct.hnsecs == 0);

    assert(d.split!"minutes"().minutes == d.total!"minutes");
}

{
    auto d = dur!"days"(12);
    assert(d.split!"weeks"().weeks == 1);
    assert(d.split!"days"().days == 12);

    assert(d.split().weeks == 1);
    assert(d.split().days == 5);
}

{
    auto d = dur!"days"(7) + dur!"hnsecs"(42);
    assert(d.split!("seconds", "nsecs")().nsecs == 4200);
}

I think that it will be a definite improvement.

- Jonathan M Davis

June 05, 2014
On Thu, Jun 05, 2014 at 01:23:47AM -0700, Jonathan M Davis via Digitalmars-d wrote:
> On Wed, 04 Jun 2014 09:12:06 +0200
> Sönke Ludwig via Digitalmars-d <digitalmars-d@puremagic.com> wrote:
> 
> > Just a minor note: What about just .only!"minutes", analogous .total!"minutes"? Removing both the .minutes shortcut and the short "get" method, pretty heavily increases verbosity, so shortening "getOnly" might be a good idea.
> 
> Actually, after some further discussion, I think that we've decided to remove get/getOnly entirely. Instead, we'll have a function called split which splits the Duration among the units that you request (rather than just one).  I'll be updating the current pull request with those changes shortly, so we may not end up with exactly what I have at the moment, but these are the currently proposed documentation examples for split:
> 
> {
>     auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
>     long days;
>     int seconds;
>     short msecs;
>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>     assert(days == 12);
>     assert(seconds == 7 * 60);
>     assert(msecs == 501);
[...]

Very nice! I like this. It looks very D-ish, and very idiomatic.

It also solves an API problem that I've encountered before, where a database wrapper module needs to allow client code to query some data from a database, but the client code needs the flexibility to select (ha!) which fields to include in the result because of performance: there are many columns and the number of rows returned may be a large number. Using compile-time field lists like you did here is an excellent way to solve this problem, since you don't have to introduce extra indirection, but you can bind the database columns to output fields at compile-time for maximum performance.


T

-- 
Старый друг лучше новых двух.
June 05, 2014
On Thu, 05 Jun 2014 07:18:59 -0700, H. S. Teoh via Digitalmars-d wrote:

> On Thu, Jun 05, 2014 at 01:23:47AM -0700, Jonathan M Davis via Digitalmars-d wrote:
>> 
>> {
>>     auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
>>     long days;
>>     int seconds;
>>     short msecs;
>>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>>     assert(days == 12);
>>     assert(seconds == 7 * 60);
>>     assert(msecs == 501);
> [...]
> 
> Very nice! I like this. It looks very D-ish, and very idiomatic.

if only we could avoid the quotes, would a enum array work?
d.split![days, second, msecs](...)
June 05, 2014
On Wednesday, 4 June 2014 at 15:51:58 UTC, John Colvin wrote:
> On Wednesday, 4 June 2014 at 14:16:31 UTC, Meta wrote:
>> On Wednesday, 4 June 2014 at 11:28:52 UTC, Kagamin wrote:
>>> Does one really needs only one component, but not the others? Maybe it should provide full computed broken form instead of separate components?
>>>
>>> auto d=dur.breakUp;
>>> d.hours; d.minutes; d.seconds;
>>
>> In some glorious future where we can destructure tuples, you could do something like this:
>>
>> (hours, minutes, seconds) = dur.parts;
>
> Assuming hours, minutes and seconds are already declared, you can do this already
>
> TypeTuple!(hours, minutes, seconds) = dur.parts;
>
> A full working example of the syntax:
>
>
> import std.typetuple;
> import std.typecons;
> import std.stdio;
>
> void main()
> {
> 	int a,b;
> 	TypeTuple!(a, b) = tuple(5, 8);
> 	assert(a == 5 && b == 8);
> }

On Wednesday, 4 June 2014 at 14:16:31 UTC, Meta wrote:
> In some glorious future where we can destructure tuples, you could do something like this:
>
> (hours, minutes, seconds) = dur.parts;

In the most glorious of futures where D supports over-powered macros, a macro `def` could be defined s.t.

    def(hours, minutes, seconds) = dur.parts;

results in

    typeof(dur.parts)[0] hours;
    typeof(dur.parts)[1] minutes;
    typeof(dur.parts)[2] seconds;
    TypeTuple!(hours,minutes,seconds) = dur.parts;

Along with a huge number of other possible/desired "language features" could be made without actually touching the compiler.

Of course, I know macros aren't ever coming, but I'm just sayin' ... :)
June 05, 2014
On 06/05/14 16:18, H. S. Teoh via Digitalmars-d wrote:
> On Thu, Jun 05, 2014 at 01:23:47AM -0700, Jonathan M Davis via Digitalmars-d wrote:
>> Actually, after some further discussion, I think that we've decided to remove get/getOnly entirely. Instead, we'll have a function called split which splits the Duration among the units that you request (rather than just one).  I'll be updating the current pull request with those changes shortly, so we may not end up with exactly what I have at the moment, but these are the currently proposed documentation examples for split:
>>
>> {
>>     auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
>>     long days;
>>     int seconds;
>>     short msecs;
>>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>>     assert(days == 12);
>>     assert(seconds == 7 * 60);
>>     assert(msecs == 501);
> [...]
> 
> Very nice! I like this. It looks very D-ish, and very idiomatic.

I'd say it is very C-ish and very unidiomatic.

Why? Well, compare with:

   struct D {
      // In real code these methods would do the work [1]:
      long days() @property { return 2012; }
      int seconds() @property { return 34; }
      short msecs() @property { return 567; }

      auto split(string FIELDS)() @property {
         static struct Result {
            mixin(FIELDS.splitter(',').map!q{`typeof(D.`~stripLeft(a)~") "~a~";\n"}().join());
         }
         return mixin(`Result(`~FIELDS~`)`);
      }
   }

   void main() {
      auto d = D();
      auto r = d.split!q{ days, seconds, msecs };
      import std.stdio;
      writeln(r, r.days, r.seconds, r.msecs);
   }

No unnecessary declarations and redundancy.

For cases where the target is already predeclared, a pseudo-destructuring syntax can also be used:

   template destr(A...) { void destr(S)(S s) @property { A = s.tupleof; } }

   void main() {
      long days;
      int seconds;
      short msecs;
      auto d = D();
      destr!(days, seconds, msecs) = d.split!q{ days, seconds, msecs };
      import std.stdio;
      writeln(days, seconds, msecs);
   }


Note that I have never even used std.datetime [1] and don't plan to; please ignore this when deciding its API. I'm just saying that encouraging that kind of return-by-weakly-typed-pointers-with-string-selectors interfaces is /not/ a good idea; there are other, much better, options in D.

artur

[1] Of course in real code the `split` implementation would probably use
    an intermediate struct to hold common state that is used while calculating
    the result. Also for namespace reasons. But that's just a caller-invisible
    implementation detail.

[2] other than as input for parsing benchmarks. :)
June 05, 2014
On Thursday, 5 June 2014 at 08:49:18 UTC, Jonathan M Davis via Digitalmars-d
>     long days;
>     int seconds;
>     short msecs;
>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);

Please don't use pass-by-pointer in D APIs. It makes it a real *nightmare* to ever use the code in a safe context. Besides, we have ref. The only arguments "for" pass by pointer afaik are:
- retain existing/C api (1)
- allow null pointers   (2)

(1) is not applicable, I think.
(2) would only make sense if split did not have a template parameter, and took "all" arguments, and only filled the non-null ones.

So, please make these pass by ref.
June 05, 2014
On Thu, 05 Jun 2014 17:54:49 -0400, Artur Skawina via Digitalmars-d <digitalmars-d@puremagic.com> wrote:

> On 06/05/14 16:18, H. S. Teoh via Digitalmars-d wrote:
>> On Thu, Jun 05, 2014 at 01:23:47AM -0700, Jonathan M Davis via Digitalmars-d wrote:
>>> Actually, after some further discussion, I think that we've decided to
>>> remove get/getOnly entirely. Instead, we'll have a function called
>>> split which splits the Duration among the units that you request
>>> (rather than just one).  I'll be updating the current pull request
>>> with those changes shortly, so we may not end up with exactly what I
>>> have at the moment, but these are the currently proposed documentation
>>> examples for split:
>>>
>>> {
>>>     auto d = dur!"days"(12) + dur!"minutes"(7) + dur!"usecs"(501223);
>>>     long days;
>>>     int seconds;
>>>     short msecs;
>>>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>>>     assert(days == 12);
>>>     assert(seconds == 7 * 60);
>>>     assert(msecs == 501);
>> [...]
>>
>> Very nice! I like this. It looks very D-ish, and very idiomatic.
>
> I'd say it is very C-ish and very unidiomatic.
>
> Why? Well, compare with:
>
>    struct D {
>       // In real code these methods would do the work [1]:
>       long days() @property { return 2012; }
>       int seconds() @property { return 34; }
>       short msecs() @property { return 567; }
>
>       auto split(string FIELDS)() @property {
>          static struct Result {
>             mixin(FIELDS.splitter(',').map!q{`typeof(D.`~stripLeft(a)~") "~a~";\n"}().join());
>          }
>          return mixin(`Result(`~FIELDS~`)`);
>       }
>    }
>
>    void main() {
>       auto d = D();
>       auto r = d.split!q{ days, seconds, msecs };
>       import std.stdio;
>       writeln(r, r.days, r.seconds, r.msecs);
>    }
>
> No unnecessary declarations and redundancy.

auto r = d.split!("days", "seconds", "msecs")();
writeln(r, r.days, r.seconds, r.msecs);

> For cases where the target is already predeclared, a pseudo-destructuring
> syntax can also be used:
>
>    template destr(A...) { void destr(S)(S s) @property { A = s.tupleof; } }
>
>    void main() {
>       long days;
>       int seconds;
>       short msecs;
>       auto d = D();
>       destr!(days, seconds, msecs) = d.split!q{ days, seconds, msecs };
>       import std.stdio;
>       writeln(days, seconds, msecs);
>    }

This requires odd machinery. Most people aren't used to writing code this way, and it would be difficult to explain. It's also not much different than the example above, and requires the compiler to inline a whole bunch of stuff in order to be efficient. Simple pointers to targets works very well. readf and getopt work this way, and are very effective.

> Note that I have never even used std.datetime [1] and don't plan to; please
> ignore this when deciding its API. I'm just saying that encouraging that kind
> of return-by-weakly-typed-pointers-with-string-selectors interfaces is /not/
> a good idea; there are other, much better, options in D.

Respectfully disagree, the API looks very good to me. And decidedly not C-like.

-Steve
June 05, 2014
On Thu, 05 Jun 2014 18:06:01 -0400, monarch_dodra <monarchdodra@gmail.com> wrote:

> On Thursday, 5 June 2014 at 08:49:18 UTC, Jonathan M Davis via Digitalmars-d
>>     long days;
>>     int seconds;
>>     short msecs;
>>     d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>
> Please don't use pass-by-pointer in D APIs. It makes it a real *nightmare* to ever use the code in a safe context.

This is similar to getopt and readf. I think it's a good way to show that a reference is being passed.

But you are right, you are not allowed to take addresses of locals in safe code. It looks decidedly less nice than pointers IMO.

-Steve
June 05, 2014
On Thursday, 5 June 2014 at 22:06:02 UTC, monarch_dodra wrote:
> On Thursday, 5 June 2014 at 08:49:18 UTC, Jonathan M Davis via Digitalmars-d
>>    long days;
>>    int seconds;
>>    short msecs;
>>    d.split!("days", "seconds", "msecs")(&days, &seconds, &msecs);
>
> Please don't use pass-by-pointer in D APIs. It makes it a real *nightmare* to ever use the code in a safe context. Besides, we have ref. The only arguments "for" pass by pointer afaik are:
> - retain existing/C api (1)
> - allow null pointers   (2)
>
> (1) is not applicable, I think.
> (2) would only make sense if split did not have a template parameter, and took "all" arguments, and only filled the non-null ones.
>
> So, please make these pass by ref.

Even better than ref would be out which guarantees that the input parameter values do not affect the function.