Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

Sneaky Internal State

Name: Anonymous 2012-03-28 23:59

I've boiled what I want out of a programming language down to a single example.  Problems like this bite me in the ass often and I haven't used a language, yet, that helps.

Suppose I'm writing a library for working with vectors.  For simplicity, it's not fancy n-dimensional vectors, etc., let's say just three floats.  So I write some code to perform operations on vectors, like add, subtract, dot product, cross product, rotate, scale... and then I come to "normalize."

Here, I come up with this optimization that vectors could also store a flag indicating whether or not they are normal.  If that flag is set, then normalize has no work to do.  The catch is that I have to decide which operations clear the flag, which operations set it, and which operations leave it unchanged.  So I do the work and end up with a nice, efficient vector library.

I use my library for a long time -- long enough that I stop caring how that optimization worked.  Eventually, months later, I decide to add some new functions to my vector library.  Of course, I've forgotten all about the "normal" flag, and I forget to set/clear it in the new functions.  Of course, there's no compile error or even a run-time error.  I just observe strange behavior when the application runs and I have to spend hours stepping through floating-point math to figure out what's wrong.

How does your language of choice improve this situation?

Name: Anonymous 2012-03-29 2:37

>>17

Let me write an example here:


f(vector x, vector y)
{
  vector nx = normalize(x);
  return nx.dot(y);
}
main()
{
  vector u = normalize(readVector());
  vector v = vector(1.3, 2.3, 1.0);
  print(f(u,v));
}


If the compiler can prove that u is normalized when f is called on it, at compile time, then it can call an alternate definition of f that does not create a normalized version of the first parameter:


fZomgOptimized(vector nx, vector y)
{
  return nx.dot(y);
}

f(vector x, vector y)
{
  return fZomgOptimized(normalize(x), y)
}
main()
{
  vector u = normalize(readVector());
  vector v = vector(1.3, 2.3, 1.0);
  print(fZomgOptimized(u,v));
}


Here a normalization is omitted, and there is no need to check a flag. Because like you said, the normalize function will return a normalized vector, 100% of the time, there is no need to check to see if it is normalized or not at run time. The compiler can infer this at compile time.

With adding vectors it is a lot less intuitive. It's usually not going to be unit length, unless there is some kind of pattern. And maybe this pattern can be seen at compile time. But if it is usually not going to be unit length, then you may as well always normalize it. Even if you sometimes normalize a vector that is already normalized, you could save more time doing that in the cases that it happens than checking a flag in every single case.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List