So I have this chunk of code that interfaces with some Windows DLLs. And it has one of these great interfaces that goes like "call this function that takes more arguments than a large semi truck has wheels, and some of them are arrays, and some of them are how big the arrays are, and if your arrays aren't big enough for the task at hand, we'll respond with an particular error, and then you make your arrays bigger and try again."
Calling the code doesn't lend itself very well to a method extraction, since I have to set up a bunch of parameters via DLLCC pointers and such. So I end up with a largish method that looks like:
do a bunch of setup.
set a candidate size.
[increment the candidate size and allocate more stuff accordingly.
result := make the call.
result == needMoreMemory] whileTrue.
commit to the final sizes
clean more stuff up
The thing is, I'm fascinated by papers and talks about memory managers and garbage collectors. Apparently, one of the growth vectors that ends up working really well at balancing too rapid growth, versus not fast enough, is the Fibonacci Series. I decided I'd like to increment my candidate size along the Fibonacci line.
With all the code I had in the method though, I didn't want to waste a bunch of code that was about incrementing to the next Fibonacci number. And that's where the post subject came into play. I was looking for a simple one liner to ratchet a Fibonacci number forward, and stumbled on it
a := b + (b := a)
I thought it was cool for a number of reasons. The symmetry itself appealed to me, both of the operands and variable names, and at the same time the way the parentheses played an asymmetric role.
This kinda "tricky" would be risky (I just rhymed) in C with an optimizer turned on. Luckily, Smalltalk is pretty good about guaranteeing its order of method evaluation. So what I'm really doing here is "stealing from the stack" to avoid having to have an intermediate variable. The old value of b is placed on the stack first, and then b is updated, but since the original value is on the stack already, I get the addition I want.
So I thought it was kinda elegant, sort of simple even, but definitely tricky. Probably too tricky, since people have to look at it to figure out what's doing. What do you think? Am I even close to that "fine line"?
Elegant just like Squeak gcd:
ReplyDelete[n = 0]
whileFalse:
[n := m \\ (m := n)].
nicolas.cellier.aka.nice
Eww! Plus is supposed to be commutative! (On the other hand, it *is* kind of elegant. Kind of. You'll definitely need to add a comment explaining it, though, which might detract from the elegance of the whole...)
ReplyDeleteI have to spend time reading a tricky coder's code. Being scarred by that, I'd choose simple, boring and easy to understand over elegant and tricky.
ReplyDeleteMy personal dogma is "make it easy to read a year from now, when you've forgotten everything".
Still, it is neat.
I think it legitimate. A Smalltalker should find the order of evaluation in that line straightforward. Bad 'tricky' code is code where what it does is not what the reader will think it does, or they will bang their head against a wall trying to work out what it does.
ReplyDelete