Thread overview
dual with statement
Jul 24, 2014
Jay Norwood
Jul 24, 2014
monarch_dodra
Jul 25, 2014
Jay Norwood
Jul 25, 2014
Jay Norwood
Jul 25, 2014
monarch_dodra
Jul 26, 2014
Jay Norwood
Jul 24, 2014
monarch_dodra
Jul 24, 2014
bearophile
July 24, 2014
I was playing around with use of the dual WITH statement.   I like the idea, since it makes the code within the with cleaner.   Also, I got the impression from one of the conference presentations ... maybe the one on the ARM debug ... that there are some additional optimizations available that the compiler processes the WITH statement block.

Anyway, a problem I ran into was if two structures had the same member names, for example struct ar.r and ar.psm in this case below.   In this case, there was no way for the compiler to determine from which structure to get the member.

void calc_per_sec_met(ref All ar){

       with (ar.r) with(ar.psm) {
              double per_sec = proc_cyc/ref_clock;
              d = (a+c)*per_sec;
              e = (c==0)?0:(a+b)/c;
       }
}

ok, so I guess I could make all the member names unique in the different structures, but that's kind of ugly.

Also, what happens if using two structs of the same type in a WITH statement.
Seems like something like this would help, which I believe I've seen used in database queries ...

 with (ar.r1 as r1) with (ar.r2 as r2){
   auto sum = r1.a + r2.a;
 }


July 24, 2014
On Thursday, 24 July 2014 at 17:19:36 UTC, Jay Norwood wrote:
> I was playing around with use of the dual WITH statement.   I like the idea, since it makes the code within the with cleaner.
>   Also, I got the impression from one of the conference presentations ... maybe the one on the ARM debug ... that there are some additional optimizations available that the compiler processes the WITH statement block.
>
> Anyway, a problem I ran into was if two structures had the same member names, for example struct ar.r and ar.psm in this case below.   In this case, there was no way for the compiler to determine from which structure to get the member.
>
> void calc_per_sec_met(ref All ar){
>
>        with (ar.r) with(ar.psm) {
>               double per_sec = proc_cyc/ref_clock;
>               d = (a+c)*per_sec;
>               e = (c==0)?0:(a+b)/c;
>        }
> }
>
> ok, so I guess I could make all the member names unique in the different structures, but that's kind of ugly.
>
> Also, what happens if using two structs of the same type in a WITH statement.
> Seems like something like this would help, which I believe I've seen used in database queries ...
>
>  with (ar.r1 as r1) with (ar.r2 as r2){
>    auto sum = r1.a + r2.a;
>  }

Just because "with" makes it that you don't have to be explicit, doesn't mean you can't:

struct S {
    int i;
    int k;
}
struct T {
    int j;
    int k;
}

void main()
{
    S s;
    T t;
    int sum;
    with (s) with (t) {
        sum = i + j + s.k + t.k;
    }
}

Or did I miss something?
July 24, 2014
On Thursday, 24 July 2014 at 17:19:36 UTC, Jay Norwood wrote:
> Anyway, a problem I ran into was if two structures had the same member names, for example struct ar.r and ar.psm in this case below.   In this case, there was no way for the compiler to determine from which structure to get the member.

From what I can observe, the compiler resolves the ambiguity by chosing the first match in terms of scope. Eg, there's shadowing. From my previous code:



with (t)
{
    writeln(k); //prints t.k
    with(s)
    {
        writeln(k); //prints s.k: it is now shadowing t.k
July 24, 2014
monarch_dodra:

> From what I can observe, the compiler resolves the ambiguity by chosing the first match in terms of scope. Eg, there's shadowing. From my previous code:
>
>
>
> with (t)
> {
>     writeln(k); //prints t.k
>     with(s)
>     {
>         writeln(k); //prints s.k: it is now shadowing t.k


A reduced test case:

void main() {
    static struct S { int k = 1; }
    static struct T { int k = 2; }
    S s;
    T t;
    with (t) {
        assert(k == 2);
        with(s) {
            assert(k == 1);
        }
    }
}


Is this a failure (a bug) of the anti-hijacking mechanism of with()?

Bye,
bearophile
July 25, 2014
On Thursday, 24 July 2014 at 20:16:53 UTC, monarch_dodra wrote:
>
> Or did I miss something?

Yes, sorry, I should have pasted a full example previously. The code at the end is with the Raw_met members renamed (they were originally a and b but clashed).

So, if Raw_met members were still a and b ...
  with(ar.r as v) with (ar.rm as res){
     res.a = v.a + v.c;
     res.b = (v.c==0)? 0: (v.a + v.b)/ v.c;

I don't recall the exact use case for the database expressions, but I believe they were substituting a simple symbol for the fully qualified object. So they would have done something analogous to this ...

  with (ar.rm.a as d) with (ar.rm.b as e) with (ar.r.a as a) with (ar.r.b as b) with (ar.r.c as c){
     d = a + c;
     e = (c==0)?0:(a+b)/c;
}

So, the expressions are simpler to read, and I've fully qualified the members only a single time.



----  this is the code for one of the metric experiments, with the members renamed to avoid the clashes.  I like that the expressions can be so simple.

double ref_clock=1_600_000_000.0;
struct Raw_met {long d; double e;}
struct Per_sec_met {double d; double e; }
struct Per_cyc_met {double d; double e; }


struct Raw {long proc_cyc; long a; long b; long c; }
struct Per_sec {double proc_cyc; double a; double b; double c; }
struct Per_cyc {double proc_cyc; double a; double b; double c; }
struct All { Raw r; Per_sec ps; Per_cyc pc; Raw_met rm; Per_sec_met psm; Per_cyc_met pcm;}


void calc_raw_met(ref All ar){
       with(ar.r) with(ar.rm){
         d = a+c;
         e = (c==0)?0:(a+b)/c;
       }
}

July 25, 2014
On Friday, 25 July 2014 at 01:54:53 UTC, Jay Norwood wrote:
> I don't recall the exact use case for the database expressions, but I believe they were substituting a simple symbol for the fully qualified object.

The sql with clause is quite a bit different than I remembered.  For one thing, I have the order reversed, so it would have been with (a as something.x.y).

It looks more like they are more like creating a temporary tuple from some more complicated selection.  It isn't clear what the implementation is, but just the that it might be a more concise way of stating things so that the expressions inside the body can be simple

So, my prior example
  with (ar.rm.a as d) with (ar.rm.b as e) with (ar.r.a as a) with
(ar.r.b as b) with (ar.r.c as c){
     d = a + c;
     e = (c==0)?0:(a+b)/c;
}


would reduce to something maybe simpler to read.  The sql seems to be using this as a foreach type operation, but I was just interested in the name substitution so that the expressions inside the with block could be simpler, as well as get rid of the struct member name clashes.

with ( (d,e,a,b,c) as (ar.rm.a, ar.rm.b, ar.r.a, ar.r.b, ar.r.c)){
     d = a + c;
     e = (c==0)?0:(a+b)/c;
}
July 25, 2014
On Friday, 25 July 2014 at 01:54:53 UTC, Jay Norwood wrote:
> On Thursday, 24 July 2014 at 20:16:53 UTC, monarch_dodra wrote:
>>
>> Or did I miss something?
>
> Yes, sorry, I should have pasted a full example previously. The code at the end is with the Raw_met members renamed (they were originally a and b but clashed).
>
> So, if Raw_met members were still a and b ...
>   with(ar.r as v) with (ar.rm as res){
>      res.a = v.a + v.c;
>      res.b = (v.c==0)? 0: (v.a + v.b)/ v.c;
>
> I don't recall the exact use case for the database expressions, but I believe they were substituting a simple symbol for the fully qualified object. So they would have done something analogous to this ...

Isn't:
with(foo.bar as baz) { ... }

Functionally nothing more than an alias? EG:
{
    alias baz = foo.bar;
    ...
}

Or mix of both. I don't see a need for "as".
July 26, 2014
On Friday, 25 July 2014 at 21:10:56 UTC, monarch_dodra wrote:
> Functionally nothing more than an alias? EG:
> {
>     alias baz = foo.bar;
>     ...
> }
>

Yes, it is all just alias.  So

with ( (d,e,a,b,c) as (ar.rm.a, ar.rm.b, ar.r.a, ar.r.b, ar.r.c)){
     d = a + c;
     e = (c==0)?0:(a+b)/c;
}

could be instead

{
  alias d = ar.rm.a;
  alias e = ar.rm.b;
  alias a = ar.r.a;
  alias b = ar.r.b;
  alias c = ar.r.c;

  d = a + c;
  e = (c==0)?0:(a+b)/c;

}

I guess this means I don't need WITH.