Wednesday, September 21, 2011

Don't Try This At Home: Stealing from the stack

I think there are days, when I want to do things I know I shouldn't as a programmer. Do others experience this. Some have said that Smalltalk is like a gun, that "with great power comes great responsibility." Some times, some of the tricks tempt me, and if I know no one's looking (read: I'm not going to be putting this in any production code), I find myself looking around for opportunities to flex a little bit of language super power muscle. Just for the grins. Just because I can.

Messing with thisContext and the stack is one of those things. When I was implementing the _1:_2:_3:_4:_5: message I was talking about the other day.

The proper and boring way to implement it was like this:
_1: one _2: two _3: three _4: four _5: five

| arguments |
arguments := Array new: 5.
arguments at: 1 put: one.
arguments at: 2 put: two.
arguments at: 3 put: three.
arguments at: 4 put: four.
arguments at: 5 put: five.
^(StringParameterSubstitution default)
originalString: self;
args: arguments;
expandedText


But, I didn't want to do that. That was too much typing I think. I wanted to be clever, so I did this instead:

_1: one _2: two _3: three _4: four _5: five

^(StringParameterSubstitution default)
originalString: self;
args: (thisContext stack copyFrom: 1 to: 5);
expandedText


There are no references to any of the method arguments. Knowing that the stack is already an array with the arguments already placed in them, exactly what I want, I just grab that, instead of making my own array populated with the method arguments.

Don't do this in production code. It's tricky and evil. But sometimes, it's good to remind yourself, or learn from others, what this great environment really is capable of doing. Who knows, having one be aware of it, there may come a point where playing with thisContext or the stack, may help you solve a real problem, in production code, or not.

1 comment:

  1. While I agree that this is a cool demo, what's wrong with

    _1: one _2: two _3: three _4: four _5: five
    ^(StringParameterSubstitution default)
    originalString: self;
    args: {one. two. three. four. five};
    expandedText

    Seems concise enough, yet explicit to me :)

    ReplyDelete