www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - static parameters

reply Bill Baxter <dnewsgroup billbaxter.com> writes:
On page 30 of WalterAndrei.pdf it talks about static function parameters.

It says
    void foo(static int i, int j) { ... }
will become a synonym for the template
    void foo(int i)(int j) { ... }

And the reason given is it's supposed to make templates "easier for 
mortals".

I don't really see how that makes anything easier.  It's longer to type 
first of all.  And you still have to be aware of the compile-time / 
runtime distinction, this just makes it a little harder to see.  And it 
introduces issues like what to do if there are both template parameters 
and static arguments, and what to do with __traits for such functions, 
and what the parameters tuple should look like, and whether you can have 
foo(int i, static j), and whether you can still call it as foo!(7)(5), 
and if you can call foo(int i)(int j) as foo(3,x)?

And if it is just like a template can you take &foo?  If not, how do you 
take the address of a particular specialization of the function?  Do you 
revert back to foo!(3) then?

In short it seems like a classic case of a feature that adds little 
benefit, but a fair number of new rules that everyone will have to 
remember, and in the end it could very likely stomp on the toes of some 
other future features that would be much more useful.

As far as I can tell, this is just another way to do something we can 
already do, and all we gain from it is the ability to save two 
characters on the calling side for functions that are only templated on 
const values.

--bb
Aug 30 2007
next sibling parent reply Robert Fraser <fraserofthenight gmail.com> writes:
Bill Baxter Wrote:

 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
     void foo(static int i, int j) { ... }
 will become a synonym for the template
     void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?
 
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

As far as I understand it, it will allow overloading on constants for manual constant folding & optimization. So if you have: void foo(static int i); void foo(int i); foo(3); // Calls the first foo(x); // Calls teh second (assuming x is not compile-time resolvable) That said, I do agree it's a bit of overkill.
Aug 30 2007
parent Don Clugston <dac nospam.com.au> writes:
Robert Fraser wrote:
 Bill Baxter Wrote:
 
 On page 30 of WalterAndrei.pdf it talks about static function parameters.

 It says
     void foo(static int i, int j) { ... }
 will become a synonym for the template
     void foo(int i)(int j) { ... }

 And the reason given is it's supposed to make templates "easier for 
 mortals".

 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?

 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?

 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.

 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.

 --bb

As far as I understand it, it will allow overloading on constants for manual constant folding & optimization. So if you have: void foo(static int i); void foo(int i); foo(3); // Calls the first foo(x); // Calls teh second (assuming x is not compile-time resolvable)

Yes, means you can do compile-time regexps with identical syntax to run-time regexps. This was my proposal from the distant past, and I think someone else suggested it as well. But, with macros, most of the impetus is gone; you could get the same effect in another way: macro foo(i) { static if (__traits(compiletimeconst, i)) foo_template!(i); else foo_function(i); } One problem with the proposal, is that you can't currently accept any type as a template value parameter (only ints, floats, and strings). So struct Bar { int a; } foo(static Bar b); is not going to work. So it's not clear that it's a big win any more. I don't think we need it.
Aug 30 2007
prev sibling next sibling parent kris <foo bar.com> writes:
Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?
 
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

There appear to be a few features with the characteristics you describe. I sure hope it's not feature-creep, yet some do bear that hallmark
Aug 30 2007
prev sibling next sibling parent Reiner Pope <some address.com> writes:
Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?
 
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

I know it's far from the only way to do this, but static parameters should hopefully also allow static opIndex, allowing us to do nifty tuple-like behaviour: struct Tuple(T...) { T impl; T[i] opIndex(static int i) { return impl[i]; } T[i] opIndexAssign(T[i] val, static int i) { return (impl[i] = val); } } void main() { Tuple!(int, bool) t; t[1] = false; t[0] = 5; } -- Reiner
Aug 31 2007
prev sibling next sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?
 
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

"this is just another way to do something we can already do" ? Are you sure that is the case? The presentation says: void foo(static int i, int j) { ... } will become a synonym for the template void foo(int i)(int j) { ... } However one will also be able to call foo as if it were a function: foo(3, 2); which is not at all possible currently for the template: void foo(int i)(int j) { ... } (or will that also change with the upcoming D features?) -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 01 2007
parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Bruno Medeiros wrote:
 Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.

 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }

 And the reason given is it's supposed to make templates "easier for 
 mortals".

 I don't really see how that makes anything easier.  It's longer to 
 type first of all.  And you still have to be aware of the compile-time 
 / runtime distinction, this just makes it a little harder to see.  And 
 it introduces issues like what to do if there are both template 
 parameters and static arguments, and what to do with __traits for such 
 functions, and what the parameters tuple should look like, and whether 
 you can have foo(int i, static j), and whether you can still call it 
 as foo!(7)(5), and if you can call foo(int i)(int j) as foo(3,x)?

 And if it is just like a template can you take &foo?  If not, how do 
 you take the address of a particular specialization of the function?  
 Do you revert back to foo!(3) then?

 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of 
 some other future features that would be much more useful.

 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated 
 on const values.

 --bb

"this is just another way to do something we can already do" ? Are you sure that is the case?

No, I'm not at all sure. That's why I was asking.
 The presentation says:
   void foo(static int i, int j) { ... }
 will become a synonym for the template
   void foo(int i)(int j) { ... }
 
 However one will also be able to call foo as if it were a function:
   foo(3, 2);
 which is not at all possible currently for the template:
   void foo(int i)(int j) { ... }
 (or will that also change with the upcoming D features?)

By "do something we can already do" I meant the functionality, not the syntax. We can already pass compile time integer parameters to functions, we just have to call it like foo!(3)(2) instead of foo(3,2). Robert and Reiner both pointed out some (mildly) interesting things it would allow. 1) seamlessly overloading on static/vs non-static. 2) allowing to make compile-time constant opIndex (and other operators too I suppose like opAddAssign). Neither of those is really knocking my socks off, though. --bb
Sep 01 2007
parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 Bruno Medeiros wrote:
 Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function 
 parameters.

 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }

 And the reason given is it's supposed to make templates "easier for 
 mortals".

 I don't really see how that makes anything easier.  It's longer to 
 type first of all.  And you still have to be aware of the 
 compile-time / runtime distinction, this just makes it a little 
 harder to see.  And it introduces issues like what to do if there are 
 both template parameters and static arguments, and what to do with 
 __traits for such functions, and what the parameters tuple should 
 look like, and whether you can have foo(int i, static j), and whether 
 you can still call it as foo!(7)(5), and if you can call foo(int 
 i)(int j) as foo(3,x)?

 And if it is just like a template can you take &foo?  If not, how do 
 you take the address of a particular specialization of the function?  
 Do you revert back to foo!(3) then?

 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of 
 some other future features that would be much more useful.

 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated 
 on const values.

 --bb

"this is just another way to do something we can already do" ? Are you sure that is the case?

No, I'm not at all sure. That's why I was asking.

You had a statement, not a question. :P
 The presentation says:
   void foo(static int i, int j) { ... }
 will become a synonym for the template
   void foo(int i)(int j) { ... }

 However one will also be able to call foo as if it were a function:
   foo(3, 2);
 which is not at all possible currently for the template:
   void foo(int i)(int j) { ... }
 (or will that also change with the upcoming D features?)

By "do something we can already do" I meant the functionality, not the syntax. We can already pass compile time integer parameters to functions, we just have to call it like foo!(3)(2) instead of foo(3,2). Robert and Reiner both pointed out some (mildly) interesting things it would allow. 1) seamlessly overloading on static/vs non-static.

That's the whole point of this functionality, just as described in Walter's slides (2 pages bellow where static function parameters are introduced). And that's why being able to call something foo(3,2) instead of foo!(3)(2) is not just a syntactical sugar.
 2) allowing to make compile-time constant opIndex (and other operators 
 too I suppose like opAddAssign).
 

That's assuming operator overloading will work with these functions, which we don't know for sure (unless it was mentioned in the conference).
 Neither of those is really knocking my socks off, though.
 
 --bb

-- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 02 2007
parent Reiner Pope <some address.com> writes:
Bruno Medeiros wrote:
 Bill Baxter wrote:
 2) allowing to make compile-time constant opIndex (and other operators 
 too I suppose like opAddAssign).

That's assuming operator overloading will work with these functions, which we don't know for sure (unless it was mentioned in the conference).

Yes, I assumed that. But I think there's a strong case for it, both in consistency and because it is required to emulate tuples. I sure hope it will work :-). -- Reiner
Sep 02 2007
prev sibling next sibling parent Jason House <jason.james.house gmail.com> writes:
Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?

Those are all good points!
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.

I think this style of functionality could be useful. Provided that I don't have to write lots of function definitions, having the compiler figure out what is or isn't compile-time values and optimizing based on that is a good thing. Personally, I think something like the return keyword could be helpful here too
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

Sep 01 2007
prev sibling parent reply Bruno Medeiros <brunodomedeiros+spam com.gmail> writes:
Bill Baxter wrote:
 On page 30 of WalterAndrei.pdf it talks about static function parameters.
 
 It says
    void foo(static int i, int j) { ... }
 will become a synonym for the template
    void foo(int i)(int j) { ... }
 
 And the reason given is it's supposed to make templates "easier for 
 mortals".
 
 I don't really see how that makes anything easier.  It's longer to type 
 first of all.  And you still have to be aware of the compile-time / 
 runtime distinction, this just makes it a little harder to see.  And it 
 introduces issues like what to do if there are both template parameters 
 and static arguments, and what to do with __traits for such functions, 
 and what the parameters tuple should look like, and whether you can have 
 foo(int i, static j), and whether you can still call it as foo!(7)(5), 
 and if you can call foo(int i)(int j) as foo(3,x)?
 
 And if it is just like a template can you take &foo?  If not, how do you 
 take the address of a particular specialization of the function?  Do you 
 revert back to foo!(3) then?
 
 In short it seems like a classic case of a feature that adds little 
 benefit, but a fair number of new rules that everyone will have to 
 remember, and in the end it could very likely stomp on the toes of some 
 other future features that would be much more useful.
 
 As far as I can tell, this is just another way to do something we can 
 already do, and all we gain from it is the ability to save two 
 characters on the calling side for functions that are only templated on 
 const values.
 
 --bb

The first thing that struck me with this change was this clear inconsistency: The static parameters are really compile time constants, but they are declared with 'static'. However, outside of function parameters, compile-time constants are declared with invariant and const (as "storage classes"). -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 05 2007
parent Robert Fraser <fraserofthenight gmail.com> writes:
Bruno Medeiros Wrote:

 The first thing that struck me with this change was this clear > inconsistency:
 The static parameters are really compile time constants, but they are 
 declared with 'static'. However, outside of function parameters, 
 compile-time constants are declared with invariant and const (as 
 "storage classes").

Actually, I think this is a problem with the const and invariant terminology. "const" doesn't mean compile-time constant, it means read-only reference. "invariant" means "constant after declaration, can be stored in ROM," but doesn't need to be compile-time resolvable. Plus, both these storage clases already exist, and "static" is a catch-all keyword for any feature not worth adding a real keyword for and doesn't really fit with anything else.
Sep 05 2007