Alright, so sometimes my "coding brain" skips a gear; once in a while you can hear the gears grind. (For instance, every once in a while I write class Foo : Bar {}
before reminding myself that's not proper anymore -- and hasn't been in a long time).
My current MO is to use inline methods as a way to improve code legibility and maintainability without sacrificing speed, but I ran across an issue recently that made me question this practice.
So, given (the admittedly contrived) code like:
double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Magic Formula. This does what?
a = b + c - (b * c);
...
I will write:
double a;
double b = 0.0;
double c = 0.0;
...
// do some stuff here
...
// skip the sanity checks
// Oh! It's probability!
a = ProbabilisticOr(b, c);
...
inline double ProbabilisticOr(double b, double c)
{
// Skip the Sanity checks
return b + c - (b * c);
}
The math I'm working on right now is fairly complex. If I want a generic CS/CE to be able to maintain it, it has to be written more like the second. The code is also pretty time sensitive.
I've recently run across an issue, as I said above. I made my mathematical constants static const double ...
like a good little programmer; but when trying to access them inline the compiler bombs out for DLLs. The target OS is Linux, but I'm developing on Windows (Visual Studio 2013) and would like to keep it "cross-platform safe".
The solution to this little problem is to take them out-of-line; but, will that hurt my performance? Given the esoteric math involved, readability is a serious issue; but it still has to perform well.
Update:
To clarify, using more / different -- and much more contrived -- code:
#ifndef BUILD_DLL
# define DLL_MODE __declspec(dllimport)
#else
# define DLL_MODE __declspec(dllexport)
#endif
class DLL_MODE ContrivedProbabilityExample
{
public:
inline ContrivedProbabilityExample(double value);
inline ContrivedProbabilityExample& operator+=(double value);
private:
inline void CheckValue(double value);
private:
static const double ZERO_PROB = 0.0;
static const double GUARANTEED_PROB= 1.0;
double probability;
private:
// Not implemented
ContrivedProbabilityExample();
};
inline ContrivedProbabilityExample::ContrivedProbabilityExample(double value) : probability(value)
{
CheckValue(value);
}
inline ContrivedProbabilityExample& ContrivedProbabilityExample::operator+=(double value)
{
CheckValue(value);
probability = probability + value - (probability * value);
}
inline void ContrivedProbabilityExample::CheckValue(double value)
{
if(value < ZERO_PROB || value > GUARANTEED_PROB)
throw std::range_error("Hey, whattaya think you're doing?");
}
This code will work fine in Static on both platforms; it will work as a Shared library on Linux. It will give an error under Windows when trying to use it as a DLL. The only solution is to move the CheckValue
method out-of-line.
"old-school" inline
had the CheckValue
method's code being substituted "as-is" where it was called from; apparently "new-school" inline does ... nothing? (Since the compiler apparently does what it wants regardless.)
AFIK The only way to make this work under DLL is to move CheckValue
out-of-line ... which could be a problem for time-sensitive code "old-school" (every call is/was guaranteed function overhead). Is this still a problem? Is there a "better" way to keep this readable; e.g. to not assume that every CS/CE working on my code will be proficient in Statistics?
Note: This is cross-platform, so "the compiler" may not be a meaningful phrase.