Uniform syntax for compile-time expressions in D
Most examples are real templates taken from Doost library: www.dsource.org/projects/doost/
This is
slightly modified version of my change
proposal:
http://d.puremagic.com/issues/show_bug.cgi?id=1827
Proposed syntax:
ctexpr (bool) : (T [S1 S2 ... Sn] [ ':' | '==' inexpr] ) | ct_bool_value
inexpr (bool) : pattern | pattern if (ctexpr) | if(ctexpr)
pattern: type | derived data type
Description:
T type identifier
S1..Sn introduced types
ct_bool_value compile time true or false
: direct or indirect type of ... (in case of value types: is implicitly convertible)
== is exact type of ...
derived data type e.g. S[] S[N = size_t] , E[K], E[int], class, typedef, int, MyType!(int), TheirType
Passing by alias, default type, default type and value examples are not taken into consideration in above syntax description. Examples for these case are in table below.
ctexpr and pattern evaluates to true or false
Both pattern and ctexpr must be true, to match template function during instantiation
Introduced symbols in pattern are aliased with concrete types when evaluating ctexpr
Symbols can have
fixed types. If reasonable when evaluating pattern symbols can have
also value e.g.:
void changeElement(T U N : U[N=uint]
if(N>100))(T array, U value, int index);
Above template
function matches all static arrays bigger than 100; N - number of
declared elements in s. array; N is binded to value of type uint.
Parts of ctexpr
can be omitted, so it looks exactly like current declarations
e.g.:
string stringize(T : bool)(bool
value); // omitted symbols and ctexpr
string stringize(T)(T
value); // omitted symbols, ":" and inexpr
Initial T can not be
redefined; currently it is rather confusing that elephant transforms
into monkey in following:
string stringize(T : T[])(T value);
//what should be passed to function? array or array element?
it
should be rather:
string stringize(T U : U[])(T value); //now
everything is clear
Following definition
with three template arguments:
void parse(T E : E[], U :
bool, V E N : E[N] if(N>100))(T array, U flag, V sarray);
should
be just syntactic sugar for:
void parse(T E : E[] &&
U : bool && V E N : E[N] if (N>100))(T array, U flag, V
sarray) ;
Above is very complicated case which would be
possible, but currently it is not. Simple cases still stay simple as
it is now.
... is() for metaprogramming can be dropped.
It is an error if defined symbols are not used in inexpr or don't have assigned types in ctexpr
If inexpr is
not defined T is aliased to all given symbols
Template function
resolution (my guess that it would be possible). When resolving
template function name it might be possible to relay on ctexpr
resulting value. If compile-time time expression returns true, then
there is a match. In such a case it would be possible to create
templ. functions:
S
toupper(isSomeString!(S))(S input)
Although there
should be probably more calculations to know which function is more
specialized.
With above proposal there can be only one syntax for: static if(), template (function) definition & static assert() & alias while is() for metaprogramming can be safely dropped. This syntax is consistent & extensible so it will allow to achieve much more.
Uniform syntax by example:
Template (function) compile-time arguments:
Old |
New |
Comment |
---|---|---|
Template function compile-time arguments: |
||
template normalizedType(T) |
template normalizedType(T); |
|
template normalizedType(T : U[N], U, size_t N) |
template normalizedType(T U N : U[N=size_t]) |
Introduced variables are before their usage |
void doIt(alias T E : E[])(E elem) |
void doIt(alias T E : E[])(E elem) |
Alias parameters; I am not sure if condition checks would work for aliases. |
void doIt(T=string E : E[])(E elem) |
void doIt(string T E : E[])(E elem) |
I am not sure if checking condition works right now. |
size_t levenshteinDistance(string equals = "a == b", Range1, Range2)(Range1 s, Range2 t) |
size_t levenshteinDistance(string equals = "a == b", Range1, Range2)(Range1 s, Range2 t) |
Default template parameter value will stay same as before. Please notice better consistency with situation when only type is default (row above) than in current version. And more possibilities to specify conditions. |
Things currently not possible: |
||
|
void do(T : class)(T instance); |
|
|
void do(T E : E[class])(T sarray, E element); |
match associative arrays with key as class |
|
S toupper(isSomeString!(S))(S input) |
See point 11 |
static if |
||
static if (is(T : Storage!(STORAGETYPE))) |
static if (T : Storage!(STORAGETYPE)) |
'is' probably can be safely dropped |
static if (is(VALUE TYPE == typedef)) |
static if (VALUE TYPE == typedef) |
1. This one is a bit tricky. Alternative could be: static if (VALUE TYPE == typedef(TYPE)) to be exact
pattern matching without 'magic' |
static if (is(T TYPE == TYPE*) || is(T == class)) |
static if (T TYPE == TYPE* || T == class) |
|
static if (isString!(VALUE)) |
static if (isString!(VALUE)) |
it should still work as static if takes as parameter boolean value, which is exactly what we get after evaluating isString!(T). |
static if (is(VALUE TYPE == TYPE*)) |
static if (VALUE TYPE == TYPE*) |
|
Things currently not possible: |
||
|
static if (T : Storage!(STORAGETYPE) if (T == MyType)) |
|
|
static if(T == invariant) |
well I am not much in const stuff, but uniform syntax opens door for this also. |
static assert |
||
static assert(is(VALUE : class), "Classes are not supported"); |
static assert(VALUE : class, "Classes are not supported"); |
|
Things currently not possible: |
||
|
static assert(V E K : E[K] if (K == int), "Not supported"); |
Well, not very good example because it is enough to write: static assert(V E : E[int], "Not supported");
Just to get idea what can be possible. |
alias syntax |
||
alias Variant[][] table; |
alias Variant[][] table; |
|
|
|
|
|
|
|
|
|
|
|
|
|
Things currently not possible: |
||
|
alias Variant[][] A B C; |
aliases Variant[][] to all symbols: A and B and C |
|
alias T U : U[]; |
simple
decomposition of types |
|
alias T U N : U[N=uint] if (N>100); |
aliases U to static array element type; and N to value of type uint, but only if size of static array is bigger than 100. |