View mode: basic / threaded / horizontal-split · Log in · Help
October 11, 2008
Uniform syntax for templates (second try)
This is my second try to propose better syntax for templates. My previous
proposal was added to bugzilla:
http://d.puremagic.com/issues/show_bug.cgi?id=1827

In this proposal I modified a little bit syntax, took into consideration
more cases and put into table few examples of new syntax compared to old
one.

Attached html version of document. Other formats are too big to send it
through news group, but they are available on request.

I hope for comments from you :-)

-- 
Regards
Marcin Kuszczak (Aarti_pl)
-------------------------------------
Ask me why I believe in Jesus - http://www.zapytajmnie.com (en/pl)
Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/
-------------------------------------
October 11, 2008
Re: Uniform syntax for templates (second try)
Marcin Kuszczak wrote:
> This is my second try to propose better syntax for templates. My previous
> proposal was added to bugzilla:
> http://d.puremagic.com/issues/show_bug.cgi?id=1827
> 
> In this proposal I modified a little bit syntax, took into consideration
> more cases and put into table few examples of new syntax compared to old
> one.
> 
> Attached html version of document. Other formats are too big to send it
> through news group, but they are available on request.
> 
> I hope for comments from you :-)

I'll make some candid comments without speaking for Walter.

a) The proposal prevents creating names in expressions, something we 
were talking about:

formattedRead("%s", &(int n));

The sequence "int n" will be ambiguous with a sequence of types.

b) At point 4 my eyes started glazing a bit.

void changeElement(T U N : U[N=uint] if(N>100))
    (T array, U value, int index);

The N=uint jumps as a surprising baroque element. Besides, U[N=uint] 
could be interpreted as a hash with uint as the default key type.

The rewrite in current D2 is:

void changeElement(T : U[N], U, uint N)
    (T array, U value, int index)
    if (N > 100);

To me it's not clear which is better. The second actually may be more 
expressive because you can collectively use all elements of the template 
in one place, something much clunkier in the other version.

c) I totally agree that this should be abolished:

string stringize(T : T[])(T value);

d) Let's try another example.

void parse(T E : E[], U : bool, V E N : E[N] if(N>100))
    (T array, U flag, V sarray);

In D2:

void parse(E, U : bool, V : E[N], uint N)
    (E[] array, U flag, V sarray)
    if(N>100);

e) This will be very hard to understand for both human and machine:

S toupper(isSomeString!(S))(S input)

f) You mention this is not possible, but they are:

void do(T : class)(T instance);
===>
void do(T : Object)(T instance);

void do(T E : E[class])(T sarray, E element);
===>
void do(K, V)(V[K] sarray, K element) if (is(K : Object))

S toupper(isSomeString!(S))(S input)
===>
S toupper(S)(S input) if (isSomeString!(S))

static if (T : Storage!(STORAGETYPE) if (T == MyType))
===>
static if (is(MyType : Storage!(STORAGETYPE), STORAGETYPE)

static if(T == invariant)
===>
static if(T == invariant) ----- should be added

static assert(V E K : E[K] if (K == int), "Not supported");
===>
static assert(is(V : E[int], E), "Not supported");

g) I think this is a rather minor improvement:

alias Variant[][] A B C;

h) I think this should be supported one way or another. Decomposing 
types quickly and easily would be a boon.

alias T U : U[];
alias T U N : U[N=uint] if (N>100);


Andrei
October 12, 2008
Re: Uniform syntax for templates (second try)
Andrei Alexandrescu wrote:

> Marcin Kuszczak wrote:
>> This is my second try to propose better syntax for templates. My previous
>> proposal was added to bugzilla:
>> http://d.puremagic.com/issues/show_bug.cgi?id=1827
>> 
>> In this proposal I modified a little bit syntax, took into consideration
>> more cases and put into table few examples of new syntax compared to old
>> one.
>> 
>> Attached html version of document. Other formats are too big to send it
>> through news group, but they are available on request.
>> 
>> I hope for comments from you :-)
> 
> I'll make some candid comments without speaking for Walter.

First of all thanks for your comments. I really appreciate them.
My comments are inlined below.


> a) The proposal prevents creating names in expressions, something we
> were talking about:
> 
> formattedRead("%s", &(int n));
> 
> The sequence "int n" will be ambiguous with a sequence of types.

What is this proposal about? Is there some topic on NG? Is above example
compile time feature? or runtime? 

Well it was difficult for me to take it into consideration, because I was
unaware of this proposal... :-)

> b) At point 4 my eyes started glazing a bit.
> 
> void changeElement(T U N : U[N=uint] if(N>100))
>      (T array, U value, int index);
> 
> The N=uint jumps as a surprising baroque element. 

Another alternative would be e.g.:
void changeElement(T U N=uint : U[N] if(N>100)) (T array, U value, int
index);
Above was in my first proposal (in bugzilla). Then default value could be
given as N=uint(5) where necessary.

or 

void changeElement(T U uint N : U[N] if(N>100)) (T array, U value, int
index);

What ever syntax would be choosen, it should be also choosen for default
template parameters.

Maybe some other syntax for default parameter type/value should be invented.
I don't care so much about that until the main advantages (summarized at
the end of this post) will be kept...

> Besides, U[N=uint] 
> could be interpreted as a hash with uint as the default key type.

No, because you are "fixing" one dimension (type) of type variable, and are
still expecting N to be defined by compiler. On compile time it is only
possible for static array, where N (value) is known at compile time. For
associative arrays it would be an error.

Side note: In fact it seems that arrays can be treated as special case of
associative arrays with perfect hashes, so your notice is fully
understandable ;-)


> The rewrite in current D2 is:
> 
> void changeElement(T : U[N], U, uint N)
>      (T array, U value, int index)
>      if (N > 100);
> 
> To me it's not clear which is better. The second actually may be more
> expressive because you can collectively use all elements of the template
> in one place, something much clunkier in the other version.

Yes, you are right. And after rethinking this case I think that current if()
after function arguments can stay as it is with global access to all
defined symbols. But in my opinion it should be added also as (optional)
extension for pattern matching expression. This way it will be possible to
use such expression in every compile time statement.

> c) I totally agree that this should be abolished:
> 
> string stringize(T : T[])(T value);

Yeah. I know :-)


> d) Let's try another example.
> 
> void parse(T E : E[], U : bool, V E N : E[N] if(N>100))
>      (T array, U flag, V sarray);
> 
> In D2:
> 
> void parse(E, U : bool, V : E[N], uint N)
>      (E[] array, U flag, V sarray)
>      if(N>100);
> 

It's not the same. In my version you restrict first template parameter to be
an array, in your example it can be any type. And additionally, isn't
declaration of N after its usage ugly ;-)


> e) This will be very hard to understand for both human and machine:
> 
> S toupper(isSomeString!(S))(S input)

Please don't consider this example and my comments below as part of my main
proposal. This example is more about template specialization resolution,
not about syntax of compile time expression. I didn't put much thinking in
template specialization resolution so below only few random thoughts:

It might be possible to define score based template function resolution. For
every function some logic in compiler would calculate points for "is
function matching". In case one of parameters don't match score would be 0
(false). In other cases there should be chosen function with maximal score. 

Well, I will stop now, as ground is getting more and more swampy :-)


> f) You mention this is not possible, but they are:
> 
> void do(T : class)(T instance);
> ===>
> void do(T : Object)(T instance);

This will not work for other categories than class and should be considered
rather as workaround of problem - not solution. Try to make the same with
struct, union, typedef etc. etc.

> void do(T E : E[class])(T sarray, E element);
> ===>
> void do(K, V)(V[K] sarray, K element) if (is(K : Object))

Not an equivalent. You allows here any types. In my version you allow only
associative arrays with classes as key. My function will not be used for
template function resolution. Comment for previous case also applies. And
my syntax is shorter...

> S toupper(isSomeString!(S))(S input)
> ===>
> S toupper(S)(S input) if (isSomeString!(S))

See my comment to your "e"

> static if (T : Storage!(STORAGETYPE) if (T == MyType))
> ===>
> static if (is(MyType : Storage!(STORAGETYPE), STORAGETYPE)

You will get syntax error in your example :-). It could be avoided with less
parenthesises. STORAGETYPE is not introduced parameter. Well my example is
also not very good. Although it would work for following case:

alias int STORAGETYPE;

class MyType : Storage!(STORAGETYPE) {
}

static if (T : Storage!(STORAGETYPE) if (T == MyType))


> static if(T == invariant)
> ===>
> static if(T == invariant) ----- should be added

You will probably just get:
static if(is(T == invariant))

I reserved already version without is() :-)

> static assert(V E K : E[K] if (K == int), "Not supported");
> ===>
> static assert(is(V : E[int], E), "Not supported");

Please notice that my syntax doesn't disallow shorter version:
static assert(V E : E[int], "Not supported");

In such a case it is even shorter.

> g) I think this is a rather minor improvement:
> 
> alias Variant[][] A B C;

I agree. Probably it should be just a syntax error.


> h) I think this should be supported one way or another. Decomposing
> types quickly and easily would be a boon.
> 
> alias T U : U[];
> alias T U N : U[N=uint] if (N>100);

Yep. It's usefull in some cases. But why not to do it in same way as other
compile time constructs and introduce something new?

---

As general comment I would like to notice that I am not considering this
syntax as finished work. There might be some changes in it, and I even
don't care too much about all details which should be adjusted. In my
opinion major advantages of this proposal are:

1. Same syntax for practically every compile time expression in D. You have
to learn it only once and then intuitively you will apply same pattern in
every case. Currently you have to learn by heart the whole IsExpression
table and additionally syntax for template functions. E.g. matching static
arrays, is far from intuitive, and even I would say that it is against good
practices of programming which demands that symbols are defined *before*
usage, not after.

2. Dropping redundant IsExpression for templates. This makes a lot of code
easier to read (e.g. because of less parenthesis). The notation gets also
shorter.

3. My proposal is more flexible & extensible than current syntax(-es). It's
also shorter in general case. And adding additional possibilities to this
compile time expression will allow to use them in all compile time
statements, differently than it is now.

4. It seems additionally that better pattern matching will render redundant
many use cases for if(ct_expression).


-- 
Regards
Marcin Kuszczak (Aarti_pl)
-------------------------------------
Ask me why I believe in Jesus - http://www.zapytajmnie.com (en/pl)
Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/
-------------------------------------
October 12, 2008
Re: Uniform syntax for templates (second try)
Marcin Kuszczak wrote:
> Andrei Alexandrescu wrote:
>> formattedRead("%s", &(int n));
>>
>> The sequence "int n" will be ambiguous with a sequence of types.
> 
> What is this proposal about? Is there some topic on NG? Is above example
> compile time feature? or runtime? 

It's just that you can introduce a symbolic definition whenever an 
expression is expected. So "int n" is good as an expression of type int.

>> d) Let's try another example.
>>
>> void parse(T E : E[], U : bool, V E N : E[N] if(N>100))
>>      (T array, U flag, V sarray);
>>
>> In D2:
>>
>> void parse(E, U : bool, V : E[N], uint N)
>>      (E[] array, U flag, V sarray)
>>      if(N>100);
>>
> 
> It's not the same. In my version you restrict first template parameter to be
> an array, in your example it can be any type. And additionally, isn't
> declaration of N after its usage ugly ;-)

It is the same. Look at how E is used.

>> f) You mention this is not possible, but they are:
>>
>> void do(T : class)(T instance);
>> ===>
>> void do(T : Object)(T instance);
> 
> This will not work for other categories than class and should be considered
> rather as workaround of problem - not solution. Try to make the same with
> struct, union, typedef etc. etc.

I can by saying:

void do(T)(T instance) if (is(T == whatever));

>> void do(T E : E[class])(T sarray, E element);
>> ===>
>> void do(K, V)(V[K] sarray, K element) if (is(K : Object))
> 
> Not an equivalent. You allows here any types. In my version you allow only
> associative arrays with classes as key. My function will not be used for
> template function resolution. Comment for previous case also applies. And
> my syntax is shorter...

The D2 variant is the same because it restricts K to be a class. Also D2 
 eliminates the function from the overload set if the "if" clause is 
not respected (it's pretty much the whole point of the feature).

>> S toupper(isSomeString!(S))(S input)
>> ===>
>> S toupper(S)(S input) if (isSomeString!(S))
> 
> See my comment to your "e"

Equivalent.

>> static if (T : Storage!(STORAGETYPE) if (T == MyType))
>> ===>
>> static if (is(MyType : Storage!(STORAGETYPE), STORAGETYPE)
> 
> You will get syntax error in your example :-).

I know. That's a bug in the compiler.

> It could be avoided with less
> parenthesises. STORAGETYPE is not introduced parameter. Well my example is
> also not very good. Although it would work for following case:
> alias int STORAGETYPE;
> 
> class MyType : Storage!(STORAGETYPE) {
> }
> 
> static if (T : Storage!(STORAGETYPE) if (T == MyType))
> 
> 
>> static if(T == invariant)
>> ===>
>> static if(T == invariant) ----- should be added
> 
> You will probably just get:
> static if(is(T == invariant))

Correct.

> I reserved already version without is() :-)
>  
>> static assert(V E K : E[K] if (K == int), "Not supported");
>> ===>
>> static assert(is(V : E[int], E), "Not supported");
> 
> Please notice that my syntax doesn't disallow shorter version:
> static assert(V E : E[int], "Not supported");
> 
> In such a case it is even shorter.
> 
>> g) I think this is a rather minor improvement:
>>
>> alias Variant[][] A B C;
> 
> I agree. Probably it should be just a syntax error.
> 
>  
>> h) I think this should be supported one way or another. Decomposing
>> types quickly and easily would be a boon.
>>
>> alias T U : U[];
>> alias T U N : U[N=uint] if (N>100);
> 
> Yep. It's usefull in some cases. But why not to do it in same way as other
> compile time constructs and introduce something new?
> 
> ---
> 
> As general comment I would like to notice that I am not considering this
> syntax as finished work. There might be some changes in it, and I even
> don't care too much about all details which should be adjusted. In my
> opinion major advantages of this proposal are:
> 
> 1. Same syntax for practically every compile time expression in D. You have
> to learn it only once and then intuitively you will apply same pattern in
> every case. Currently you have to learn by heart the whole IsExpression
> table and additionally syntax for template functions. E.g. matching static
> arrays, is far from intuitive, and even I would say that it is against good
> practices of programming which demands that symbols are defined *before*
> usage, not after.

Uniformity is good.

> 2. Dropping redundant IsExpression for templates. This makes a lot of code
> easier to read (e.g. because of less parenthesis). The notation gets also
> shorter.

I think this is rather minor.

> 3. My proposal is more flexible & extensible than current syntax(-es). It's
> also shorter in general case. And adding additional possibilities to this
> compile time expression will allow to use them in all compile time
> statements, differently than it is now.

I'm not sure about terseness. Your patterns tend to introduce more symbols.

> 4. It seems additionally that better pattern matching will render redundant
> many use cases for if(ct_expression).

Yah, that I'm looking forward to.

This is a big change. To sell this big change to people and Walter, you 
need to have some smashing advantages. So far you have I'm not seeing a 
smashing advantage. Easily decomposing types in patterns would be one, 
but that is something that could be pulled out of your proposal and 
implemented alone.


Andrei
October 12, 2008
Re: Uniform syntax for templates (second try)
Andrei Alexandrescu wrote:

> Marcin Kuszczak wrote:
>> As general comment I would like to notice that I am not considering this
>> syntax as finished work. There might be some changes in it, and I even
>> don't care too much about all details which should be adjusted. In my
>> opinion major advantages of this proposal are:
>> 
>> 1. Same syntax for practically every compile time expression in D. You
>> have to learn it only once and then intuitively you will apply same
>> pattern in every case. Currently you have to learn by heart the whole
>> IsExpression table and additionally syntax for template functions. E.g.
>> matching static arrays, is far from intuitive, and even I would say that
>> it is against good practices of programming which demands that symbols
>> are defined *before* usage, not after.
> 
> Uniformity is good.
> 
>> 2. Dropping redundant IsExpression for templates. This makes a lot of
>> code easier to read (e.g. because of less parenthesis). The notation gets
>> also shorter.
> 
> I think this is rather minor.

IsExpression is causing problems for newbies, as I already mentioned before.
Is syntax for templates was mentioned as difficult for students of D
language. And it must be learnt by heart. (Well, maybe that's opposite:
template function parameters must be learnt by heart, as they are
inconsistent with is()?)

>> 3. My proposal is more flexible & extensible than current syntax(-es).
>> It's also shorter in general case. And adding additional possibilities to
>> this compile time expression will allow to use them in all compile time
>> statements, differently than it is now.
> 
> I'm not sure about terseness. Your patterns tend to introduce more
> symbols.

You will need more symbols only when you need to take more information from
expression. There will be always version which will introduce not more
symbols than currently.

>> 4. It seems additionally that better pattern matching will render
>> redundant many use cases for if(ct_expression).
> 
> Yah, that I'm looking forward to.
> 
> This is a big change. To sell this big change to people and Walter, you
> need to have some smashing advantages. So far you have I'm not seeing a
> smashing advantage. Easily decomposing types in patterns would be one,
> but that is something that could be pulled out of your proposal and
> implemented alone.

Well, I am not saying that this is top-priority change right now. I am just
saying that it would be better to have it implemented - it should be a way
to go. I really don't have an idea how much work is it to implement this.
The fact is that most pieces are already in-place, they just have to be
connected together. Maybe it would be possible to introduce this change
partially, finally depreciating is() completely? There will be probably not
so much impact on user code, as only heavily templated code (using matching
by e.g. static arrays) will be affected. Common cases will stay exactly the
same.

-- 
Regards
Marcin Kuszczak (Aarti_pl)
-------------------------------------
Ask me why I believe in Jesus - http://www.zapytajmnie.com (en/pl)
Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/
-------------------------------------
October 12, 2008
Re: Uniform syntax for templates (second try)
Marcin Kuszczak wrote:
> Well, I am not saying that this is top-priority change right now. I am just
> saying that it would be better to have it implemented - it should be a way
> to go. I really don't have an idea how much work is it to implement this.
> The fact is that most pieces are already in-place, they just have to be
> connected together. Maybe it would be possible to introduce this change
> partially, finally depreciating is() completely? There will be probably not
> so much impact on user code, as only heavily templated code (using matching
> by e.g. static arrays) will be affected. Common cases will stay exactly the
> same.

Why are you sure deprecating is() is a goal in and of itself? You 
mention beginners are having trouble understanding it, but then you'd 
need to make a pretty good case that beginners won't have much trouble 
understanding your way. (It took me a while.)

Besides one good thing about is() is that it allows you to match type 
patterns without error. For example:

static if (is(T = V[K], K, V)) {
    // T is a hash, use K and V
} else static if (is(T = V[], V)) {
    // T is an array, use V
} ...

In contrast, aliasing can only fail with a compile-time error:

alias T K V : T = V[K];

I agree that using a symbol before clarifying that it's being introduced 
is odd. Anyhow, it would be great if more people added to this exchange 
to get a feel of the level of interest.


Andrei
October 12, 2008
Re: Uniform syntax for templates (second try)
Andrei Alexandrescu wrote:

> Marcin Kuszczak wrote:
>> Well, I am not saying that this is top-priority change right now. I am
>> just saying that it would be better to have it implemented - it should be
>> a way to go. I really don't have an idea how much work is it to implement
>> this. The fact is that most pieces are already in-place, they just have
>> to be connected together. Maybe it would be possible to introduce this
>> change partially, finally depreciating is() completely? There will be
>> probably not so much impact on user code, as only heavily templated code
>> (using matching by e.g. static arrays) will be affected. Common cases
>> will stay exactly the same.
> 
> Why are you sure deprecating is() is a goal in and of itself? You
> mention beginners are having trouble understanding it, but then you'd
> need to make a pretty good case that beginners won't have much trouble
> understanding your way. (It took me a while.)

They will have to learn my syntax anyway. Currently there is no way around,
as my syntax is based on is() expression from D1.0. But in my proposal
there is only one syntax to learn. Currently you have to learn how to write
is() expression and how to write template function parameters.

> Besides one good thing about is() is that it allows you to match type
> patterns without error. 

It will be still possible as in your example below, but in simpler way:
static if (T V K :V[K])
I am not arguing about removing this case. It is usefull.

> For example: 
> 
> static if (is(T = V[K], K, V)) {
>      // T is a hash, use K and V
> } else static if (is(T = V[], V)) {
>      // T is an array, use V
> } ...

LOL. And now you have been stroked by D template syntax nuances! 

Above code is incorrect. And it is not only matter of '=' instead '=='. It
is the matter of funky syntax, which doesn't keep any rules. In fact in 2.0
it's even worse than in 1.0 after adding TemplateParameterList to is()
expression.

Above code should be written as below:

void main() {
   alias long[char[]] T;
   static if (is(T V == V[K], K)) {
       pragma(msg, V.stringof ~ " " ~ K.stringof);
   } else static if (is(T V == V[])) {
       pragma(msg, V.stringof);
   }
}

Who will guess how to write above without looking into docs? No one.

BTW. first pragma prints: "long const(char)[]". Is it by design or is it an
error?

> In contrast, aliasing can only fail with a compile-time error:
> 
> alias T K V : T = V[K];

This syntax would be usefull only in case where you can know for sure that T
is associative array. In such a case you can safely decompose T into
subtypes.

> I agree that using a symbol before clarifying that it's being introduced
> is odd. Anyhow, it would be great if more people added to this exchange
> to get a feel of the level of interest.

Well, I wonder why no one except you commented about this issue. That might
be the case that people didn't write so much code using isExpression and
complicated template function's template parameters. I have written
automatic serializer, which is currently probably the most advanced
solution for D. It has definable back-ends (SimpleText, JSon and
Binary(thanks to Bill Baxter, who wrote it)), versioning of classes,
importing old versions, thread safety, exception safety, discovering of
templated functions in user classes and optional saving results to string
or any other stream (btw. I would be happy to discuss with someone about my
design :-)). It is heavily templated code, with many different corner cases
which stresses type system a lot (e.g. I discovered that it's not possible
to create pointer to class in straight way). Maybe only few people wrote
such a code? I don't know because inconstancy just strikes in the eyes when
working with it...

-- 
Regards
Marcin Kuszczak (Aarti_pl)
-------------------------------------
Ask me why I believe in Jesus - http://www.zapytajmnie.com (en/pl)
Doost (port of few Boost libraries) - http://www.dsource.org/projects/doost/
-------------------------------------
October 12, 2008
Re: Uniform syntax for templates (second try)
"Marcin Kuszczak" <aarti_please_no@spam_interia.pl> wrote in message 
news:gctj4a$2k7p$1@digitalmars.com...
> Andrei Alexandrescu wrote:
>
> I agree that using a symbol before clarifying that it's being introduced
>> is odd. Anyhow, it would be great if more people added to this exchange
>> to get a feel of the level of interest.
>
> Well, I wonder why no one except you commented about this issue.

I've been following, but feeling completely out of my league. The idea of 
more consistency in the syntaxes (as well as removing is()) sounds great, 
but I really haven't been using D templates and such enough to feel like I'd 
really know what I was talking about and actually have real informed 
opinions.
October 12, 2008
Re: Uniform syntax for templates (second try)
Sun, 12 Oct 2008 11:15:59 -0500,
Andrei Alexandrescu wrote:
> Anyhow, it would be great if more people added to this exchange 
> to get a feel of the level of interest.

I admit I felt disappointed a couple of times when I wasn't able to use 
some is() tricks in a template type list.  If that's fixed then I'm fine 
with the rest of the syntax.

Unconditional type decomposition sounds useful.
October 13, 2008
Re: Uniform syntax for templates (second try)
On Mon, Oct 13, 2008 at 4:28 AM, Marcin Kuszczak
<aarti_please_no@spam_interia.pl> wrote:
> Well, I wonder why no one except you commented about this issue.

I also have been glancing over this thread, but just haven't had the
time to really follow it.
But is and template matching syntax really is fu-bar right now, and
something to make it saner, more consistent and easier to remember
would be great.  Any time I want to use pattern matching is
expressions I basically open up the manual to the is expression page
right now, but I can't remember that bizarre syntax to save my life.

--bb
Top | Discussion index | About this forum | D home