Thread overview
correct way to create boiler plate code
May 16, 2011
dmerrio
May 16, 2011
Trass3r
May 16, 2011
dmerrio
May 16, 2011
Timon Gehr
May 16, 2011
Trass3r
May 16, 2011
Kai Meyer
May 16, 2011
dmerrio
May 16, 2011
bearophile
May 16, 2011
dmerrio
May 16, 2011
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
> 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
> 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
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
> 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
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
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
Thank you for the reply. Potential, but there still seems to be alot of repetitive code.
May 16, 2011
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