digitalmars.D.learn - The power of static if! (A bit of fun)
- Don Clugston (52/52) Oct 25 2005 I really think the docs for "static if" don't do it justice. Since I'm
- Don Clugston (62/62) Oct 26 2005 Here's an improved version, which generates all Fibonnacci numbers which...
- Sean Kelly (8/13) Oct 26 2005 Very cool. I hadn't thought to use pragma(msg) in that way :-) Nor had...
- Don Clugston (14/31) Oct 27 2005 It was pure speculation on my part. I did not expect either of those
- Walter Bright (4/11) Oct 28 2005 This is perfect stuff for a magazine article. If you want to prepare one...
- Georg Wrede (5/19) Oct 29 2005 Guys, this is just awesome!
- Derek Parnell (9/31) Oct 29 2005 Ok, I'll expose my ignorance here, but why is this such a fanfare item? ...
- Don Clugston (21/54) Nov 02 2005 Yes, calculating PI is largely useless, the only reason for using PI is
- Sean Kelly (7/12) Nov 02 2005 Agreed. Blitz++ is a good example of some practical uses for this sort
- Sean Kelly (13/26) Nov 02 2005 I just saw your post in the other forum. That would cover everything
- Don Clugston (32/68) Nov 02 2005 Hmmm. That's a definite possible direction. I suspect, though, that it's...
- BCS (9/77) Nov 02 2005 How about a function attribute of "state"? It would mean that the return...
- Ivan Senji (10/22) Oct 27 2005 really nice work. And when that promotion bug is fixed so things can be
- Don Clugston (12/39) Oct 27 2005 Indeed. Even better would be if a constant index of an array of
- Ivan Senji (14/28) Oct 27 2005 I would expect this to work instead of getting the odd "non-constant
- Ivan Senji (7/20) Oct 27 2005 Correction: it works in
- Don Clugston (9/23) Oct 27 2005 It means it didn't evaluate it at compile time.
- Ivan Senji (5/23) Oct 27 2005 I hope so.
- Sean Kelly (6/15) Oct 27 2005 Another surprise. So constants can be initialized at run time via stati...
- Burton Radons (5/25) Nov 01 2005 Colour me surprised, this is an actual intended feature - if a const
- Derek Parnell (35/40) Nov 01 2005 Yeah! I really wanted this feature and I didn't realize it existed eithe...
- Kris (11/37) Nov 01 2005 Nice! Now if only we could make the assigment at the declaration site,
- Derek Parnell (46/50) Nov 01 2005 Huh? If they *must* be overridden, how does their function body get
- Kris (22/74) Nov 01 2005 I haven't tried compiling or running any of these, so please take these
- Bruno Medeiros (8/16) Nov 02 2005 Hum, should this be allowed? Is it even possible (at source code level)
- Walter Bright (6/19) Nov 05 2005 elsewhere.
- pragma (49/54) Nov 05 2005 NOTE: Please, for the love of all that's sane, do not use the following ...
- Derek Parnell (16/38) Nov 05 2005 Walter, you did not answer my issue with this. I repeat it from my earli...
- Sean Kelly (12/26) Nov 01 2005 It's similar to this in C++:
- Bruno Medeiros (7/11) Nov 02 2005 Hum... thus, that's a case where it's not true that "The const attribute...
- Sean Kelly (4/14) Oct 27 2005 This would be extremely cool. And it seems like it shouldn't be terribl...
- Walter Bright (3/5) Oct 28 2005 I'm not familiar with that bug?
- Ivan Senji (9/18) Oct 28 2005 Sorry not a bug, you said it was a limitation.
- Walter Bright (3/11) Oct 28 2005 I'm still not sure what you mean. Can you refresh my memory?
- Ivan Senji (11/28) Oct 29 2005 Sorry again, i don't know why i called it promotion, i should have said
- Walter Bright (3/13) Oct 29 2005 Ok, I understand now. Don also posted this issue.
I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_. Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language. Enjoy! ----------------------------- template inttostr(int n) { template digittostr(int n) { static if (n==0) const char [] s="0"; else static if (n==1) const char [] s="1"; else static if (n==2) const char [] s="2"; else static if (n==3) const char [] s="3"; else static if (n==4) const char [] s="4"; else static if (n==5) const char [] s="5"; else static if (n==6) const char [] s="6"; else static if (n==7) const char [] s="7"; else static if (n==8) const char [] s="8"; else const char [] s="9"; } static if (n<0) const char [] s = "-" ~ inttostr!(-n).s; else static if (n<10) const char [] s = digittostr!(n).s; else const char [] s = inttostr!(n/10).s ~ digittostr!(n%10).s; } template ordinal(int n) { static if (n==1) const char [] ordinal = inttostr!(n).s ~"st"; else static if (n==2) const char [] ordinal = inttostr!(n).s ~"nd"; else static if (n==3) const char [] ordinal = inttostr!(n).s ~"rd"; else const char [] ordinal = inttostr!(n).s ~"th"; } template fib(int n) { static if (n==0) const int f=0; else static if (n==1) const int f=1; else const int f = fib!(n-1).f + fib!(n-2).f; static if (n>0) { pragma(msg, "The " ~ ordinal!(n).ordinal ~ " Fibonnacci number is "~ inttostr!(fib!(n-1).f).s); } } int main() { return fib!(30).f; ButItWontActuallyCompile; }
Oct 25 2005
Here's an improved version, which generates all Fibonnacci numbers which are small enough to fit in the given integral type. Try changing the last line to short, uint, ulong, etc. This is something that would be *extremely* hard to do in C++. I just wish I could improve the digittostr function. Tested on DMD-Windows 0.136 and 0.137. ------------------- // Works for any integral type. template inttostr(Type, Type n) { template digittostr(int n) { static if (n==0) const char [] s="0"; else static if (n==1) const char [] s="1"; else static if (n==2) const char [] s="2"; else static if (n==3) const char [] s="3"; else static if (n==4) const char [] s="4"; else static if (n==5) const char [] s="5"; else static if (n==6) const char [] s="6"; else static if (n==7) const char [] s="7"; else static if (n==8) const char [] s="8"; else const char [] s="9"; } static if (Type.min<0 && n<0) const char [] s = "-" ~ inttostr!(-n).s; else static if (n<10) const char [] s = digittostr!(n).s; else const char [] s = inttostr!(Type, n/10).s ~ digittostr!(n%10).s; } template ordinal(int n) { static if (n%10==1 && n!=11) const char [] ordinal = inttostr!(int, n).s ~"st"; else static if (n%10==2 && n!=12) const char [] ordinal = inttostr!(int, n).s ~"nd"; else static if (n%10==3 && n!=13) const char [] ordinal = inttostr!(int, n).s ~"rd"; else const char [] ordinal = inttostr!(int, n).s ~"th"; } // Calculate the nth Fibonnacci number template fib(Type, int n) { static if (n==1) const Type f=0; else static if (n==2) const Type f=1; else const Type f = fib!(Type, n-1).f + fib!(Type, n-2).f; } template showallfibs(Type) { template showfibs(Type, int n) { pragma(msg, "The " ~ ordinal!(n).ordinal ~ " Fibonnacci number is "~ inttostr!(Type, fib!(Type, n).f).s); static if (fib!(Type, n).f < Type.max/2) { const int show = showfibs!(Type,n+1).show; } else { const int show = 0; pragma(msg, "The " ~ ordinal!(n+1).ordinal ~ " Fibonnacci number is greater than " ~ inttostr!(Type, Type.max).s); } } const int notfinished = showfibs!(Type, 1).show; } static assert(showallfibs!(long).notfinished);
Oct 26 2005
In article <djn8dp$93g$1 digitaldaemon.com>, Don Clugston says...I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.Very cool. I hadn't thought to use pragma(msg) in that way :-) Nor had I realized that the concatenate operator worked on const declarations. This is probably the most template-oriented thing I've done in D so far: http://svn.dsource.org/projects/ares/trunk/src/ares/std/atomic.d Not as fancy, but it's far more compact and readable than it would have been in C++ (note that the unsigned versions don't work because of a compiler bug). Sean
Oct 26 2005
Sean Kelly wrote:In article <djn8dp$93g$1 digitaldaemon.com>, Don Clugston says...It was pure speculation on my part. I did not expect either of those things to work. I haven't yet worked out what a 'literal' is in D, but it is much more generous than C++. For example, casts are permitted. This isI really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_.Very cool. I hadn't thought to use pragma(msg) in that way :-) Nor had I realized that the concatenate operator worked on const declarations.probably the most template-oriented thing I've done in D so far: http://svn.dsource.org/projects/ares/trunk/src/ares/std/atomic.d Not as fancy, but it's far more compact and readable than it would have been in C++ (note that the unsigned versions don't work because of a compiler bug).Nice. I haven't used the 'is' operator yet, I think it has enormous potential too. And now we have 'auto' typing... I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now). Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.
Oct 27 2005
"Don Clugston" <dac nospam.com.au> wrote in message news:djput7$1822$1 digitaldaemon.com...I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now). Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.This is perfect stuff for a magazine article. If you want to prepare one, I can get you in with the publisher(s).
Oct 28 2005
Walter Bright wrote:"Don Clugston" <dac nospam.com.au> wrote in message news:djput7$1822$1 digitaldaemon.com...Guys, this is just awesome! It took Don to show us what Walter has created! I'm getting the impression it's time to throw my meta stuff out the window. ;-(I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now). Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.This is perfect stuff for a magazine article. If you want to prepare one, I can get you in with the publisher(s).
Oct 29 2005
On Sun, 30 Oct 2005 01:38:17 +0300, Georg Wrede wrote:Walter Bright wrote:Ok, I'll expose my ignorance here, but why is this such a fanfare item? Its just a fancy way to declare literals, no? And who needs PI calculated at compile time anyway - just hard code the literal - it ain't changing anytime soon. What am I missing? -- Derek Parnell Melbourne, Australia 30/10/2005 10:01:06 AM"Don Clugston" <dac nospam.com.au> wrote in message news:djput7$1822$1 digitaldaemon.com...Guys, this is just awesome! It took Don to show us what Walter has created! I'm getting the impression it's time to throw my meta stuff out the window. ;-(I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now). Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.This is perfect stuff for a magazine article. If you want to prepare one, I can get you in with the publisher(s).
Oct 29 2005
Derek Parnell wrote:On Sun, 30 Oct 2005 01:38:17 +0300, Georg Wrede wrote:Yes, calculating PI is largely useless, the only reason for using PI is that everyone knows what it should be. But in general, the feature allows you to replace most 'magic numbers' with the program which was used to create them. Even more interesting to me is the possibility of creating lookup tables at compile time. Examples: * the table which is used for isalpha(), ispunct(), etc. * the table of primes in the BigInt library of Deimos. In both these cases, it's obvious that another program was written to generate those tables. Where is it now? Is it bug-free? What if you decide you need a bigger lookup table? With the metaprogramming possibilities in D, we don't need another program. Caveat: right now, lookup tables can only be created using strings to store the data, because ~ is evaluated early only for strings, and [] is never evaluated early. But I think both those limitations are emminently fixable. It's interesting also because it gives most of the capability of languages like LISP, but with syntax that is closer to C, and consequently much more intelligible for C/C++ programmers. It's a case where D is venturing into unexplored territority.Walter Bright wrote:Ok, I'll expose my ignorance here, but why is this such a fanfare item? Its just a fancy way to declare literals, no? And who needs PI calculated at compile time anyway - just hard code the literal - it ain't changing anytime soon. What am I missing?"Don Clugston" <dac nospam.com.au> wrote in message news:djput7$1822$1 digitaldaemon.com...Guys, this is just awesome! It took Don to show us what Walter has created! I'm getting the impression it's time to throw my meta stuff out the window. ;-(I've also made a template that calculates pi at compile time by summing a power series. I have hopes that I can make it work to arbitrary precision (it only does reals right now). Seriously, this compiler is *far* more advanced than the programming techniques we've developed to use it. Now that we know that a compile-time itoa() is possible, and even a basic compile-time printf, I can imagine a whole compile-time library.This is perfect stuff for a magazine article. If you want to prepare one, I can get you in with the publisher(s).
Nov 02 2005
Don Clugston wrote:It's interesting also because it gives most of the capability of languages like LISP, but with syntax that is closer to C, and consequently much more intelligible for C/C++ programmers. It's a case where D is venturing into unexplored territority.Agreed. Blitz++ is a good example of some practical uses for this sort of thing (http://www.oonumerics.org/blitz/), but this sort of code generation is difficult to impossible with C++. All we need now is built-in support for lists and we'll practically have a real LISP front-end on D :) Sean
Nov 02 2005
Sean Kelly wrote:Don Clugston wrote:I just saw your post in the other forum. That would cover everything but typelists, which would be quite useful for template specialization and such: template fn(T : [int,long]) { void fn() {} } I suppose the declarative form might be: const type t = [int,long]; Though I'm not sure whether being able to declare a typelist makes sense as it would allow things like this: static if( ... ) t[0] var; else char var; Thoughts? SeanIt's interesting also because it gives most of the capability of languages like LISP, but with syntax that is closer to C, and consequently much more intelligible for C/C++ programmers. It's a case where D is venturing into unexplored territority.Agreed. Blitz++ is a good example of some practical uses for this sort of thing (http://www.oonumerics.org/blitz/), but this sort of code generation is difficult to impossible with C++. All we need now is built-in support for lists and we'll practically have a real LISP front-end on D :)
Nov 02 2005
Sean Kelly wrote:Sean Kelly wrote:Don Clugston wrote:I just saw your post in the other forum. That would cover everything but typelists, which would be quite useful for template specialization and such: template fn(T : [int,long]) { void fn() {} } I suppose the declarative form might be: const type t = [int,long]; Though I'm not sure whether being able to declare a typelist makes sense as it would allow things like this: static if( ... ) t[0] var; else char var; Thoughts?It's interesting also because it gives most of the capability of languages like LISP, but with syntax that is closer to C, and consequently much more intelligible for C/C++ programmers. It's a case where D is venturing into unexplored territority.Agreed. Blitz++ is a good example of some practical uses for this sort of thing (http://www.oonumerics.org/blitz/), but this sort of code generation is difficult to impossible with C++. All we need now is built-in support for lists and we'll practically have a real LISP front-end on D :)SeanHmmm. That's a definite possible direction. I suspect, though, that it's not as important for D as for Lisp. We already have normal template type parameters, structs, and indexed arrays. I'm a bit worried about painting ourselves into a corner when we don't even know how big the room is yet :-) Another radical possibility: Imagine that itoa!(int) was an allowable overload for itoa(int). The rationale is, the function itoa!(int) is not a template at all. Instead, it's a function that operates on compile-time constants, turning them into other compile-time constants. It should never result in any code being generated in the executable. The minimal syntax change to allow this would be by creating const aliases. const alias itoa!(long n).s char[] itoa(long n); This means: if you see a call to itoa() where the parameter n is known at compile time, you should use the template instead of the normal itoa() function. But the ideal would be to have (say) const int as a type which is distinct from int, having a value which is known at compile time, and potentially treated differently. (This is completely different to const in C++, which doesn't seem to mean much at all). Any such function could be used in compile-time expressions like static assert and static if. So when you write writef( itoa(x) ); and if at compile time x is known to be 7, then this compiles to writef(itoa!(7).s); ----> writef("7"); but if the value of x is unknown (either because it reaches that line at different times with more than one value, or because the compiler can't work it out what the single value is), it just uses itoa(x). I'm sure there are lots of problems with this idea -- I'm just beginning to think about it. I can't see how it could be done with D's simple function overloading.
Nov 02 2005
How about a function attribute of "state"? It would mean that the return value of the function is only a function of it's arguments (and it's only side effect is it's return). This would mean that if a function has the state attribute and it's arguments are known at compile time, then it's return can also be found at compile time (more or less what Don Clugston suggested under a different name). The important aspect of this is that the compiler would only allow code in such a function that it knows can be evaluated and removed at compile time. This would also eliminate the use of a template and a function doing the same thing. In article <dkarbt$2j3$1 digitaldaemon.com>, Don Clugston says...Sean Kelly wrote:Sean Kelly wrote:Don Clugston wrote:I just saw your post in the other forum. That would cover everything but typelists, which would be quite useful for template specialization and such: template fn(T : [int,long]) { void fn() {} } I suppose the declarative form might be: const type t = [int,long]; Though I'm not sure whether being able to declare a typelist makes sense as it would allow things like this: static if( ... ) t[0] var; else char var; Thoughts?It's interesting also because it gives most of the capability of languages like LISP, but with syntax that is closer to C, and consequently much more intelligible for C/C++ programmers. It's a case where D is venturing into unexplored territority.Agreed. Blitz++ is a good example of some practical uses for this sort of thing (http://www.oonumerics.org/blitz/), but this sort of code generation is difficult to impossible with C++. All we need now is built-in support for lists and we'll practically have a real LISP front-end on D :)SeanHmmm. That's a definite possible direction. I suspect, though, that it's not as important for D as for Lisp. We already have normal template type parameters, structs, and indexed arrays. I'm a bit worried about painting ourselves into a corner when we don't even know how big the room is yet :-) Another radical possibility: Imagine that itoa!(int) was an allowable overload for itoa(int). The rationale is, the function itoa!(int) is not a template at all. Instead, it's a function that operates on compile-time constants, turning them into other compile-time constants. It should never result in any code being generated in the executable. The minimal syntax change to allow this would be by creating const aliases. const alias itoa!(long n).s char[] itoa(long n); This means: if you see a call to itoa() where the parameter n is known at compile time, you should use the template instead of the normal itoa() function. But the ideal would be to have (say) const int as a type which is distinct from int, having a value which is known at compile time, and potentially treated differently. (This is completely different to const in C++, which doesn't seem to mean much at all). Any such function could be used in compile-time expressions like static assert and static if. So when you write writef( itoa(x) ); and if at compile time x is known to be 7, then this compiles to writef(itoa!(7).s); ----> writef("7"); but if the value of x is unknown (either because it reaches that line at different times with more than one value, or because the compiler can't work it out what the single value is), it just uses itoa(x). I'm sure there are lots of problems with this idea -- I'm just beginning to think about it. I can't see how it could be done with D's simple function overloading.
Nov 02 2005
Don Clugston wrote:I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_. Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language. Enjoy!really nice work. And when that promotion bug is fixed so things can be writen this way: template inttostr(int n) { static if (n<0) const char [] inttostr = "-" ~ .inttostr!(-n); else static if (n<10) const char [] inttostr = digittostr!(n); else const char [] inttostr = .inttostr!(n/10) ~ digittostr!(n%10); } it will be even nicer and easier!
Oct 27 2005
Ivan Senji wrote:Don Clugston wrote:Indeed. Even better would be if a constant index of an array of constants, was a literal. Then digittostr would just be template digittostr(int n) { const char [] digittostr="0123456789"[n]; } at which point it becomes a genuine functional programming language, because you can manipulate lists. (Right now I've shown you can create an arbitrary list, but AFAIK you can't peek inside it). But maybe there's some syntax it will accept right now. Walter's created a monster. Who knows what it can do!I really think the docs for "static if" don't do it justice. Since I'm new to D templates, I've been trying to come up with a more interesting example than the one in the docs. Here's my first attempt. This program prints a nicely-formatted list of the first 30 Fibonnacci numbers _at compile time_. Note that except for the clunky 'inttostr' template (which is a general utility template, could be quite useful in other contexts), it's not much longer than a straightforward implementation in a functional programming language. Enjoy!really nice work. And when that promotion bug is fixed so things can be writen this way: template inttostr(int n) { static if (n<0) const char [] inttostr = "-" ~ .inttostr!(-n); else static if (n<10) const char [] inttostr = digittostr!(n); else const char [] inttostr = .inttostr!(n/10) ~ digittostr!(n%10); } it will be even nicer and easier!
Oct 27 2005
Don Clugston wrote:Indeed. Even better would be if a constant index of an array of constants, was a literal. Then digittostr would just be template digittostr(int n) { const char [] digittostr="0123456789"[n]; }I would expect this to work instead of getting the odd "non-constant expression "0123456789"[5]" error. But this works :) template digittostr(int n) { const char[] digittostr; static this() { digittostr = "0123456789"[n..n+1]; } } But unfortunately this way we can't have implicit promotion.at which point it becomes a genuine functional programming language, because you can manipulate lists. (Right now I've shown you can create an arbitrary list, but AFAIK you can't peek inside it). But maybe there's some syntax it will accept right now. Walter's created a monster. Who knows what it can do!Indeed!
Oct 27 2005
Ivan Senji wrote:But this works :)Correction: it works in writefln(digittostr!(0).digittostr); but not at compile time with pragma(msg,digittostr!(0).digittostr); Strange. What does "string expected for message, not 'digittostr'" mean anyway??template digittostr(int n) { const char[] digittostr; static this() { digittostr = "0123456789"[n..n+1]; } } But unfortunately this way we can't have implicit promotion.
Oct 27 2005
Ivan Senji wrote:Ivan Senji wrote:It means it didn't evaluate it at compile time. We're so close! I've also tried this way: const char q[][] = ["0", "1", "2", "3","4","5","6","7","8","9"]; const char[] digittostr = q[n]; but it gives the string as q[3], not "3". It seems that [] is never evaluated at compile time, but it's fascinating that ~ is.But this works :)Correction: it works in writefln(digittostr!(0).digittostr); but not at compile time with pragma(msg,digittostr!(0).digittostr); Strange. What does "string expected for message, not 'digittostr'" mean anyway??
Oct 27 2005
Don Clugston wrote:Ivan Senji wrote:Yes, i figured out this was the problem.Strange. What does "string expected for message, not 'digittostr'" mean anyway??It means it didn't evaluate it at compile time.We're so close!I hope so.I've also tried this way: const char q[][] = ["0", "1", "2", "3","4","5","6","7","8","9"]; const char[] digittostr = q[n]; but it gives the string as q[3], not "3". It seems that [] is never evaluated at compile time, but it's fascinating that ~ is.Yes it is fascinating, i hope this is a bug and not by spec. Maybe to solve this problem a little Walter-intervention is needed?
Oct 27 2005
In article <djq9pn$1jo5$1 digitaldaemon.com>, Ivan Senji says...But this works :) template digittostr(int n) { const char[] digittostr; static this() { digittostr = "0123456789"[n..n+1]; } }Another surprise. So constants can be initialized at run time via static this? I thought the format always had to be: const T t = val; Interesting. Sean
Oct 27 2005
Sean Kelly wrote:In article <djq9pn$1jo5$1 digitaldaemon.com>, Ivan Senji says...Colour me surprised, this is an actual intended feature - if a const value isn't given an initialiser, it can be given one in a static constructor. It can also be used for write-once fields in a class: http://www.digitalmars.com/d/attribute.html#constBut this works :) template digittostr(int n) { const char[] digittostr; static this() { digittostr = "0123456789"[n..n+1]; } }Another surprise. So constants can be initialized at run time via static this? I thought the format always had to be: const T t = val; Interesting.
Nov 01 2005
On Tue, 01 Nov 2005 14:26:49 +0000, Burton Radons wrote:Colour me surprised, this is an actual intended feature - if a const value isn't given an initialiser, it can be given one in a static constructor. It can also be used for write-once fields in a class: http://www.digitalmars.com/d/attribute.html#constYeah! I really wanted this feature and I didn't realize it existed either. Sample code: --------------------------- import std.stdio; const int code_A, code_B, code_C, code_D, code_E; static this() { int v = 1; code_A = v++; code_B = v++; code_C = v++; code_D = v++; code_E = v++; } void main() { writefln("%d %d %d %d %d ", code_A, code_B, code_C, code_D, code_E ); } -- Derek (skype: derek.j.parnell) Melbourne, Australia 2/11/2005 10:39:21 AM
Nov 01 2005
Nice! Now if only we could make the assigment at the declaration site, rather than just within static-ctors (the compiler could create an implicit static-ctor in the same way that it creates module-ctors :-) e.g. const Foo f = new Foo; Also new to me was this little nugget at the bottom of the page: "Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide 'base class functionality.' " ... Suuweeeet! When did that happen? Hats' off to Walter for these two. "Burton Radons" <burton-radons smocky.com> wrote in message news:dk8q3b$136s$1 digitaldaemon.com...Sean Kelly wrote:In article <djq9pn$1jo5$1 digitaldaemon.com>, Ivan Senji says...Colour me surprised, this is an actual intended feature - if a const value isn't given an initialiser, it can be given one in a static constructor. It can also be used for write-once fields in a class: http://www.digitalmars.com/d/attribute.html#constBut this works :) template digittostr(int n) { const char[] digittostr; static this() { digittostr = "0123456789"[n..n+1]; } }Another surprise. So constants can be initialized at run time via static this? I thought the format always had to be: const T t = val; Interesting.
Nov 01 2005
On Tue, 1 Nov 2005 15:49:22 -0800, Kris wrote:Also new to me was this little nugget at the bottom of the page: "Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide 'base class functionality.' " ... Suuweeeet! When did that happen?Huh? If they *must* be overridden, how does their function body get executed? In fact, I've tried a few tests and it seems that they do not have to be overridden anyway. Also, it seems that the only thing that 'abstract' does is allow the compiler to issue an error rather than catch it at link time. Sample without 'abstract': --------------------- import std.stdio; class CC_base { void funcX(); } class myClass : CC_base { } void main() { myClass cc = new myClass; cc.funcX(); } ------------------ This compiles okay but crashes at link time " Error 42: Symbol Undefined _D4test7CC_base5funcXFZv". If I put the 'abstract' on the class declaration it has no effect. The linker still aborts. If I put it on the member function "abstract void funcX();" then the compiler detects a problem "cannot create instance of abstract class myClass". If I give the function a body ... abstract void funcX() { writefln("Base functionality"); } it compiles, links and runs okay. The 'abstract' function which is *not* overridden gets run. If I remove the 'abstract' but retain the body there is no change. The 'abstract' doesn't seem to do anything with regards to forcing the function to be overridden. So it seems that if you give an abstract function a body then the 'abstract' is ignored. -- Derek (skype: derek.j.parnell) Melbourne, Australia 2/11/2005 10:52:14 AM
Nov 01 2005
I haven't tried compiling or running any of these, so please take these comments with a grain of salt: 1) In the cases without a function body, the linker is doing the right thing. That "no body" syntax states the symbol will be resolved elsewhere. You must add "abstract" to the method declaration to get the desired behaviour, as you did in the third case. 2) The way I read the abstract documentation is thus: "an abstract method can provide basic implementation, which may or may not be taken advantage of by an overriding implementation". Hence, a subclass must provide a matching & overriding method (upon the superclass abstract method). However, said subclass method can simply invoke super.functionName(args) to get the default behavior. If, as you indicate, an abstract method with a body does not actually /require/ subclass implementation, then the use of "abstract" on the superclass method is entirely superfluous ~ and the documentation claims would thus be bogus (since the compiler would behave the same with & without the superclass "abstract" method modifer). I sincerely hope this indicates a bug in the compiler as opposed to a waft of hot air from the documentation ;-) - Kris "Derek Parnell" <derek psych.ward> wrote in message news:nvxauw987u1e$.h217vqke1lia$.dlg 40tude.net...On Tue, 1 Nov 2005 15:49:22 -0800, Kris wrote:Also new to me was this little nugget at the bottom of the page: "Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide 'base class functionality.' " ... Suuweeeet! When did that happen?Huh? If they *must* be overridden, how does their function body get executed? In fact, I've tried a few tests and it seems that they do not have to be overridden anyway. Also, it seems that the only thing that 'abstract' does is allow the compiler to issue an error rather than catch it at link time. Sample without 'abstract': --------------------- import std.stdio; class CC_base { void funcX(); } class myClass : CC_base { } void main() { myClass cc = new myClass; cc.funcX(); } ------------------ This compiles okay but crashes at link time " Error 42: Symbol Undefined _D4test7CC_base5funcXFZv". If I put the 'abstract' on the class declaration it has no effect. The linker still aborts. If I put it on the member function "abstract void funcX();" then the compiler detects a problem "cannot create instance of abstract class myClass". If I give the function a body ... abstract void funcX() { writefln("Base functionality"); } it compiles, links and runs okay. The 'abstract' function which is *not* overridden gets run. If I remove the 'abstract' but retain the body there is no change. The 'abstract' doesn't seem to do anything with regards to forcing the function to be overridden. So it seems that if you give an abstract function a body then the 'abstract' is ignored. -- Derek (skype: derek.j.parnell) Melbourne, Australia 2/11/2005 10:52:14 AM
Nov 01 2005
Kris wrote:I haven't tried compiling or running any of these, so please take these comments with a grain of salt: 1) In the cases without a function body, the linker is doing the right thing. That "no body" syntax states the symbol will be resolved elsewhere. You must add "abstract" to the method declaration to get the desired behaviour, as you did in the third case.Hum, should this be allowed? Is it even possible (at source code level) to declare a class method *outside* of the class declaration itself? (à la C++) -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Nov 02 2005
"Bruno Medeiros" <daiphoenixNO SPAMlycos.com> wrote in message news:4368A9E1.5050003 SPAMlycos.com...Kris wrote:elsewhere.I haven't tried compiling or running any of these, so please take these comments with a grain of salt: 1) In the cases without a function body, the linker is doing the right thing. That "no body" syntax states the symbol will be resolvedYes, it makes it possible to provide the implementation of a class function in another language, such as assembly, C, or even Fortran!You must add "abstract" to the method declaration to get the desired behaviour, as you did in the third case.Hum, should this be allowed?Is it even possible (at source code level) to declare a class method *outside* of the class declaration itself? (à la C++)Not in D, but in another language, yes.
Nov 05 2005
In article <dkjhqm$2hg2$1 digitaldaemon.com>, Walter Bright says..."Bruno Medeiros" <daiphoenixNO SPAMlycos.com> wrote in messageNOTE: Please, for the love of all that's sane, do not use the following in production code, unless someone puts a gun to your head. Otherwise, Cuthulu himself will awake from his ancient slumber and devour all of mankind, starting with you. :) In the spirit of this thread, I took walter's words here as a direct challenge, as I felt pretty sure D could be put to task here. Technically, Walter is correct. D wasn't designed with partial classes, from within D, in mind. His hint above, that other languages could be used for this facility, got me thinking that this could be done. It is possible to work around this by clever use of the compiler, and tricking the linker. So here is the hack: ////////////////// module test_a; private import std.stdio; class Foobar{ extern(C) uint add(uint a,uint b); // here is your 'empty' method } void main(){ Foobar f = new Foobar(); writefln("test: %d",f.add(42,69)); } /////////////////// module test_b; import test_a; // here is the body of the method (that's not a typeo) extern(C) uint _D6test_a6Foobar3addUkkZk(Foobar _this,uint a,uint b){ return a+b; } ////////////////// Compile: dmd test_a.d test_b.d Run: test_a.exe Output: "test: 111" The trick here is is to use extern(C) as to specify the call-spec on the class-definition (test_a) side, *and* circumvent name-mangling on the method-definition side (test_b). The horribly named symbol you see in test_b is a perfect match for the symbol in test_a, so the linker is satisified and the program runs perfectly. The reason why this works at all is because D does not name-mangle if the symbol defined is at the module level, and does not use the D calling convention. By this, extern(C) has two distinct behaviors, depending on context; this makes sense from a C-programming point of view. Note: I did try using extern(C) *only* on the test_b side (being careful to fetch the last parameter from EAX), but this somehow generates an access violation once main() exits; differences in stack-management between C and D perhaps? Also, you can link the modules one at a time, and ignore the linker errors you get (even when using '-c'); for reasons unknown, these do not interfere with the creation of .obj files one bit. - EricAnderton at yahooIs it even possible (at source code level) to declare a class method *outside* of the class declaration itself? (à la C++)Not in D, but in another language, yes.
Nov 05 2005
On Sat, 5 Nov 2005 15:49:02 -0800, Walter Bright wrote:"Bruno Medeiros" <daiphoenixNO SPAMlycos.com> wrote in message news:4368A9E1.5050003 SPAMlycos.com...Walter, you did not answer my issue with this. I repeat it from my earlier post... It seems that the only thing that 'abstract' does is allow the compiler to issue an error rather than catch it at link time. The 'abstract' function which is *not* overridden gets run. If I remove the 'abstract' but retain the body there is no change. The 'abstract' doesn't seem to do anything with regards to forcing the function to be overridden. So it seems that if you give an abstract function a body then the 'abstract' is ignored. This is *not* what the documentation seems to be saying. -- Derek Parnell Melbourne, Australia 6/11/2005 6:00:19 PMKris wrote:elsewhere.I haven't tried compiling or running any of these, so please take these comments with a grain of salt: 1) In the cases without a function body, the linker is doing the right thing. That "no body" syntax states the symbol will be resolvedYes, it makes it possible to provide the implementation of a class function in another language, such as assembly, C, or even Fortran!You must add "abstract" to the method declaration to get the desired behaviour, as you did in the third case.Hum, should this be allowed?Is it even possible (at source code level) to declare a class method *outside* of the class declaration itself? (à la C++)Not in D, but in another language, yes.
Nov 05 2005
Derek Parnell wrote:On Tue, 1 Nov 2005 15:49:22 -0800, Kris wrote:Awesome!Also new to me was this little nugget at the bottom of the page: "Functions declared as abstract can still have function bodies. This is so that even though they must be overridden, they can still provide 'base class functionality.' " ... Suuweeeet! When did that happen?Huh? If they *must* be overridden, how does their function body get executed?It's similar to this in C++: class C { virtual void fn() = 0 { /* default behavior */ } }; class D : C { virtual void fn() { C::fn(); } };In fact, I've tried a few tests and it seems that they do not have to be overridden anyway. Also, it seems that the only thing that 'abstract' does is allow the compiler to issue an error rather than catch it at link time.Perhaps this bit isn't finished yet. It would be nice if this were enforced as per the spec. Sean
Nov 01 2005
Burton Radons wrote:... It can also be used for write-once fields in a class: http://www.digitalmars.com/d/attribute.html#constHum... thus, that's a case where it's not true that "The const attribute declares constants that can be evaluated at compile time", right? -- Bruno Medeiros - CS/E student "Certain aspects of D are a pathway to many abilities some consider to be... unnatural."
Nov 02 2005
In article <djq81i$1i11$1 digitaldaemon.com>, Don Clugston says...Indeed. Even better would be if a constant index of an array of constants, was a literal. Then digittostr would just be template digittostr(int n) { const char [] digittostr="0123456789"[n]; } at which point it becomes a genuine functional programming language, because you can manipulate lists. (Right now I've shown you can create an arbitrary list, but AFAIK you can't peek inside it). But maybe there's some syntax it will accept right now.This would be extremely cool. And it seems like it shouldn't be terribly difficult to implement, since ~ is already supported in this context. Sean
Oct 27 2005
"Ivan Senji" <ivan.senji_REMOVE_ _THIS__gmail.com> wrote in message news:djq3r9$1dfh$1 digitaldaemon.com...And when that promotion bug is fixed so things can be writen this way:I'm not familiar with that bug?
Oct 28 2005
Walter Bright wrote:"Ivan Senji" <ivan.senji_REMOVE_ _THIS__gmail.com> wrote in message news:djq3r9$1dfh$1 digitaldaemon.com...Sorry not a bug, you said it was a limitation. template factorial(int n) { static if (1) { enum { factorial = n * .factorial!(n-1) } } } No promotion when using static if.And when that promotion bug is fixed so things can be writen this way:I'm not familiar with that bug?
Oct 28 2005
"Ivan Senji" <ivan.senji_REMOVE_ _THIS__gmail.com> wrote in message news:dju3t8$2ida$1 digitaldaemon.com...Sorry not a bug, you said it was a limitation. template factorial(int n) { static if (1) { enum { factorial = n * .factorial!(n-1) } } } No promotion when using static if.I'm still not sure what you mean. Can you refresh my memory?
Oct 28 2005
Walter Bright wrote:"Ivan Senji" <ivan.senji_REMOVE_ _THIS__gmail.com> wrote in message news:dju3t8$2ida$1 digitaldaemon.com...Sorry again, i don't know why i called it promotion, i should have said implicit template properties. Simpler example: template Foo(int n) { static if(n==0) const int Foo; else static if(n==1) const float Foo; else const char[] Foo; } writefln(Foo!(1).Foo); //works writefln(Foo!(1)); //voids have no valueSorry not a bug, you said it was a limitation. template factorial(int n) { static if (1) { enum { factorial = n * .factorial!(n-1) } } } No promotion when using static if.I'm still not sure what you mean. Can you refresh my memory?
Oct 29 2005
"Ivan Senji" <ivan.senji_REMOVE_ _THIS__gmail.com> wrote in message news:djv7p7$gkq$1 digitaldaemon.com...Sorry again, i don't know why i called it promotion, i should have said implicit template properties. Simpler example: template Foo(int n) { static if(n==0) const int Foo; else static if(n==1) const float Foo; else const char[] Foo; } writefln(Foo!(1).Foo); //works writefln(Foo!(1)); //voids have no valueOk, I understand now. Don also posted this issue.
Oct 29 2005