www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Some more template syntax sugar

reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
I think function templates still require too much in the way of type 
annotations. Take the canonical example, sqr:

T sqr(T) (T x)
{
	return x*x;
}

In this example, we have to declare T three times, even though I think 
this could be inferred. I propose an alternative syntax:

auto sqr(x)
{
	return x*x;
}

which IMHO looks very elegant.

Here are the rules more formally:
  - if a type is missing for an parameter, template this function by 
that argument. Do this for every parameter.
  - use type inference (just like auto) to determine the return type, 
unless it is marked 'void'

so, the above code becomes:

typeof(__ret) sqr(__t1) ( __t1 x)
{
	auto __ret = x * x;
	return __ret;
}

and for more complex examples,

auto foo(a, b, c, d)
{
	...
}

becomes:

typeof(__ret) foo(__t1, __t2, __t3, __t4) ( __t1 a, __t2 b, __t3 c, __t4 d)
{
	...
}

and the instantiation rules are as per normal.

Cheers,

Reiner
Aug 28 2006
next sibling parent Kristian <kjkilpi gmail.com> writes:
On Mon, 28 Aug 2006 15:18:04 +0300, Reiner Pope  
<reiner.pope REMOVE.THIS.gmail.com> wrote:
 I think function templates still require too much in the way of type  
 annotations. Take the canonical example, sqr:

 T sqr(T) (T x)
 {
 	return x*x;
 }

 In this example, we have to declare T three times, even though I think  
 this could be inferred. I propose an alternative syntax:

 auto sqr(x)
 {
 	return x*x;
 }

 which IMHO looks very elegant.

It looks nice to me too.
Aug 28 2006
prev sibling next sibling parent Derek Parnell <derek nomail.afraid.org> writes:
On Mon, 28 Aug 2006 22:18:04 +1000, Reiner Pope wrote:

 I think function templates still require too much in the way of type 
 annotations. Take the canonical example, sqr:
 
 T sqr(T) (T x)
 {
 	return x*x;
 }
 
 In this example, we have to declare T three times, even though I think 
 this could be inferred. I propose an alternative syntax:
 
 auto sqr(x)
 {
 	return x*x;
 }
 
 which IMHO looks very elegant.

It does! At first glance, this looks quite a natural consequence of the way the D language is heading. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 29/08/2006 10:59:17 AM
Aug 28 2006
prev sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Reiner Pope wrote:
 I think function templates still require too much in the way of type 
 annotations. Take the canonical example, sqr:
 
 T sqr(T) (T x)
 {
     return x*x;
 }
 
 In this example, we have to declare T three times, even though I think 
 this could be inferred. I propose an alternative syntax:
 
 auto sqr(x)
 {
     return x*x;
 }
 
 which IMHO looks very elegant.

I know. The problem is that it is indistinguishable from: typedef int x; auto sqr(x); i.e. when x is a typedef and no parameter name is given, or when x is a parameter name and no type is given.
Aug 29 2006
next sibling parent Kristian <kjkilpi gmail.com> writes:
On Tue, 29 Aug 2006 11:22:19 +0300, Walter Bright  
<newshound digitalmars.com> wrote:

 Reiner Pope wrote:
 I think function templates still require too much in the way of type  
 annotations. Take the canonical example, sqr:
  T sqr(T) (T x)
 {
     return x*x;
 }
  In this example, we have to declare T three times, even though I think  
 this could be inferred. I propose an alternative syntax:
  auto sqr(x)
 {
     return x*x;
 }
  which IMHO looks very elegant.

I know. The problem is that it is indistinguishable from: typedef int x; auto sqr(x); i.e. when x is a typedef and no parameter name is given, or when x is a parameter name and no type is given.

Can't we make parameter names to be mandatory here? typedef int x; auto sqr(x); //'x' is treated as parameter name auto sqr2(x val, y); //'x' is treated as typedef Hmm, if someone would like to use non-auto return values with function templates, then how about adding '!' to function template names? For example: int myTemplate!(x, y) { return(x < y ? -1 : (x > y ? 1 : 0)); }
Aug 29 2006
prev sibling next sibling parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Walter Bright wrote:
 I know. The problem is that it is indistinguishable from:
 
     typedef int x;
     auto sqr(x);
 
 i.e. when x is a typedef and no parameter name is given, or when x is a 
 parameter name and no type is given.

Is the solution to this any worse than the current spec's dealing with aliases. From the spec:
  Note: Type aliases can sometimes look indistinguishable from alias
declarations:
 
 alias foo.bar abc;	// is it a type or a symbol?
 
 The distinction is made in the semantic analysis pass.
 
 Aliases cannot be used for expressions:
 
 struct S { static int i; }
 S s;
 
 alias s.i a;	// illegal, s.i is an expression
 alias S.i b;	// ok
 b = 4;		// sets S.i to 4

If the semantic analysis pass can determine the validity of alias expressions, I would have thought that it could determine the meaning of your example: - if x is defined as a type, then it is a nameless parameter - if not, then it is a templated function Of course, this provides no way of shadowing types, but I'm not sure how much of a problem that is. The alternatives I see aren't as nice, since some syntax modification would be required: 1. Modify the syntax I propose to make it clear that it's a nameless parameter. Basically any additional keyword/symbol could work, but that extra character makes a big difference in use. I think auto sqr(x) { ... } is much nicer than auto sqr( x) { ... } 2. Modify the syntax for nameless parameters. Perhaps something like the functional languages, where _ denotes a nameless parameter: typedef int a; interface Foo { int bar(a); } would then become: typedef int a; interface Foo { int bar(a _); } I like this proposal a lot more, because it follows the functional language idea of _ being a variable eater. But this is going to break much more code, so I'm stuck here. Cheers, Reiner
Aug 29 2006
parent reply Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
I've thought about this ambiguity and still come to not much more of a 
conclusion. However, a few thoughts:

(just to clarify my naming, let's call the current system (parameters 
without names) nameless parameters, and my suggestion (implicit 
templating) typeless parameters)

1. Nameless parameters are a very small syntactical sugar as opposed to 
typeless parameters, and I assert that we can do without them. Most of 
the time, you should name your parameters anyway, so the caller can have 
a better idea of what they are used for, and if you decide that it is 
just way to much to type, then you can get away with only two more 
characters for each parameter:

   int foo(int, int);

becomes

   int foo(int a, int b);

which really isn't much more to type.

2. It would be possible to do a small modification of the typeless 
parameter syntax to make it grammatically distinct from typeless 
parameters. For instance, add a ' ' to make it clear:

   auto sqr( x) {...}

While, on the surface, this seems the rights solution, I think it 
creates a similar mental block as we get with lazy parameters: even though

   foo( {x();} );

is only three characters more than

   foo( x() );

you will get people used to 'proper' lazy evaluation (Smug Lisp Weenies) 
who say that this means D doesn't *really* support it. My point: by 
using the same typeless syntax that dynamically typed languages use, it 
appeals much more to fans of those languages.



I think that an unmodified syntax is the best approach from a niceness 
point of view, and if the language were being designed afresh, I would 
go for that and ban nameless parameters, since I've already said they 
are hardly useful.

However, given that we are not starting afresh, there may be some code 
out there which uses nameless parameters. I would guess that that code 
doesn't appear much, and the only places I can imagine it being is in 
interfaces and in extern declarations. Since interfaces can't have 
templates, this would be flagged as an error at compile-time, making it 
easy to find and solve. For extern declarations, I don't know whether 
templates are permitted, so this *may* cause a problem.

Thoughts, anyone?

Cheers,

Reiner
Sep 01 2006
next sibling parent Kristian <kjkilpi gmail.com> writes:
I still think that it would be good if parameters names would be  
mandatory. But then again, I always name my parameters.

typedef int x;
void foo(x);    //'x' is a typeless parameter -> this is a function  
template
void foo(x y);  //'x' is a typedef -> this is a normal function

Would this break too much old code?
If so, how about using '!' with templates (as I mentioned earlier)? For  
example:

void foo!(x);  //definitely a function template


On Fri, 01 Sep 2006 13:10:49 +0300, Reiner Pope  
<reiner.pope REMOVE.THIS.gmail.com> wrote:
 I've thought about this ambiguity and still come to not much more of a  
 conclusion. However, a few thoughts:

 (just to clarify my naming, let's call the current system (parameters  
 without names) nameless parameters, and my suggestion (implicit  
 templating) typeless parameters)

 1. Nameless parameters are a very small syntactical sugar as opposed to  
 typeless parameters, and I assert that we can do without them. Most of  
 the time, you should name your parameters anyway, so the caller can have  
 a better idea of what they are used for, and if you decide that it is  
 just way to much to type, then you can get away with only two more  
 characters for each parameter:

    int foo(int, int);

 becomes

    int foo(int a, int b);

 which really isn't much more to type.

 2. It would be possible to do a small modification of the typeless  
 parameter syntax to make it grammatically distinct from typeless  
 parameters. For instance, add a ' ' to make it clear:

    auto sqr( x) {...}

 While, on the surface, this seems the rights solution, I think it  
 creates a similar mental block as we get with lazy parameters: even  
 though

    foo( {x();} );

 is only three characters more than

    foo( x() );

 you will get people used to 'proper' lazy evaluation (Smug Lisp Weenies)  
 who say that this means D doesn't *really* support it. My point: by  
 using the same typeless syntax that dynamically typed languages use, it  
 appeals much more to fans of those languages.



 I think that an unmodified syntax is the best approach from a niceness  
 point of view, and if the language were being designed afresh, I would  
 go for that and ban nameless parameters, since I've already said they  
 are hardly useful.

 However, given that we are not starting afresh, there may be some code  
 out there which uses nameless parameters. I would guess that that code  
 doesn't appear much, and the only places I can imagine it being is in  
 interfaces and in extern declarations. Since interfaces can't have  
 templates, this would be flagged as an error at compile-time, making it  
 easy to find and solve. For extern declarations, I don't know whether  
 templates are permitted, so this *may* cause a problem.

 Thoughts, anyone?

 Cheers,

 Reiner

Sep 01 2006
prev sibling parent reply Walter Bright <newshound digitalmars.com> writes:
Reiner Pope wrote:
 Thoughts, anyone?

1) Lots of people like nameless parameters to implicitly document that the parameter isn't used. 2) Nameless parameters come up an awful lot in C/C++ header files - I think they're expected.
Sep 02 2006
next sibling parent Reiner Pope <reiner.pope REMOVE.THIS.gmail.com> writes:
Walter Bright wrote:
 2) Nameless parameters come up an awful lot in C/C++ header files - I 
 think they're expected.

I thought of that one, and since you want D to work in the same way as C and C++ when the syntax is the same, I figure you must keep nameless parameters working in the way they do. That means that we need a modified typeless parameter syntax. I'm not sure which keywords and operators are available, but I think that isn't used. How about just sticking a into the syntax for typeless parameters to make it unambiguous. auto foo( x, y, int) // x and y are typeless parameters, and the third paremeter is nameless. Cheers, Reiner
Sep 02 2006
prev sibling parent reply Derek Parnell <derek psyc.ward> writes:
On Sat, 02 Sep 2006 13:14:31 -0700, Walter Bright wrote:

 Reiner Pope wrote:
 Thoughts, anyone?

1) Lots of people like nameless parameters to implicitly document that the parameter isn't used.

And lots of people like named parameters to explicitly document the meaning of the parameters.
 2) Nameless parameters come up an awful lot in C/C++ header files - I 
 think they're expected.

So what? This is D and not C/C++. If one is going to use a new language then one should be prepared to learn a few new things too. -- Derek Parnell Melbourne, Australia "Down with mediocrity!"
Sep 02 2006
parent Don Clugston <dac nospam.com.au> writes:
Derek Parnell wrote:
 On Sat, 02 Sep 2006 13:14:31 -0700, Walter Bright wrote:
 
 Reiner Pope wrote:
 Thoughts, anyone?

the parameter isn't used.

And lots of people like named parameters to explicitly document the meaning of the parameters.

It would be better to be able to explicitly document that the parameter isn't used. Maybe by reusing the 'null' keyword. int somefunc(int x, uint null) { }
  
 2) Nameless parameters come up an awful lot in C/C++ header files - I 
 think they're expected.

So what? This is D and not C/C++. If one is going to use a new language then one should be prepared to learn a few new things too.

It would add a lot more pain to converting C header files to D. For example, the Win32 API project, would require over ten thousand changes.
Sep 04 2006
prev sibling parent Derek Parnell <derek nomail.afraid.org> writes:
On Tue, 29 Aug 2006 01:22:19 -0700, Walter Bright wrote:

 Reiner Pope wrote:
 I think function templates still require too much in the way of type 
 annotations. Take the canonical example, sqr:
 
 T sqr(T) (T x)
 {
     return x*x;
 }
 
 In this example, we have to declare T three times, even though I think 
 this could be inferred. I propose an alternative syntax:
 
 auto sqr(x)
 {
     return x*x;
 }
 
 which IMHO looks very elegant.

I know. The problem is that it is indistinguishable from: typedef int x; auto sqr(x); i.e. when x is a typedef and no parameter name is given, or when x is a parameter name and no type is given.

Think outside the actual example and see if the concept of doing a simplification can be achieved. I'm sure you can come up with a better syntax for such an obvious improvement. -- Derek (skype: derek.j.parnell) Melbourne, Australia "Down with mediocrity!" 30/08/2006 9:09:51 AM
Aug 29 2006