www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - correct way to create boiler plate code

reply dmerrio <rdmerrio gmail.com> writes:
I am parsing some formulas from a spreadsheet file. To duplicate
the behavior of the spreadsheet functions, I am having to create a
lot of boiler plate code that maps from the spreadsheet functions
to the built-in functions. Mixin would seem to allow me to
automate the boiler-plate creation, but i am not utilizing it
correctly. What is the correct to call Mixin in this situation, or
is their a better way to create the boiler-plate code?

For background, i am new to D. D is my second language with my
primary experience being a script kiddie in Excel VBA, so take it
slow, please.



import main; //class definition of rng
import std.math; //trig functions
import std.conv; //to!double
import std.string; //toupper

double transFunc(alias transedentalFunc)(rng aRng){
	try{return(transedentalFunc(aRng.getCellValue().coerce!
(double)));} //cellValue stored as a Variant
	catch{return(transedentalFunc(to!double(aRng.getCellValue
().coerce!(string))));} //replicate spreadsheet behavior and
convert to a number
}

//Example 1 of boilerplate code
double SIN(double aReal){return(sin(aReal));}
double SIN(string aStr){return(sin(to!double(aStr)));}
double SIN(rng aRng){return(transFunc!(sin)(aRng));}

//Example 2 of boilerplate code
double COS(double aReal){return(cos(aReal));}
double COS(string aStr){return(cos(to!double(aStr)));}
double COS(rng aRng){return(transFunc!(cos)(aRng));}

string[] funcs = ["tan"];
void createFuncs(){
	foreach(func; funcs){
		mixin("double " ~ toupper(func) ~ "(double aReal)
{return(" ~ func ~ "(aReal));}");
	}
}

calling mixin a compile time has the following error...

Error	1	Error: variable func cannot be read at compile time
	C:\D\SVNProjects\trunk\xcellD\xcell1\trig.d	22


thanks for your help
May 16 2011
next sibling parent reply Trass3r <un known.com> writes:
 string[] funcs = ["tan"];
 calling mixin a compile time has the following error...

 Error	1	Error: variable func cannot be read at compile time
 	C:\D\SVNProjects\trunk\xcellD\xcell1\trig.d	22
That's because funcs is mutable. Try to make it immutable or enum.
May 16 2011
parent dmerrio <rdmerrio gmail.com> writes:
changing the relevent code, changes the error, but it still does
not compile...

immutable funcs = ["tan"];
void createFuncs(){
	foreach(func; funcs){
		mixin("double " ~ toupper(func) ~ "(double aReal)
{return(" ~ func ~ "(aReal));}");
	}
}

new error...
Error	1	Error: argument to mixin must be a string, not
("double TAN(double aReal){return(" ~ func ~ "(aReal));}")
	C:\D\SVNProjects\trunk\xcellD\xcell1\trig.d	24


Thanks for the suggestion, any others????
May 16 2011
prev sibling next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
 I am parsing some formulas from a spreadsheet file. To duplicate
 the behavior of the spreadsheet functions, I am having to create a
 lot of boiler plate code that maps from the spreadsheet functions
 to the built-in functions. Mixin would seem to allow me to
 automate the boiler-plate creation, but i am not utilizing it
 correctly. What is the correct to call Mixin in this situation, or
 is their a better way to create the boiler-plate code?

 For background, i am new to D. D is my second language with my
 primary experience being a script kiddie in Excel VBA, so take it
 slow, please.
hi, Disregard the other answer, making func immutable won't solve your problem.
 string[] funcs = ["tan"];
 void createFuncs(){
  foreach(func; funcs){
   mixin("double " ~ toupper(func) ~ "(double aReal)
 {return(" ~ func ~ "(aReal));}");
  }
 }
foreach runs at runtime, while mixin is expanded at compile time. If you want to inject your boilerplate into module namespace, you would rather write a function that generates the code and mixin the result of a call to that function: string[] funcs = ["tan"]; string createFuncs(){ string res; foreach(func; funcs){ res~="double " ~ toupper(func) ~ "(double aReal){return(" ~ func ~ "(aReal));}"; } return res; } mixin(createFuncs());
May 16 2011
parent Trass3r <un known.com> writes:
 foreach runs at runtime, while mixin is expanded at compile time.
Not the whole truth though. foreach over tuples gets unrolled at compile time so you can do stuff like: // +=, -=, ... Vector opOpAssign(string op, U)(U s) { foreach (i, _; tuple) mixin("tuple[i] " ~ op ~ "= s;"); return this; }
May 16 2011
prev sibling next sibling parent reply Kai Meyer <kai unixlords.com> writes:
On 05/16/2011 01:08 PM, dmerrio wrote:
 I am parsing some formulas from a spreadsheet file. To duplicate
 the behavior of the spreadsheet functions, I am having to create a
 lot of boiler plate code that maps from the spreadsheet functions
 to the built-in functions. Mixin would seem to allow me to
 automate the boiler-plate creation, but i am not utilizing it
 correctly. What is the correct to call Mixin in this situation, or
 is their a better way to create the boiler-plate code?

 For background, i am new to D. D is my second language with my
 primary experience being a script kiddie in Excel VBA, so take it
 slow, please.



 import main; //class definition of rng
 import std.math; //trig functions
 import std.conv; //to!double
 import std.string; //toupper

 double transFunc(alias transedentalFunc)(rng aRng){
 	try{return(transedentalFunc(aRng.getCellValue().coerce!
 (double)));} //cellValue stored as a Variant
 	catch{return(transedentalFunc(to!double(aRng.getCellValue
 ().coerce!(string))));} //replicate spreadsheet behavior and
 convert to a number
 }

 //Example 1 of boilerplate code
 double SIN(double aReal){return(sin(aReal));}
 double SIN(string aStr){return(sin(to!double(aStr)));}
 double SIN(rng aRng){return(transFunc!(sin)(aRng));}

 //Example 2 of boilerplate code
 double COS(double aReal){return(cos(aReal));}
 double COS(string aStr){return(cos(to!double(aStr)));}
 double COS(rng aRng){return(transFunc!(cos)(aRng));}

 string[] funcs = ["tan"];
 void createFuncs(){
 	foreach(func; funcs){
 		mixin("double " ~ toupper(func) ~ "(double aReal)
 {return(" ~ func ~ "(aReal));}");
 	}
 }

 calling mixin a compile time has the following error...

 Error	1	Error: variable func cannot be read at compile time
 	C:\D\SVNProjects\trunk\xcellD\xcell1\trig.d	22


 thanks for your help
This works: //import main; //class definition of rng import std.math; //trig functions import std.conv; //to!double import std.string; //toupper import std.stdio; void main() { mixin(createFunc!("sin")); mixin(createFunc!("cos")); mixin(createFunc!("tan")); writeln(SIN(0)); // 0 writeln(COS(0)); // 1 writeln(TAN(0)); // 0 return; } template createFunc(string func){ const char[] createFunc = "double " ~ toupper(func) ~ "(double aReal) {return(" ~ func ~ "(aReal));}"; } Stole it from http://www.digitalmars.com/d/2.0/mixin.html I don't think there's a way to use an array of strings, since (as pointed out by others and your error message) that mixins are done compile-time and foreach are done (mostly) at run-time.
May 16 2011
parent dmerrio <rdmerrio gmail.com> writes:
Thank you for the reply. Potential, but there still seems to be
alot of repetitive code.
May 16 2011
prev sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
dmerrio:

 import main; //class definition of rng
 import std.math; //trig functions
 import std.conv; //to!double
 import std.string; //toupper
 
 double transFunc(alias transedentalFunc)(rng aRng){
 	try{return(transedentalFunc(aRng.getCellValue().coerce!
 (double)));} //cellValue stored as a Variant
 	catch{return(transedentalFunc(to!double(aRng.getCellValue
 ().coerce!(string))));} //replicate spreadsheet behavior and
 convert to a number
 }
 
 //Example 1 of boilerplate code
 double SIN(double aReal){return(sin(aReal));}
 double SIN(string aStr){return(sin(to!double(aStr)));}
 double SIN(rng aRng){return(transFunc!(sin)(aRng));}
Mine is not an answer that directly helps you solve your problem. Experience shows that messy code doesn't help you see your problems, and sometimes it even hides bugs. So I suggest you to reformat your code in a more human way, use more normal naming conventions, and use named imports if you want to import just some names. This means writing: import std.conv: to; Instead of: import std.conv; //to!double To put a newline before the closing brace, to add spaces and newlines where they are belong, and so on. This helps a lot. Bye, bearophile
May 16 2011
parent dmerrio <rdmerrio gmail.com> writes:
Thanks for the formatting tips. Copy and pasting kind of messed up
the formatting, not that it was good to start with. I am still
developing a coding style.

== Quote from bearophile (bearophileHUGS lycos.com)'s article
 dmerrio:
 import main; //class definition of rng
 import std.math; //trig functions
 import std.conv; //to!double
 import std.string; //toupper

 double transFunc(alias transedentalFunc)(rng aRng){
 	try{return(transedentalFunc(aRng.getCellValue().coerce!
 (double)));} //cellValue stored as a Variant
 	catch{return(transedentalFunc(to!double(aRng.getCellValue
 ().coerce!(string))));} //replicate spreadsheet behavior and
 convert to a number
 }

 //Example 1 of boilerplate code
 double SIN(double aReal){return(sin(aReal));}
 double SIN(string aStr){return(sin(to!double(aStr)));}
 double SIN(rng aRng){return(transFunc!(sin)(aRng));}
Mine is not an answer that directly helps you solve your
problem. Experience shows that messy code doesn't help you see your problems, and sometimes it even hides bugs. So I suggest you to reformat your code in a more human way, use more normal naming conventions, and use named imports if you want to import just some names.
 This means writing:
 import std.conv: to;
 Instead of:
 import std.conv; //to!double
 To put a newline before the closing brace, to add spaces and
newlines where they are belong, and so on. This helps a lot.
 Bye,
 bearophile
May 16 2011