On 4/30/21 9:24 AM, sighoya wrote:
On Friday, 30 April 2021 at 01:30:54 UTC, Steven Schveighoffer wrote:

In my case, for value of a certain type in the loop, I was storing a specific field from the first one I found, and then verifying that all the other values of that type (not exactly the same type, but similar) had the same value for that field, otherwise it was an error.

I could have done it in 2 loops, but it's wasteful.

I have problems to grok exactly what you're talking about, can you provide some neat and small example for this?



I'll just show you the code here. This is from my (up and coming) sql builder project.

A `ColumnDef!T` is an sql table column of type `T`, which contains an expression describing the column, and a table definition of where the column comes from. `TableDef` is const inside the column def:

```d
struct ColumnDef(T)
{
    const TableDef table;
    ExprString expr;
    alias type = T;
}
```

Now, what if you wanted a "computed" column? that is, you wanted to define a column with a type, but that is computed from other columns? Like `select total - tax as netcost from sometable`

What I want to create is something that returns a ColumnDef from an arbitrary expression. But there is only one table definition, so if you want to return a ColumnDef, you need to ensure there is only one source table. So here is my code that does that:

```d
ColumnDef!T exprCol(T, Args...)(Args args)
{
    // first, find all columns, and ensure that table defs are all from the
    // same table (a ColumnDef cannot have multiple tables).
    const(TableDef)* tabledef;
    foreach(ref arg; args)
    {
        static if(is(typeof(arg) == ColumnDef!U, U))
        {
            if(tabledef && arg.table != *tabledef)
throw new Exception("can't have multiple tabledefs in the expression");
            else
                tabledef = &arg.table;
        }
    }

    assert(tabledef !is null);

    // build the expr string
    ExprString expr;
    foreach(ref a; args)
    {
        static if(is(typeof(a) == string))
            expr ~= a;
        else
            expr ~= a.expr;
    }
    return ColumnDef!(T)(*tabledef, expr);
}
```

The pointer abstraction works perfectly, but if there was no way to use that abstraction, there aren't any D facilities to allow this. It's really tail-const that I need.

I could have looped 2x over the args, and used an inner function to fetch the first one (or maybe used a staticIndexOf to get the first ColumnDef thing), and a second loop to verify all the remaining args have the same table def, but this loop works just as designed and is super-readable.

-Steve

Reply via email to