| Thread overview | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|
|
May 16, 2011 correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dmerrio | > 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dmerrio | > 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Trass3r | 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Timon Gehr | > 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dmerrio | 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to dmerrio | 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 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to Kai Meyer | Thank you for the reply. Potential, but there still seems to be alot of repetitive code. | |||
May 16, 2011 Re: correct way to create boiler plate code | ||||
|---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 | |||
Copyright © 1999-2021 by the D Language Foundation
Permalink
Reply