Tuesday, January 17, 2012

TAG-MemoryUsage

Prompted by a discussion in the VWNC mailing list, I decided to write a little tool to help me see where and how much memory is being used by what objects.

Unable to display content. Adobe Flash is required.

Friday, January 13, 2012

Some Edgy Reification

Ever had that experience where you're working on something, and it just feels like something's missing? You muddle on for a while. You begin to suspect there's an object whispering in the digital ether to come into being. When it works out (it doesn't always), I've found it to be one of the more rewarding experiences along the Zen Path of All Objects All The Time.

Working with GUIs and widgets and layout, an object I get to know real well is Rectangle. It's a pretty classic object that you find in many a class library, Smalltalk or otherwise. When working with widget trees and layout, rectangles make a lot of sense, because they store (directly or indirectly) the data you need to approximate most widget's layouts (e.g. top, left, bottom, and right). But when it comes to actually working with layout, my experience has been that often just Rectangles are sub optimal.

Generally, the types of behavior Rectangle supports are methods that work with all or most of the 4 implied values of a rectangle. But much of layout involves dealing with just one side of a rectangle. When we're left aligning some rectangles, we care about their left first, and then possibly all of their rights. So we often see code that looks like

newBox := bounds left + someDelta @ bounds top extent: bounds extent.

We didn't want to have to care about tops or extents.

We could do
aBox left: aBox left + someDelta

but I see less of this pattern actually.

A more involved example (no code) involves determining the bottomRight corner of a rectangle for a widget that may or may not have scrollbars around it. First we check if we need to move the right in for a scrollbar, and do so by the thickness if necessary. Then we use that width to determine if we need to show a horizontal scrollbar now. And now if we adjusted for that, we have to check one more time to see if we didn't need a vertical scrollbar before but do now. We care about first the right side, then the bottom side, then the right side.

Another pattern I've seen is that there are many types of widgets and layouts that can be either vertical or horizontal. A row layout container and column layout container are very similar, but one works along the x axis and the other the y axis. Consider a chunk of code that given a list of rectangles, stretch their widths from the leftmost to the rightmost, proportionately by their current widths.

| sumWidth scalar lastRight |
sumWidth := aBoxList inject: 0 into: [:sum :each | sum + each width].
scalar := sumWidth / (aBoxList last right - aBoxList first left).
lastRight := aBoxList first left.aBoxList do:
[:each |
each left: lastRight.
each right: (lastRight := each width * scalar + each left)]


If I want to reuse that same algorithm to work in a vertical direction, I get to copy/paste it and modify as such

| sumHeight scalar lastRight |
sumHeight := aBoxList inject: 0 into: [:sum :each | sum + each height].
scalar := sumHeight / (aBoxList last bottom - aBoxList first top).
lastBottom := aBoxList first top.aBoxList do:
[:each |
each top: lastBottom.
each bottom: (lasBottom := each height * scalar + each top)]


It gets even funner when you're working with points and have to transpose all of the constant x values for constant y values.

The Free Dictionary defines reification as
To regard or treat (an abstraction) as if it had concrete or material existence.

What I found working with these types of problems was that there was an object for a Rectangle's edge that really wanted to come into being. RectangleEdge is an abstract class defining the API, and polymorphic subclasses for TopEdge, LeftEdge, RightEdge, and BottomEdge take care of the particulars. Having an object which reifies the edge of a rectangle allows us to talk about rectangle manipulation at a higher level for many problems.

What follows is an overview of the classes' use and APIs. Followed by a revisit of the above examples, but using edges.

Creation


A particular edge can created by sending leftEdge, rightEdge, bottomEdge, or topEdge to an instance a Rectangle.

aRectangle bottomEdge

Or by sending the message of: to a given EdgeClass
BottomEdge of: aRectangle


A selection of some of the handier high level messages that allow us to talk about rectangle edges more directly

Accessing
complementDistance
"How far apart are I and my complement (opposite) edge?"
position
"The placement value for this edge along either the x or y axis as appropriate."
position: aNumber
"Modify my target rectangle such that the edge I reify is now at aNumber."

Adjusting
-= aDelta
"Modify my position so that it is my current position minus aDelta."
+= aDelta
"Modify my position so that it is the sum of aDelta and my current position."
lineUpWith: anEdge
"Change my position so that I line up with anEdge."

Other Edges
adjacentEdges
"Return the edges that are normal or perpendicular to me."
complementEdge
"Answer the edge of my box that is opposite of me."
sameEdgeOf: aRectangle
"Return the equivalent edge of aRectangle to me."

Testing
attractsEdge: anEdge
"Answer whether I'm the kind of edge that would want to be considered in concert with anEdge for alignment purposes."
linesUpWith: anEdge
"Do I associate with anEdge in alignment considerations?"

There's more than these, but these seemed some of the more obvious. I actually came up with these classes when I first came to work at Cincom and was working on the failed next generation UIPainter with Vassili Bykov called "Splash". Having reified edges was a big help in doing snap to alignment and other interactive layout operations. And I've been using it with the work on skins (see the description of doing scrollbar layout above). And have been using it with layout prototypes on beyond the current Panel idea found in VisualWorks. It's likely it will finally be integrated in a build near you, before our next release.

Circling back around to the original examples, I now write code like

aBox rightEdge -= self scrollbarThickness


I think this makes the code more expressive of what I'm doing, instead of being lost in how I'm trying to manipulate a rectangle to get the same result. The layout algorithm is even more interesting. Parameterizing the code shown with which edge classes to use, one can make it work for either horizontal or vertical manipulation, by just changing one variable:

| sum scalar lastPosition edgeClass |
edgeClass := LeftEdge.sum := aBoxList inject: 0
into: [:sum :each | sum + (edgeClass of: each) complementDistance].
scalar := sum /
((edgeClass of: aBoxList last) complementEdge position - (edgeClass of: aBoxList first) position).
last := (edgeClass of: aBoxList first) position.aBoxList do:
[:each |
| lowEdge |
lowEdge := (edgeClass of: each) position: last.
lowEdge complementEdge
position: (last := lowEdge complementDistance * scalar + lowEdge position)]


This reified Edge object has enabled me to build layout algorithms that can be configured to work in either the x or y directions without having to have lots of code duplication.

Thursday, December 8, 2011

Call for STIC Talk Input

I think I'm going to submit a talk proposal to STIC for the March conference. There are lots of UI/Tools related things I could try and talk about, however there's only 45 minutes given for a talk slot. So I'm putting out a call for talk input. If you are coming to STIC this year, and have to listen to me for 45 minutes, what would I talk about to make the best use of your time?

Some possible thoughts that have crossed my mind:


  • Here's how Skins work, the issues involved, and where we want to go with them

  • Where 15 years of the VW UI framework has gotten us, how we got here, what we don't like, what we do like, and what we want to fix, and how

  • 10000 ft view of how VisualWorks UI framework fits together, do's and don'ts

  • Rolling your own widgets. The old way. And the new way.

  • Stand at the front of the room and let people throw bread rolls at me



or something completely different?

Private or public responses are fine, and thanks for them.

Thursday, October 6, 2011

Sounding Out the View Tree

A couple of days ago, I asked myself the following question:

What would something like jQuery look like in Smalltalk?

What follows is a sort of experience report and overview of what I came up with. It took me about 3 iterations to get to what's described below. I'm unsure at this point whether it's really pretty good, completely wrong, or sorta there but sorta not.

Motivation


My motivation for putting this together was some disturbing patterns I see all to often in VisualWorks (and for many years). The first is the reliance on the builder variable. When the VW UIBuilder assembles an interface from specs, it hangs on to the widgets that had an ID associated with them. You can then use the componentAt: message to retrieve that in application code. Here's an example from CompiledCodeInspector.
changeSelectedField
"..."
self builder == nil ifTrue: [^self].
w := self builder componentAt: #text.
w == nil ifTrue: [^self].
"..."

There are a couple of different problems I have with this. First of all, there's the need to first check if we have a builder. Much of this type of code is writen with a "if the builders there, do this, otherwise who cares" approach. Then we turn around and do a similar check on the result to make sure it's not nil. Later on in this method, not shown, we have to send things like widget and widget controller to it to further manipulate it. #controllerAt:, #wrapperAt:, and #widgetAt: all exist to try and help smooth this out.

We really shouldn't be having code needed to retain artifacts of the assembling process to get at widgets. That information ought to be encapsulated with the widgets themselves. But instead, we have to worry about whether we have enough state yet in two different places to determine whether we can act or not. And what we get back is... well it's a Wrapper. Usually. Of some sort. But usually we want the view object. And so we have to become intimately familiar with what was constructed and how it is related to be able to get at it.

We also may have to worry about where it's actually stored at. In the case of subcanvasing, where a different builder is used to assemble subsets of UI, we end up with cases like found in the ClassCreationDialog, where we have to add an extra instance variable to keep track of those subbuilders, just so we can use the componentAt: methods. The widgets are there in the view tree, but alas, the only way to get at them is from the builder.

To see examples of the second pattern that bothers me, do this.

  1. Open a System Browser

  2. Select all Packages using Ctrl-a

  3. Select the Rewrite tool (in the mid page tab control)

  4. Enter ``@r container container in the Search for: box

  5. Click the Search... button and wait for the result



One of the more egregious examples is found in SpinButtonController
pressAction
| compositeView inputBoxController |
"..."
compositeView := view container container.
inputBoxController := compositeView controller.
(view spin: inputBoxController view model value) ifFalse: [^self].
compositeView container container takeKeyboardFocus

Two times in the same method, the code walks up the view tree. Not just with one container send, but with two. There's explicit assumptions being made here about the structure of the view tree. Needing to have one widget reach out and communicate with another is not terrible. But exploiting the particular structure of the view tree violates encapsulation. This kind of a code is a huge headache for us as we consider how to move beyond and reduce the amount of Wrappers in our view trees. Getting rid of WidgetStateWrappers is actually probably achievable, but every site like this will need to be fixed. The only information we should realistically be exploiting is that "somewhere above me is an object that fulfills a role I know about and I'd like to talk to it."

Three Interesting Aspect of jQuery


First of all, I am not a jQuery expert. I've played a little with it. Read about it. Asked questions about it. In those forays, there were three basic properties that intrigued me about it:

  1. Ability to specify a criteria to match against widgets in a DOM.

  2. The idea that it is always a collectionish thing that is returned, whether it has 0, 1, or many matches.

  3. Terseness, which allows the programmer to see more code that has to do with manipulating the matches, rather than lots of code finding matches.



Building a Query Model in Smalltalk


The first thing I set out to do was build a Query model for view trees. The jQuery selectors have at least 4 kinds of general queries.


  1. Type (e.g. $("div") )

  2. Id (e.g. $("#cancelButton") )

  3. Class (e.g. $(".demoGroup") )

  4. Attribute (e.g. $("[checked ='false']") )



I started with a basic Query object. A query can be asked if it matches: aViewTreeElement. Different subclasses capture different kinds of matches.

Type Queries


These are probably the easiest to map over. DOM's have things like div and table elements. VisualWorks view trees also have different types of elements, embodied as different Class behaviors. The only real difference, is that you have inheritance in the Smalltalk world. So you might want to match all subtypes of Wrapper. This is why I called it a TypeQuery instead of a ClassQuery. You can make one like

Query type: Wrapper


Id Queries


The skin work we've been doing in the next version of VisualWorks adds an id/id: API to VisualPart. It turns out that if we insert a leading line in the following UILookPolicy method
widgetWrapperWrapping: aWrapper decorator: aDecorator component: aComponent state: aWidgetState spec: aSpec colors: colors isOpaque: opaqueFlag inBuilder: aBuilder
| sw dt |
aComponent id: aSpec name.
"...."

Once that happens, any name of a widget given in the UIPainter is applied as the id of the actual view object (not one wrapper or another). You can make an IdQuery with

Query id: #okButton


Class Queries (or Tag Queries)


In css, which jQuery leverages, you can attach one or more arbitrary "class" attributes to an element. It's like being able to keyword tag subsets of widgets. One might, for example, have a set of widgets that all close a dialog: "Overwrite All", "Overwrite Older", "Overwrite None", and "Cancel". One could set the class of these buttons to be ".dialogAction".

We currently have nothing like this in the VisualWorks view tree. But it might be nice to have. Because the word "Class" already has a very canonized and entrenched meaning in Smalltalk, I chose to use a different name for these. I called them tags. Three methods are added to VisualPart to support this:


  • tag: anObject "adds anObject as a tag to the receiver"

  • hasTag: anObject "returns whether the receiver has anObject attached to it as a tag"

  • untag: anObject "removes anObject as a tag from the receiver, if it is there"



I think my thought for these, like Id's, is that they would usually be Symbol objects, but there's actually nothing that says they couldn't be more complex objects. A TagQuery would be created with an expression like

Query tag: #dialogActions


Attribute Queries (or Block Queries)


I did not create something like Attribute Queries. The VisualWorks view tree elements don't have rigorously defined attributes. But they do respond to messages of course. So I just generalized this so that you could use a BlockClosure (actually any object that responds to cull:) to select elements. For example

Query block: [:element | element isEnabled]


But one could do weirder things with it

"all widgets in the lower half of a window"
Query block: [:each | (each localPointToGlobal: Point zero) y >= aWindow bounds center y]


would be used to select view tree elements that currently respond true to isEnabled. The astute reader will note that the previous three query's could all be emulated with a BlockQuery.

Logical Combinators


For full expression's sake, I also added a NotQuery, and AndQuery and an OrQuery.
(Query type: Button) | (Query id: #okField) "Either inherits from Button or has id of #okButton"
(Query type: Wrapper) & (Query block: [:each | each component isNil]) "All wrappers with no component set yet"
(Query tag: #header) not "Everything that is not tagged #header"


View Trees as Collections



a jQuery results in a collection of 0 or more elements that you can operate on. We already have a Collection API in Smalltalk. I wasn't interested in rolling a new or specific one of those. I'd rather leverage what I can do already with existing Collections. So the other half of this is the ability to create a collection facade to a view tree, rooted in one or more existing tree elements.

ViewTreeSet is a subclass of Collection, it implements the necessary messages and inherits all of the other services that Collection already provides. jQuery (I believe) always searches the whole DOM tree, top down. Where our focus is at the specific widget level, I did not want to restrict it to that. Two specific classes currently exist for ViewTreeSet. One goes down the view tree, traversing the child elements of the roots, and the other goes up, traversing the parents up to the topmost element. Putting these two pieces together (the Query and the Collection), these also have a slot for a query. We can ask ApplicationModels, VisualParts, and Windows for either their childViewTree or their parentViewTree. Now we can do things like compute just how many Wrappers are in a current UI?

(self childViewTree query: (Query type: Wrapper)) size


Or we could enable a bunch of widgets

(self childViewTree query: (Query tag: #dialogAnswer))
do: [:each | each enable]


Or programmatically drive the OK button

(self childViewTree query: (Query id: #okButton)) do: [:each | each simulateMousePress]


Or tell a view's appropriate parent to takeKeyboardFocus without worrying how many layers away it is

(self parentViewTree query: (Query type: WidgetWrapper))
do: [:each | each takeKeyboardFocus]



Since a ViewTreeSet is actually derived from a collection of objects, we can ask them for a childViewTree or parentViewTree as well, and then we can stack queries

((self parentViewTree query: (Query type: BorderDecorator)) childViewTree
query: (Query type: Scrollbar)) do: [:each | each invalidate]


In that example, we're first querying upwards to the nearest BorderDecorator, and then querying downwards to find all Scrollbars and forcing them to invalidate (redraw).

I found myself struggling to come up with interesting and fun examples, so I apologize if these seem too esoteric. There's a sort of Chicken-and-Egg problem here. Without the utility, you don't think about what to do with it. And then you have it, and then you begin looking around to see if it's just a solution in search of a problem, if there's real value here. I think at this point, I'm not entirely sure yet.

Trying to Sweeten Things Up



jQuery uses CSS for its selectors, which uses lots of infix/punctation characters to mean individual things and keep things pretty tight and terse. We could do something like that in Smalltalk too. But I was interested in seeing how much mileage I could get out of sticking to Smalltalk legal syntax.

This is a tricky proposition I found. Basically, I anticipate that if the code I had to input to use these were terser, I'd be more likely to use them. But without having used them much, I'm left trying to guess and anticipate exactly what the syntactic sugar I might use would look like.

I basically used 3 tricks to try and get things short and sweet (or bitter and sour maybe).

Binary Selectors



I chose to reduce the common childViewTree query: part of my expressions to the single ? character. And to use ?? for the parent counterpart. The examples from above now become

(self ? (Query type: Wrapper)) size

self ? (Query tag: #dialogAnswer) do: [:each | each enable]

self ? (Query id: #okButton) do: [:each | each simulateMousePress]

self ?? (Query type: WidgetWrapper) do: [:each | each takeKeyboardFocus]

self ?? (Query type: BorderDecorator) ? (Query type: Scrollbar)
do: [:each | each invalidate]


I've toyed with implementing ?! and ??! as well which automatically send not to the argument. Note that the do: Blocks could be shortened by taking advantage of the fact that unary selectors can be cull:'ed in place of those blocks, but we're concentrating on the query part here, not what we do with the results.

Overloading Literals



The second technique to shorten and simplify these, was to make assumptions about certain literal Smalltalk expressions. By having an asUIQuery method sent to arguments of these messages, we can coerce certain common Smalltalk objects into their Query counter part objects. I've added it to Symbol, Class, and BlockClosure. This allows us to shorten 4 of the above examples to

(self ? Wrapper) size

self ? #okButton do: [:each | each simulateMousePress]

self ?? WidgetWrapper do: [:each | each takeKeyboardFocus]

self ?? BorderDecorator ? Scrollbar do: [:each | each invalidate]


We can do blocks too

self ? TextEditorView ? [:each | each displayContents isEmpty]


The problem I run into with this part is that I haven't devised a way to be able to use Symbols directly as standins for both Id's and Tags. Since we can commute spec names to id's easily, using Symbols directly as Id matches makes the most sense right now. I've toyed with ideas like letting the first character of the Symbol mean something. And generalizing it to CharacterArray. But I could go farther and make String arguments a whole embedded syntax similar to the CSS style that jQuery uses.

Another area where this only goes so far, is that we can't put together complex queries this way. I'm not sure how often those would exist anyway. One could borrow more from the whole ? theme and add more binary selector sugar: ?& to and the argument with the receiver. But we wouldn't be able to do ?|; Smalltalk doesn't allow | as a binary selector, except for by itself.

We could abuse things like Collections too, so that one could easily assemble or lists, something like

self ? #(#okButton #cancelButton) do: [:each | each flash]


From my little playing around, I like the basic techniques here, but I'm not sure how far it scales. Or how far it needs to scale.

Adding Common Actions



Assuming that 90% of the time, we might use something like this to do some common widget behavior, I've added some of those directly to the ViewTreeSet. So then some of the examples from above can be simplified as

(self ? (Query tag: #dialogAnswer)) enable

(self ?? BorderDecorator ? Scrollbar) invalidate


Beyond Cheesy Examples



I did sit down and try to use this on some actual real existing code in the system. The ClassCreationDialog was a good case. It tries to be relatively interactive, and was written by a programmer whose skills I esteem highly: Vassili Bykov. To accomplish what he wanted with VisualWorks standard approaches (plus some technique he added), he had to not only work thru a builder, but retain a reference to intermediate sub builders, so that he could hunt down and update widgets. And a number of helper methods had to be written. I was able to get rid of an instance variable and a family of helper methods, replaced with one longer method, but more expressive (IMO). Here's a screenshot of some of the differences made:



Followed by a screenshot that shows a sample of the kind of change that is made to the longer validateEverything method



The code on the right is longer, but it is no longer so long and involved that it needs to use a helper method to do what it does.

Michael Lucas-Smith suggested I take a look at some of the methods he put together for xPressly, which was used to give his Smalltalk Solutions presentations on xTreams. He had some methods that were forced to do lots of container container container types of things. So I modified it to use this query stuff. It improves the container container nonsense, but it brings into that much more relief how silly it is that you have to go running around in other object to essentially manipulate the one you intended. Fixing that is a problem for another day unfortunately.



Current Conclusions



I don't have any yet. I need more data. There are parts of this I feel right about, other parts I'm not so sure. I'd love to get some feedback. Does this just all sound like a bad idea? Or maybe good idea in spirit, but misguided in implementation? Generally warm to it, but issues with certain details?

If you have some code in the Open Repository that you'd like to see how this would change, I'd love to take a crack at modifying it as a way of taking this stuff for a spin, if your stuff isn't too involved.

Also, I'm still looking for a good name for this stuff. I've currently called it WidgetPath, which I think is a dumb name.

Friday, September 23, 2011

One of the Best Bits of Programming Advice I ever Got

Years ago (early 1992), I attached myself to this crazy skunkworks project that was using this weird language called Smalltalk. "Object Oriented" was in its infancy as a "hot" item. High paid consultants. Lots of people laying claim to what this new object religion was all about. This was 5 years before Alan Kay would make the statement "I invented the term 'Object Oriented Programming' and this {Java and C++} is not what I had in mind."

Shortly after hooking up with this whacky group with the whacky language, still confused about what the difference was between an instance variable, a class variable, and a class instance variable, I found myself in a training course taught by Russ Pencin, of ParcPlace. Russ would say something that I didn't really appreciate at the time. Despite not understanding the point behind this sage advice, I endeavored to follow it. It would take years of experience and exposure to appreciate it's value. The advice?

Don't make objects that end with 'er'.

That's it. The OOP paradigm sprang to life amidst of a culture of what we called "procedural programming." Now days we don't talk so much about the comparison between the two paradigms. Probably in part because Object Oriented languages are now a dime a dozen. The OOP religion, in a multitude of flavors won out. Sadly, I often find myself echoing words I heard Adele Goldberg say around 2000: "Now days we have lots of Object Oriented Programming, but not so many Object Oriented Programmers". If there was one piece of advice I would pass on to the hordes of would be Object Oriented Programmers, it would be the sage advice offered by Russ: "Don't make objects that end with 'er'."

What's in a name anyway? Why is this worth getting excited about? What I've discovered over the years, is that the jst of OOP is that we bind behavior to data. As long as you haven't joined in the Functional Monks in their Monasteries of Statelessness, programs are made of behavior and data. In classic structured/programming, we concentrate on behavior (verbs), and then figure out what data (nouns) we need to make it all work. In other words, we bind data to behavior. But in OOP, we make the locus of programs be the nouns, the data, and then we figure out what kind of behavior we can bind to them, and hope that the problems we hope to solve gel out of the emergent behaviors.

I recently posited to a colleague that in nearly every "er" object case, there was a better name for it. And that giving it a better name would tend to make the design more encapsulated, less spaghetti code, in short more object oriented. It's not a hard and fast rule, but there are a lot of cases where it can improve things.

Take some sort of "Loader" for example. The focus here is on the unit of work it does. It'll have lots of instance variables, lots of arguments, and pass lots of data around probably. Now instead replace that with a LoadRecord and a LoadStream. I'm reasonably confident you'll end up with something that is more akin to what the original Founding Fathers of OOP had in mind. We want to create objects that describe what they are, and then bind behavior to them, rather than focus on what they do, and then figure out what data they'll need to do that.

Some er's that I've learned to avoid over the years:

  • Managers - Every time I see one of these, I cringe. People will usually tell me what it does, long before they can tell me what it is. Is it a registry? Fine call it a registry. Is it a history or a log? Call it that. Is it a factory? Call it that.
  • Controllers - Only good controller object I've made in the last 20 years was an interface to a BallastVoltageController that represented a real world object. The fact that every single MVC implementation in the world has had a different role for Controller ought to tell us something about how well that idea fit.
  • Organizer (and many like them) - Focus is on what it does. This is a great example of how easy it is to turn many of these 'ers' into nouns. Call it an Organization. Now we're focusing on what it is.
  • Analyzer/Renderer/etc - Definitely examples of "worker" objects. What if they had been Analysis/Rendering/etc.
  • Builder/Loader/Reader/Writer/etc - Remove the focus from the objects being manipulated, and tend assume to much responsibility themselves.
There's lots of exceptions to such a rule of course.
  • There are lots of noun words that end in 'er'. Register. Border. Character. Number. If it's really a noun, fine.
  • There are many 'er' words that despite their focus on what they do, have become so commonplace, that we're best to just stick with them, at least in part. Parser. Compiler. Browser.
  • When you are trying to model a domain object that ends in 'er'. I'm fine with a Manager subclass of Personel, which is there to refine a type of personal that has management behavior to it.
Your mileage may vary, I'm sure there are those that disagree with this. Until you apply the mindset for a while though, you'll never really know. Give it a whirl on one of your projects/designs and see what happens.

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.

A thought about field identifiers

When I was playing with template field substitution last couple of days, I was again reminded that the common Smalltalk substitution syntax (John Brant informs me that it is indeed in more than just VisualWorks and Squeak) is really frustrating to use for any sort of HTML/XML generation. The use of the < and > means you have to constantly escape those characters in your templates if you are generating any kind of output that you actually want to include the alligator brackets.

And a thought occurred to me. As long as I'm not generating HTML or XML, I couldn't think of a better field identifying character to use. There are some others such as { } or [ ] that work visually as well. But for the last 15+ years, we've all been reading more and more and more of the "when Lisp met alligators" syntax. It's been pounded mercilessly into our brains. We've all gotten quite accustomed to parsing, in our heads, the text shows up between brackets, apart from the rest. Because of that, using them as field identifiers, is actually the best thing possible.

It's the meta that's the achilles heel. When you want to use these same field separators to generate other field separators. In other words, I could posit that if HTML/XML had used { } to enclose tags, we'd find ourselves appreciating it in a substitution syntax the most, and hating it most when we tried to use it to generate more of the same.