www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - String Metaprogramming

reply "Clayton" <johnsjdsd gmail.com> writes:
Am new to D programming, am considering it since it supports 
compile-time function execution . My challenge is how can I 
re-implement the function below so that it is fully executed in 
compile-time. The function should result to tabel1 being computed 
at compile-time. There seems to be a lot of mutation happening 
here yet I have heard no mutation should take place in 
meta-programming as it subscribes to functional programming 
paradigm.



void computeAtCompileTime( ref string pattern ,ref int[char] 
tabel1){
	int size = to!int(pattern.length) ;
	
	foreach( c; ALPHABET){
		tabel1[c] = size;
	}
	
	for( int i=0;i<size -1 ; ++i){   //Initialise array
		tabel1[pattern[i]] = size -i-1;

         pragma(msg, format("reached pattern  
table1[pattern[i]]=(%s) here",
         table1[pattern[i]].stringof  ~"     v="~ (size 
-i-1).stringof));
	}

	
	
	
}
Jul 18 2015
next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Saturday, 18 July 2015 at 13:48:20 UTC, Clayton wrote:
 There seems to be a lot of mutation happening here yet I have 
 heard no mutation should take place in meta-programming as it 
 subscribes to functional programming paradigm.
That's not true in D, you can just write a regular function and evaluate it in a compile time context, like initializing a static variable. You usually don't need to write special code for compile time stuff in D.
Jul 18 2015
parent reply "Clayton" <johnsjdsd gmail.com> writes:
On Saturday, 18 July 2015 at 13:56:36 UTC, Adam D. Ruppe wrote:
 On Saturday, 18 July 2015 at 13:48:20 UTC, Clayton wrote:
 There seems to be a lot of mutation happening here yet I have 
 heard no mutation should take place in meta-programming as it 
 subscribes to functional programming paradigm.
That's not true in D, you can just write a regular function and evaluate it in a compile time context, like initializing a static variable. You usually don't need to write special code for compile time stuff in D.
Thanks , you were right . It seems there are some key words though which one has to use so that the code gets executed on compile-time .For example I had to change the second forloop to a foreach loop, and then put and enum to ensure that TableFromCompiler gets evaluated at compiletime. Having written the code this way though gives rise to some other question, D supports 2 approches to compiletime metaprogramming i.e. CTFE and Templates, it seems am not very sure which paradigm my code falls in. import std.stdio; import std.string; import std.conv; I[C] computeAtCompileTime(S ,C,I)( const S pattern ){ I[C] table1; const int size = to!int(pattern.length) ;//Length of the pattern to be matched foreach( c; ALPHABET){ //Initialise array table1[c] = size; } foreach(i; 0..size-1){ table1[pattern[i]] = size -i-1; } return table1; } void main(){ enum TableFromCompiler = computeAtCompileTime!(const string ,char, int)(pattern); writeln(TableFromCompiler); }
Jul 18 2015
parent "anonymous" <anonymous example.com> writes:
On Saturday, 18 July 2015 at 16:18:30 UTC, Clayton wrote:
 Thanks , you were right . It seems there are some key words 
 though which one has to use so that the code gets executed on 
 compile-time .For example I had to change the second forloop to 
 a foreach loop,
`for` loops work just fine in CTFE. `foreach` is usually nicer, though (regardless of CTFE or not).
 and then put and enum to ensure that TableFromCompiler gets 
 evaluated at compiletime. Having written the code this way 
 though gives rise to some other question, D supports 2 
 approches to compiletime metaprogramming i.e. CTFE and 
 Templates, it seems am not very sure which paradigm my code 
 falls in.
Your computeAtCompileTime is a template that results in a function when instantiated. You're calling such a generated function and you're assigning the result to an enum, which makes it a CTFE call. So there's both CTFE and a template in your code. You could probably do the whole pre-computation without CTFE, using only templates. But (here) CTFE is more straight forward as you can just write normal run time D.
Jul 18 2015
prev sibling next sibling parent "E.S. Quinn" <anonymous example.com> writes:
On Saturday, 18 July 2015 at 13:48:20 UTC, Clayton wrote:
 Am new to D programming, am considering it since it supports 
 compile-time function execution . My challenge is how can I 
 re-implement the function below so that it is fully executed in 
 compile-time. The function should result to tabel1 being 
 computed at compile-time. There seems to be a lot of mutation 
 happening here yet I have heard no mutation should take place 
 in meta-programming as it subscribes to functional programming 
 paradigm.



 void computeAtCompileTime( ref string pattern ,ref int[char] 
 tabel1){
 	int size = to!int(pattern.length) ;
 	
 	foreach( c; ALPHABET){
 		tabel1[c] = size;
 	}
 	
 	for( int i=0;i<size -1 ; ++i){   //Initialise array
 		tabel1[pattern[i]] = size -i-1;

         pragma(msg, format("reached pattern  
 table1[pattern[i]]=(%s) here",
         table1[pattern[i]].stringof  ~"     v="~ (size 
 -i-1).stringof));
 	}

 	
 	
 	
 }
Actually, the main things you can't do in CTFE are FPU math operations (much of std.math has issues unfortunately), compiler intrinsics, pointer/union operations, and I/O. I don't immediately see anything that will cause issues with CTFE in that function. However, sometimes the compiler isn't smart enough to figure out that it should be doing that, but you can force the compiler to try CTFE using this pattern int ctfeFunc() { } void main() { enum val = ctfeFunc(); } enums are manifest constants, and thus must be computable at compile time, so this will issue an error if something in your function can't CTFE.
Jul 18 2015
prev sibling parent reply "Nicholas Wilson" <iamthewilsonator hotmail.com> writes:
On Saturday, 18 July 2015 at 13:48:20 UTC, Clayton wrote:
 Am new to D programming, am considering it since it supports 
 compile-time function execution . My challenge is how can I 
 re-implement the function below so that it is fully executed in 
 compile-time. The function should result to tabel1 being 
 computed at compile-time. There seems to be a lot of mutation 
 happening here yet I have heard no mutation should take place 
 in meta-programming as it subscribes to functional programming 
 paradigm.
 void computeAtCompileTime( ref string pattern ,ref int[char] 
 tabel1){
change function signature to int[char] function(string) or as the char type is the index probably better of as int[256] function(string). also probably no need to take pattern by ref as it is effectively struct{ size_t length; char* ptr;}. also we aren't going to modify it. int[256] computeAtCompileTime(string pattern) {
 	int size = to!int(pattern.length) ;
pattern.length is a size_t no need to change its type in another variable. you are unlikely to be dealing with string longer than 2^32 (also signedness) but w/e int[256] ret; // implicitly initialised to int.init (i.e. 0)
 	
 	foreach( c; ALPHABET){
 		tabel1[c] = size;
 	}
 	
 	for( int i=0;i<size -1 ; ++i){   //Initialise array
 		tabel1[pattern[i]] = size -i-1;
can just foreach over pattern foreach(i, c; pattern) ret[c] = pattern.length - i -1;
         pragma(msg, format("reached pattern  
 table1[pattern[i]]=(%s) here",
         table1[pattern[i]].stringof  ~"     v="~ (size 
 -i-1).stringof));
 	}
 }
if you want this to be not callable at runtime then wrap the main body (sans variable declaration) with if (__ctfe) { ... }
Jul 18 2015
parent reply "Clayton" <johnsjdsd gmail.com> writes:
On Saturday, 18 July 2015 at 16:01:25 UTC, Nicholas Wilson wrote:
 On Saturday, 18 July 2015 at 13:48:20 UTC, Clayton wrote:
 [...]
 [...]
change function signature to int[char] function(string) or as the char type is the index probably better of as int[256] function(string). also probably no need to take pattern by ref as it is effectively struct{ size_t length; char* ptr;}. also we aren't going to modify it. int[256] computeAtCompileTime(string pattern) {
 [...]
pattern.length is a size_t no need to change its type in another variable. you are unlikely to be dealing with string longer than 2^32 (also signedness) but w/e int[256] ret; // implicitly initialised to int.init (i.e. 0)
 [...]
can just foreach over pattern foreach(i, c; pattern) ret[c] = pattern.length - i -1;
 [...]
 [...]
if you want this to be not callable at runtime then wrap the main body (sans variable declaration) with if (__ctfe) { ... }
Thanks Nicholas , I have integrated some of your advice on the edited code i.e. foreach and ref in pattern . Hope I fully understood what you meant. Am yet to look whether I still need to change the signature . I have heared there are two approaches to this, Where does one really draw the line between CTFE and Template metaprogramming?
Jul 18 2015
parent "Tamas" <foldenyi.tamas gmail.com> writes:
 Thanks  Nicholas , I have integrated some of your advice on the 
 edited code i.e. foreach and ref in pattern . Hope I fully 
 understood  what you meant. Am yet to look whether I still need 
 to change the signature . I have heared there are two 
 approaches to this, Where does one really draw the line between 
 CTFE and Template metaprogramming?
Template metaprogramming == "abuse the template facility in C++ to run a program in compile time" used to be the only way to execute something at compile time in C++. In D you don't want to do that as writing such code is a matter of putting an enum or static at the right place. Still, you can use templates to achieve your goal, if that helps.
Jul 18 2015