write once type?
Steven Schveighoffer
schveiguy at gmail.com
Fri Apr 30 13:36:10 UTC 2021
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
More information about the Digitalmars-d-learn
mailing list