<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7515306875906042828</id><updated>2012-02-16T19:06:03.519-08:00</updated><title type='text'>Objology</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://objology.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2481055512360964076</id><published>2012-01-17T10:06:00.000-08:00</published><updated>2012-01-17T10:07:14.180-08:00</updated><title type='text'>TAG-MemoryUsage</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;&lt;object id="scPlayer" width="1002" height="744" type="application/x-shockwave-flash" data="http://content.screencast.com/users/TravisGriggs/folders/Jing/media/215e3330-a993-4a4f-8bc3-bc7ad66c90e0/jingswfplayer.swf" &gt; &lt;param name="movie" value="http://content.screencast.com/users/TravisGriggs/folders/Jing/media/215e3330-a993-4a4f-8bc3-bc7ad66c90e0/jingswfplayer.swf" /&gt; &lt;param name="quality" value="high" /&gt; &lt;param name="bgcolor" value="#FFFFFF" /&gt; &lt;param name="flashVars" value="thumb=http://content.screencast.com/users/TravisGriggs/folders/Jing/media/215e3330-a993-4a4f-8bc3-bc7ad66c90e0/FirstFrame.jpg&amp;containerwidth=1002&amp;containerheight=744&amp;content=http://content.screencast.com/users/TravisGriggs/folders/Jing/media/215e3330-a993-4a4f-8bc3-bc7ad66c90e0/00000228.swf&amp;blurover=false" /&gt; &lt;param name="allowFullScreen" value="true" /&gt; &lt;param name="scale" value="showall" /&gt; &lt;param name="allowScriptAccess" value="always" /&gt; &lt;param name="base" value="http://content.screencast.com/users/TravisGriggs/folders/Jing/media/215e3330-a993-4a4f-8bc3-bc7ad66c90e0/" /&gt; Unable to display content. Adobe Flash is required. &lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2481055512360964076?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2481055512360964076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2012/01/tag-memoryusage.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2481055512360964076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2481055512360964076'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2012/01/tag-memoryusage.html' title='TAG-MemoryUsage'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-7176334203281592622</id><published>2012-01-13T16:12:00.000-08:00</published><updated>2012-01-14T01:11:26.666-08:00</updated><title type='text'>Some Edgy Reification</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;newBox := bounds left + someDelta @ bounds top extent: bounds extent.&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;We didn't want to have to care about tops or extents.&lt;br /&gt;&lt;br /&gt;We could do&lt;br /&gt;&lt;pre&gt;&lt;code&gt;aBox left: aBox left + someDelta&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;but I see less of this pattern actually.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| sumWidth scalar lastRight |&lt;br /&gt;sumWidth := aBoxList inject: 0 into: [:sum :each | sum + each width].&lt;br /&gt;scalar := sumWidth / (aBoxList last right - aBoxList first left).&lt;br /&gt;lastRight := aBoxList first left.aBoxList do: &lt;br /&gt;    [:each |&lt;br /&gt;    each left: lastRight.&lt;br /&gt;    each right: (lastRight := each width * scalar + each left)]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;If I want to reuse that same algorithm to work in a vertical direction, I get to copy/paste it and modify as such&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| sumHeight scalar lastRight |&lt;br /&gt;sumHeight := aBoxList inject: 0 into: [:sum :each | sum + each height].&lt;br /&gt;scalar := sumHeight / (aBoxList last bottom - aBoxList first top).&lt;br /&gt;lastBottom := aBoxList first top.aBoxList do: &lt;br /&gt;    [:each |&lt;br /&gt;    each top: lastBottom.&lt;br /&gt;    each bottom: (lasBottom := each height * scalar + each top)]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It gets even funner when you're working with points and have to transpose all of the constant x values for constant y values.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.thefreedictionary.com/"&gt;The Free Dictionary&lt;/a&gt; defines &lt;a href="http://www.thefreedictionary.com/reification"&gt;&lt;i&gt;reification&lt;/i&gt;&lt;/a&gt; as&lt;br /&gt;&lt;blockquote&gt;To regard or treat (an abstraction) as if it had concrete or material existence.&lt;/blockquote&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;What follows is an overview of the classes' use and APIs. Followed by a revisit of the above examples, but using edges.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Creation&lt;/h4&gt;&lt;br /&gt;A particular edge can created by sending &lt;i&gt;leftEdge&lt;/i&gt;, &lt;i&gt;rightEdge&lt;/i&gt;, &lt;i&gt;bottomEdge&lt;/i&gt;, or &lt;i&gt;topEdge&lt;/i&gt; to an instance a Rectangle.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;aRectangle bottomEdge&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Or by sending the message &lt;i&gt;of:&lt;/i&gt; to a given EdgeClass&lt;br /&gt;&lt;pre&gt;&lt;code&gt;BottomEdge of: aRectangle&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;A selection of some of the handier high level messages that allow us to talk about rectangle edges more directly&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Accessing&lt;/i&gt;&lt;br /&gt;&lt;b&gt;complementDistance&lt;/b&gt;&lt;br /&gt;"How far apart are I and my complement (opposite) edge?"&lt;br /&gt;&lt;b&gt;position&lt;/b&gt;&lt;br /&gt;"The placement value for this edge along either the x or y axis as appropriate."&lt;br /&gt;&lt;b&gt;position:&lt;/b&gt; aNumber&lt;br /&gt;"Modify my target rectangle such that the edge I reify is now at aNumber."&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Adjusting&lt;/i&gt;&lt;br /&gt;&lt;b&gt;-=&lt;/b&gt; aDelta&lt;br /&gt;"Modify my position so that it is my current position minus aDelta."&lt;br /&gt;&lt;b&gt;+=&lt;/b&gt; aDelta&lt;br /&gt;"Modify my position so that it is the sum of aDelta and my current position."&lt;br /&gt;&lt;b&gt;lineUpWith:&lt;/b&gt; anEdge&lt;br /&gt;"Change my position so that I line up with anEdge."&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Other Edges&lt;/i&gt;&lt;br /&gt;&lt;b&gt;adjacentEdges&lt;/b&gt;&lt;br /&gt;"Return the edges that are normal or perpendicular to me."&lt;br /&gt;&lt;b&gt;complementEdge&lt;/b&gt;&lt;br /&gt;"Answer the edge of my box that is opposite of me."&lt;br /&gt;&lt;b&gt;sameEdgeOf:&lt;/b&gt; aRectangle&lt;br /&gt;"Return the equivalent edge of aRectangle to me."&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Testing&lt;/i&gt;&lt;br /&gt;&lt;b&gt;attractsEdge:&lt;/b&gt; anEdge&lt;br /&gt;"Answer whether I'm the kind of edge that would want to be considered in concert with anEdge for alignment purposes."&lt;br /&gt;&lt;b&gt;linesUpWith:&lt;/b&gt; anEdge&lt;br /&gt;"Do I associate with anEdge in alignment considerations?"&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://blog.3plus4.org/"&gt;Vassili Bykov&lt;/a&gt; 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.&lt;br /&gt;&lt;br /&gt;Circling back around to the original examples, I now write code like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;aBox rightEdge -= self scrollbarThickness&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| sum scalar lastPosition edgeClass |&lt;br /&gt;edgeClass := LeftEdge.sum := aBoxList inject: 0&lt;br /&gt;     into: [:sum :each | sum + (edgeClass of: each) complementDistance].&lt;br /&gt;scalar := sum /&lt;br /&gt; ((edgeClass of: aBoxList last) complementEdge position - (edgeClass of: aBoxList first) position).&lt;br /&gt;last := (edgeClass of: aBoxList first) position.aBoxList do: &lt;br /&gt;    [:each |&lt;br /&gt;    | lowEdge |&lt;br /&gt;    lowEdge := (edgeClass of: each) position: last.&lt;br /&gt;    lowEdge complementEdge&lt;br /&gt;     position: (last := lowEdge complementDistance * scalar + lowEdge position)]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-7176334203281592622?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/7176334203281592622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2012/01/some-edgy-reification.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7176334203281592622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7176334203281592622'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2012/01/some-edgy-reification.html' title='Some Edgy Reification'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-7834807454797553562</id><published>2011-12-08T11:37:00.000-08:00</published><updated>2011-12-08T11:40:14.716-08:00</updated><title type='text'>Call for STIC Talk Input</title><content type='html'>I think I'm going to submit a talk proposal to &lt;a href="http://www.stic.st/conferences/stic12/"&gt;STIC for the March conference&lt;/a&gt;. 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?&lt;br /&gt;&lt;br /&gt;Some possible thoughts that have crossed my mind:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Here's how Skins work, the issues involved, and where we want to go with them&lt;/li&gt;&lt;br /&gt;&lt;li&gt;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&lt;/li&gt;&lt;br /&gt;&lt;li&gt;10000 ft view of how VisualWorks UI framework fits together, do's and don'ts&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Rolling your own widgets. The old way. And the new way.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Stand at the front of the room and let people throw bread rolls at me&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;or something completely different?&lt;br /&gt;&lt;br /&gt;Private or public responses are fine, and thanks for them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-7834807454797553562?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/7834807454797553562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/12/call-for-stic-talk-input.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7834807454797553562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7834807454797553562'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/12/call-for-stic-talk-input.html' title='Call for STIC Talk Input'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-3381698822129561291</id><published>2011-10-06T23:11:00.000-07:00</published><updated>2011-10-06T23:35:51.263-07:00</updated><title type='text'>Sounding Out the View Tree</title><content type='html'>A couple of days ago, I asked myself the following question:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;What would something like jQuery look like in Smalltalk?&lt;/div&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Motivation&lt;/h3&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;changeSelectedField&lt;br /&gt; "..."&lt;br /&gt; self builder == nil ifTrue: [^self].&lt;br /&gt; w := self builder componentAt: #text.&lt;br /&gt; w == nil ifTrue: [^self].&lt;br /&gt; "..."&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;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 &lt;i&gt;widget&lt;/i&gt; and &lt;i&gt;widget controller&lt;/i&gt; to it to further manipulate it. #controllerAt:, #wrapperAt:, and #widgetAt: all exist to try and help smooth this out.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;To see examples of the second pattern that bothers me, do this.&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Open a System Browser&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Select all Packages using Ctrl-a&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Select the &lt;i&gt;Rewrite&lt;/i&gt; tool (in the mid page tab control)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Enter &lt;i&gt;``@r container container&lt;/i&gt; in the &lt;i&gt;Search for:&lt;/i&gt; box&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Click the &lt;i&gt;Search...&lt;/i&gt; button and wait for the result&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;One of the more egregious examples is found in SpinButtonController&lt;br /&gt;&lt;pre&gt;&lt;code&gt;pressAction&lt;br /&gt; | compositeView inputBoxController |&lt;br /&gt; "..."&lt;br /&gt; compositeView := view container container.&lt;br /&gt; inputBoxController := compositeView controller.&lt;br /&gt; (view spin: inputBoxController view model value) ifFalse: [^self].&lt;br /&gt; compositeView container container takeKeyboardFocus&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Two times in the same method, the code walks up the view tree. Not just with one &lt;i&gt;container&lt;/i&gt; 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."&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Three Interesting Aspect  of jQuery&lt;/h3&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Ability to specify a criteria to match against widgets in a DOM.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The idea that it is always a collectionish thing that is returned, whether it has 0, 1, or many matches.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Terseness, which allows the programmer to see more code that has to do with manipulating the matches, rather than lots of code finding matches.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Building a Query Model in Smalltalk&lt;/h3&gt;&lt;br /&gt;The first thing I set out to do was build a Query model for view trees. The &lt;a href="http://www.w3schools.com/jquery/jquery_ref_selectors.asp"&gt;jQuery selectors&lt;/a&gt; have at least 4 kinds of general queries.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Type (e.g. $("div") )&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Id (e.g. $("#cancelButton") )&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Class (e.g. $(".demoGroup") )&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Attribute (e.g. $("[checked ='false']") )&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;I started with a basic Query object. A query can be asked if it &lt;i&gt;matches: aViewTreeElement&lt;/i&gt;. Different subclasses capture different kinds of matches.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Type Queries&lt;/h4&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Query type: Wrapper&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Id Queries&lt;/h4&gt;&lt;br /&gt;The skin work we've been doing in the next version of VisualWorks adds an &lt;i&gt;id/id:&lt;/i&gt; API to VisualPart. It turns out that if we insert a leading line in the following UILookPolicy method&lt;br /&gt;&lt;pre&gt;&lt;code&gt;widgetWrapperWrapping: aWrapper decorator: aDecorator component: aComponent state: aWidgetState spec: aSpec colors: colors isOpaque: opaqueFlag inBuilder: aBuilder&lt;br /&gt; | sw dt |&lt;br /&gt; aComponent id: aSpec name.&lt;br /&gt; "...."&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Query id: #okButton&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Class Queries (or Tag Queries)&lt;/h4&gt;&lt;br /&gt;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".&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;tag: anObject&lt;/i&gt; "adds anObject as a tag to the receiver"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;hasTag: anObject&lt;/i&gt; "returns whether the receiver has anObject attached to it as a tag"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;i&gt;untag: anObject&lt;/i&gt; "removes anObject as a tag from the receiver, if it is there"&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Query tag: #dialogActions&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Attribute Queries (or Block Queries)&lt;/h4&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;Query block: [:element | element isEnabled]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But one could do weirder things with it&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;"all widgets in the lower half of a window"&lt;br /&gt;Query block: [:each | (each localPointToGlobal: Point zero) y &amp;gt;= aWindow bounds center y]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Logical Combinators&lt;/h4&gt;&lt;br /&gt;For full expression's sake, I also added a NotQuery, and AndQuery and an OrQuery.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(Query type: Button) | (Query id: #okField) "Either inherits from Button or has id of #okButton"&lt;br /&gt;(Query type: Wrapper) &amp;amp; (Query block: [:each | each component isNil]) "All wrappers with no component set yet"&lt;br /&gt;(Query tag: #header) not "Everything that is not tagged #header"&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;View Trees as Collections&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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 &lt;i&gt;childViewTree&lt;/i&gt; or their &lt;i&gt;parentViewTree&lt;/i&gt;. Now we can do things like compute just how many Wrappers are in a current UI?&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self childViewTree query: (Query type: Wrapper)) size&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or we could enable a bunch of widgets&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self childViewTree query: (Query tag: #dialogAnswer))&lt;br /&gt; do: [:each | each enable]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or programmatically drive the OK button&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self childViewTree query: (Query id: #okButton)) do: [:each | each simulateMousePress]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Or tell a view's appropriate parent to takeKeyboardFocus without worrying how many layers away it is&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self parentViewTree query: (Query type: WidgetWrapper))&lt;br /&gt; do: [:each | each takeKeyboardFocus]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since a ViewTreeSet is actually derived from a collection of objects, we can ask them for a &lt;i&gt;childViewTree&lt;/i&gt; or &lt;i&gt;parentViewTree&lt;/i&gt; as well, and then we can stack queries&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;((self parentViewTree query: (Query type: BorderDecorator)) childViewTree&lt;br /&gt; query: (Query type: Scrollbar)) do: [:each | each invalidate]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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).&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Trying to Sweeten Things Up&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;I basically used 3 tricks to try and get things short and sweet (or bitter and sour maybe).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Binary Selectors&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;I chose to reduce the common &lt;i&gt;childViewTree query:&lt;/i&gt; part of my expressions to the single ? character. And to use ?? for the parent counterpart. The examples from above now become&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self ? (Query type: Wrapper)) size&lt;br /&gt;&lt;br /&gt;self ? (Query tag: #dialogAnswer) do: [:each | each enable]&lt;br /&gt;&lt;br /&gt;self ? (Query id: #okButton) do: [:each | each simulateMousePress]&lt;br /&gt;&lt;br /&gt;self ?? (Query type: WidgetWrapper) do: [:each | each takeKeyboardFocus]&lt;br /&gt;&lt;br /&gt;self ?? (Query type: BorderDecorator) ? (Query type: Scrollbar)&lt;br /&gt; do: [:each | each invalidate]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I've toyed with implementing ?! and ??! as well which automatically send &lt;i&gt;not&lt;/i&gt; to the argument. Note that the do: Blocks could be shortened by taking advantage of the fact that unary selectors can be &lt;i&gt;cull:&lt;/i&gt;'ed in place of those blocks, but we're concentrating on the query part here, not what we do with the results.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Overloading Literals&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;The second technique to shorten and simplify these, was to make assumptions about certain literal Smalltalk expressions. By having an &lt;i&gt;asUIQuery&lt;/i&gt; 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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self ? Wrapper) size&lt;br /&gt;&lt;br /&gt;self ? #okButton do: [:each | each simulateMousePress]&lt;br /&gt;&lt;br /&gt;self ?? WidgetWrapper do: [:each | each takeKeyboardFocus]&lt;br /&gt;&lt;br /&gt;self ?? BorderDecorator ? Scrollbar do: [:each | each invalidate]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can do blocks too&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;self ? TextEditorView ? [:each | each displayContents isEmpty]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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: ?&amp;amp; 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.&lt;br /&gt;&lt;br /&gt;We could abuse things like Collections too, so that one could easily assemble or lists, something like&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;self ? #(#okButton #cancelButton) do: [:each | each flash]&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Adding Common Actions&lt;/h4&gt;&lt;br /&gt;&lt;br /&gt;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&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;(self ? (Query tag: #dialogAnswer)) enable&lt;br /&gt;&lt;br /&gt;(self ?? BorderDecorator ? Scrollbar) invalidate&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Beyond Cheesy Examples&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-jvDrA0DF0xs/To6byz5K_aI/AAAAAAAAAMQ/UR5QNa0Gazw/s1600/ClassCreationDialogOne.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 1192px; height: 380px;" src="http://2.bp.blogspot.com/-jvDrA0DF0xs/To6byz5K_aI/AAAAAAAAAMQ/UR5QNa0Gazw/s1600/ClassCreationDialogOne.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5660633078877060514" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Followed by a screenshot that shows a sample of the kind of change that is made to the longer &lt;i&gt;validateEverything&lt;/i&gt; method&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-kXT-zPH2So8/To6bzK7zeNI/AAAAAAAAAMY/h2pLRuyS5lw/s1600/ClassCreationDialogTwo.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 786px; height: 159px;" src="http://4.bp.blogspot.com/-kXT-zPH2So8/To6bzK7zeNI/AAAAAAAAAMY/h2pLRuyS5lw/s1600/ClassCreationDialogTwo.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5660633085062117586" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://mlucassmith.tumblr.com/"&gt;Michael Lucas-Smith&lt;/a&gt; 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 &lt;b&gt;that&lt;/b&gt; is a problem for another day unfortunately.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-SjSdVQvfLZI/To6bzTzP4EI/AAAAAAAAAMg/H_AlsU5qbL0/s1600/xPresslyOne.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 930px; height: 507px;" src="http://1.bp.blogspot.com/-SjSdVQvfLZI/To6bzTzP4EI/AAAAAAAAAMg/H_AlsU5qbL0/s1600/xPresslyOne.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5660633087442149442" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Current Conclusions&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-3381698822129561291?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/3381698822129561291/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/10/sounding-out-view-tree.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/3381698822129561291'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/3381698822129561291'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/10/sounding-out-view-tree.html' title='Sounding Out the View Tree'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-jvDrA0DF0xs/To6byz5K_aI/AAAAAAAAAMQ/UR5QNa0Gazw/s72-c/ClassCreationDialogOne.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-8163612763266338431</id><published>2011-09-23T16:14:00.000-07:00</published><updated>2011-09-25T21:47:54.562-07:00</updated><title type='text'>One of the Best Bits of Programming Advice I ever Got</title><content type='html'>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 &lt;a href="http://en.wikipedia.org/wiki/Alan_Kay"&gt;Alan Kay&lt;/a&gt; would make the statement "I invented the term 'Object Oriented Programming' and this {&lt;span style="font-style:italic;"&gt;Java and C++&lt;/span&gt;} is not what I had in mind."&lt;br /&gt;&lt;br /&gt;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?&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;i&gt;&lt;b&gt;Don't make objects that end with 'er'.&lt;/b&gt;&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Adele_Goldberg_(computer_scientist)"&gt;Adele Goldberg&lt;/a&gt; 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'."&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;Some er's that I've learned to avoid over the years:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;Analyzer/Renderer/etc - Definitely examples of "worker" objects. What if they had been Analysis/Rendering/etc.&lt;/li&gt;&lt;li&gt;Builder/Loader/Reader/Writer/etc - Remove the focus from the objects being manipulated, and tend assume to much responsibility themselves.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;There's lots of exceptions to such a rule of course.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;There are lots of noun words that end in 'er'. Register. Border. Character. Number. If it's really a noun, fine.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;li&gt;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.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;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.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-8163612763266338431?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/8163612763266338431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/09/one-of-best-bits-of-programming-advice.html#comment-form' title='52 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/8163612763266338431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/8163612763266338431'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/09/one-of-best-bits-of-programming-advice.html' title='One of the Best Bits of Programming Advice I ever Got'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>52</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-4002356488544986545</id><published>2011-09-21T17:47:00.000-07:00</published><updated>2011-09-21T18:12:52.218-07:00</updated><title type='text'>Don't Try This At Home: Stealing from the stack</title><content type='html'>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.&lt;br /&gt;&lt;br /&gt;Messing with &lt;span style="font-weight:bold;"&gt;thisContext&lt;/span&gt; and the stack is one of those things. When I was implementing the _1:_2:_3:_4:_5: message I was talking about the &lt;a href="http://objology.blogspot.com/2011/09/syntactic-tartness-for-macro-expansion.html"&gt;other day&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The proper and boring way to implement it was like this:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;_1: one _2: two _3: three _4: four _5: five&lt;br /&gt;&lt;br /&gt;     | arguments |&lt;br /&gt;     arguments := Array new: 5.&lt;br /&gt;     arguments at: 1 put: one.&lt;br /&gt;     arguments at: 2 put: two.&lt;br /&gt;     arguments at: 3 put: three.&lt;br /&gt;     arguments at: 4 put: four.&lt;br /&gt;     arguments at: 5 put: five.&lt;br /&gt;     ^(StringParameterSubstitution default)&lt;br /&gt;          originalString: self;&lt;br /&gt;          args: arguments;&lt;br /&gt;          expandedText&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;_1: one _2: two _3: three _4: four _5: five&lt;br /&gt;&lt;br /&gt;     ^(StringParameterSubstitution default)&lt;br /&gt;          originalString: self;&lt;br /&gt;          args: (thisContext stack copyFrom: 1 to: 5);&lt;br /&gt;          expandedText&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-4002356488544986545?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/4002356488544986545/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/09/dont-try-this-at-home-stealing-from.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4002356488544986545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4002356488544986545'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/09/dont-try-this-at-home-stealing-from.html' title='Don&apos;t Try This At Home: Stealing from the stack'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-7096450992706948715</id><published>2011-09-21T17:37:00.000-07:00</published><updated>2011-09-21T17:45:44.479-07:00</updated><title type='text'>A thought about field identifiers</title><content type='html'>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 &amp;lt; and &amp;gt; 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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-7096450992706948715?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/7096450992706948715/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/09/thought-about-field-identifiers.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7096450992706948715'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7096450992706948715'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/09/thought-about-field-identifiers.html' title='A thought about field identifiers'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-6103927053202806209</id><published>2011-09-20T00:13:00.000-07:00</published><updated>2011-09-20T00:26:19.068-07:00</updated><title type='text'>A Tragedy: When Localization met Interpolation (repost)</title><content type='html'>&lt;span style="font-style:italic;"&gt;This is &lt;a href="http://www.cincomsmalltalk.com/userblogs/travis/blogView?showComments=true&amp;printTitle=A_Tragedy:_When_Localization_met_Interpolation&amp;entry=3401021725"&gt;a repost from my old blog&lt;/a&gt;. When I end-of-lifed that Blog, I said might pull some of those over here. Lukas's comments on the previous &lt;a href="http://objology.blogspot.com/2011/09/syntactic-tartness-for-macro-expansion.html"&gt;Syntactic Tartness for Macro Expansion&lt;/a&gt; reminded me of this one. At the time I wrote that, I failed to give credit to Steve Dahl, who I had spent about 2 days kicking ideas back and forth with on Skype about this.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Adrian Kuhn commented in a previous post:&lt;br /&gt;&lt;br /&gt;"In general, I think that Smalltalk desperately misses String interpolation!"&lt;br /&gt;&lt;br /&gt;Yes, I agree. But the devils running amuck in the details. The problem is that I18n translation made it first. There's two ways that I've seen to do translation: 1) statically recompile your program, making a sweep of all (or subset) of the strings in the program and translating them 2) doing translation at runtime, by looking up the string in some database. The first is pretty old school. :)&lt;br /&gt;&lt;br /&gt;The challenges with String Interpolation are a few:&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Far Reaching Changes&lt;/h3&gt;&lt;br /&gt;You need to modify the compiler. You might be able to try to have a unary message that evaluates a string, compiling expressions on the fly in the context of the sender. In this case, the tools can do nothing to help you get the code right. They get confused, because you create variables that don't appear to be referenced. You can't do it right in the context of clean closures. So a parser/compiler change is definitely in order. And don't forget the usual rant, it's not enough to modify just the base compiler. You've got to look at it in the context of the debugger's ability to put breakpoints as well as step through code, in the context of the RB parser, which you want for rewrites and formatting, as well as code highlighting maybe. This does not make it undoable. It simply means it's not a quick thing you can whip up over the weekend.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What Is It When?&lt;/h3&gt;&lt;br /&gt;So lets say you have the expression:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;string := '[[customer name]] is [[customer age]] years old'.&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;If you use it as the argument of a nextPutAll: send, you probably want it to be in expanded form. But, if you want to look it up in an I18n dictionary, then you would rather have it in symbolic form.&lt;br /&gt;You could detect string literals with whatever the expression preamble is ([[ in the examples above) at compile time and build some sort of complex literal that held both blocks as well as a string. But you'd still have to figure out how to resolve the message =. In an assert: form, you'd probably want expanded, but at dictionary look up time for translation you'd want the compressed form.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What Happened Elsewhere&lt;/h3&gt;&lt;br /&gt;It's been interesting to spend a little time looking at how Ruby and Python do these. &lt;a href="http://www.yotabanana.com/hiki/ruby-gettext-faq.html#General+Questions"&gt;This page&lt;/a&gt; makes it clear that the Ruby gettext guys also understood that it is hard to have your cake and eat it too when it comes to mixing interpolation and localization. The answer isn't as definitive with Python, but I think I've convinced myself it's a similar story after looking at docs for a little while.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-6103927053202806209?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/6103927053202806209/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/09/tragedy-when-localization-met.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6103927053202806209'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6103927053202806209'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/09/tragedy-when-localization-met.html' title='A Tragedy: When Localization met Interpolation (repost)'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-5518305241211462113</id><published>2011-09-19T10:53:00.000-07:00</published><updated>2011-09-19T22:27:07.965-07:00</updated><title type='text'>Syntactic Tartness for Macro Expansion</title><content type='html'>&lt;div&gt;One thing that is very natural for Smalltalk image based programming, is to programmatically assemble source and install it into the very same running program. I've been using the RB Change framework to do just that with something I'm working on lately.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To piece together the appropriate source, working with a template source and string, and then fill in the variables is something that's desirable. VisualWorks and Squeak (maybe some other Smalltalk use this same approach?) have an ability to expand templates strings with macro substitution. The template for a setter method might look something like&lt;/div&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'&amp;lt;1s&amp;gt;: anObject&lt;br /&gt;     &amp;lt;1s&amp;gt; := anObject'&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To  fill out those fields, you send messages like &lt;i&gt;expandMacrosWith:&lt;/i&gt;, &lt;i&gt;expandMacrosWith:with:&lt;/i&gt;, &lt;i&gt;expandMacrosWith:with:with:&lt;/i&gt;, and &lt;i&gt;expandMacrosWithArguments:&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;I am no fan of this API. First, it is too verbose. When I'm looking at template substitution, I don't want a bunch of other longish selectors. They dilute the information I'm trying to glean as I piece together the template and what's being substituted.&lt;br /&gt;&lt;br /&gt;Secondly, I find it doesn't scale well when evolving the code. It's common that I start with a simple template in the first cut of code.  Something like&lt;br /&gt;&lt;pre&gt;&lt;code&gt;    'Hello &amp;lt;1s&amp;gt;' expandMacrosWith: aName&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;But as I refactor and discover more needs, the need to add parameters arises. As long as I only add two more parameters, I can just use the variants with the additional &lt;i&gt;with:&lt;/i&gt; keywords.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'&amp;lt;1s&amp;gt; ^self &amp;lt;2s&amp;gt; &amp;lt;3s&amp;gt;'&lt;br /&gt;     expandMacrosWith: aVariableName&lt;br /&gt;     with: aBasicAccessingMethod&lt;br /&gt;     with: sizeof + 1&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;As soon, as I go to 4 fields though, I have to change gears and use the &lt;i&gt;expandMacrosWithArguments:&lt;/i&gt; API and build the sequence myself. It could be argued that it's best to just always start with this version, but it's the very longest of the selectors. If you're using VisualWorks, and don't have the language syntax for array construction (e.g. {statement. statement. statement.}), then it's even funner, because you can use the &lt;span style="font-style:italic;"&gt;Array with:with:with:with:&lt;/span&gt; expression, but if you need to move to 5 fields, then you've got to change your code all around again.&lt;br /&gt;&lt;br /&gt;Over the years, I've tried a couple of different experiments to make this all something I liked a little better. They've used involved interesting binary selectors (e.g. "%") and proxy objects, or at least fun with doesNotUnderstand: messages. I thought I'd try something a little different. I wanted something that correlated well with the numbered fields, but was uber-terse as well.&lt;br /&gt;&lt;br /&gt;So I went with the shortest selector that could possibly work: _1:, _1:_2:, _1:_2:_3:, etc. Written in selector shorthand like that, it's pretty ugly. When actually used in code though, it improves some:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'&amp;lt;1s&amp;gt;At: anOffset&lt;br /&gt;     ^self &amp;lt;2s&amp;gt; anOffset * &amp;lt;3p&amp;gt; + &amp;lt;4p&amp;gt;'&lt;br /&gt;     _1: aVariableName&lt;br /&gt;     _2: aBasicAccessingMethod&lt;br /&gt;     _3: aByteSize&lt;br /&gt;     _4: sizeof + 1&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;and&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'inspector&amp;lt;1s&amp;gt;Field&lt;br /&gt; %&amp;lt;inspectorFields&amp;gt;&lt;br /&gt; ^Array with: (Tools.Trippy.DerivedAttribute&lt;br /&gt;    label: ''&amp;lt;2s&amp;gt;''&lt;br /&gt;    valueBlock: [self &amp;lt;2s&amp;gt;])'&lt;br /&gt;     _1: upperVariableName&lt;br /&gt;     _2: aVariableName&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;and&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'&amp;lt;1s&amp;gt;&lt;br /&gt;     ^(0 to: &amp;lt;2p&amp;gt;) collect: [:n | self &amp;lt;3s&amp;gt; &amp;lt;4p&amp;gt; + (n * &amp;lt;5p&amp;gt;)]'&lt;br /&gt;     _1: aVariableName&lt;br /&gt;     _2: anInteger - 1&lt;br /&gt;     _3: aBasicAccessingMethod&lt;br /&gt;     _4: sizeof + 1&lt;br /&gt;     _5: aByteSize&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;I don't dare call this syntactic sugar. The use of the underscores is too ugly to be sugary. It's a sort of bitter sweet thing, thus the "tart" label.&lt;br /&gt;&lt;br /&gt;It does solve two problems nicely. It is very terse. You see a minimal amount of "scaffolding" getting the job done, and are free to spend more time looking at the template and the substitutions. One could get that though by using inlined arrays with a shorter selector, something like:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;'&amp;lt;1s&amp;gt;&lt;br /&gt;     ^(0 to: &amp;lt;2p&amp;gt;) collect: [:n | self &amp;lt;3s&amp;gt; &amp;lt;4p&amp;gt; + (n * &amp;lt;5p&amp;gt;)]' macro: {&lt;br /&gt;          aVariableName.&lt;br /&gt;          anInteger - 1.&lt;br /&gt;          aBasicAccessingMethod.&lt;br /&gt;          sizeof + 1.&lt;br /&gt;          aByteSize.}&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;One thing you lose with this though, is the strong association between each substitution and field. In the former example, when I glance at the template and see field 4, and then want to know what's being substituted, I see it instantly. I just find the 4 in the selector below. Without that direct link, I have to parse the array linearly to find it.&lt;br /&gt;&lt;br /&gt;I haven't used this _syntax enough to decide if it's usefulness would overcome its ugliness, but it was interesting to play with it and discover the visual readability aspect. I'll likely use it on some more non-production stuff to get a better feel.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-5518305241211462113?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/5518305241211462113/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/09/syntactic-tartness-for-macro-expansion.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/5518305241211462113'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/5518305241211462113'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/09/syntactic-tartness-for-macro-expansion.html' title='Syntactic Tartness for Macro Expansion'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-107962954496187189</id><published>2011-08-23T16:39:00.000-07:00</published><updated>2011-08-23T18:07:16.774-07:00</updated><title type='text'>I've Inherited an Interesting Dilemma</title><content type='html'>Consider two browser screenshots. The first is the class side of AlphaBlendedIcons, with the needsComment method selected.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-Va-njuE5xbE/TlQ7MplmSaI/AAAAAAAAALw/QZ7KrqP13y4/s1600/AlphaBlendedIconsHierarchy.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 622px; height: 233px;" src="http://3.bp.blogspot.com/-Va-njuE5xbE/TlQ7MplmSaI/AAAAAAAAALw/QZ7KrqP13y4/s1600/AlphaBlendedIconsHierarchy.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644201321510095266" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This second is the instance side of NameSpace, the needsComment method selected.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-Ec3ZqHYxKlg/TlQ7MDzZKzI/AAAAAAAAALo/YaaGaNEsL9o/s1600/NamespaceHierarchy.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 623px; height: 257px;" src="http://4.bp.blogspot.com/-Ec3ZqHYxKlg/TlQ7MDzZKzI/AAAAAAAAALo/YaaGaNEsL9o/s1600/NamespaceHierarchy.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644201311367408434" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In both cases, if you invoke the menu of the selectors list, and choose the &lt;i&gt;Hierarchy Implementors&lt;/i&gt; option, you get the following two results, respectively...&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-DO5eBw6jYJA/TlQ7L2LBjWI/AAAAAAAAALY/hsxeCUCT7cU/s1600/AlphaBlendedIconsImplementors.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 389px; height: 172px;" src="http://3.bp.blogspot.com/-DO5eBw6jYJA/TlQ7L2LBjWI/AAAAAAAAALY/hsxeCUCT7cU/s1600/AlphaBlendedIconsImplementors.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644201307708427618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-YLAwN40gKAE/TlQ7MLsueZI/AAAAAAAAALg/eg__TT4CUkM/s1600/NamespaceImplementors.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 425px; height: 170px;" src="http://1.bp.blogspot.com/-YLAwN40gKAE/TlQ7MLsueZI/AAAAAAAAALg/eg__TT4CUkM/s1600/NamespaceImplementors.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5644201313486928274" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So what's the issue? The issue is the presence of ClassDescription in the Implementors browsers. Should it be there or not?&lt;br /&gt;&lt;br /&gt;On the one hand we have the notion of "hierarchy." In RB land, a &lt;i&gt;Hierarchy Browser&lt;/i&gt; is a pretty common thing. It is a limited view of classes always going as high as Object. If you are on the instance side, it tops at Object. If you are on the class side, it tops at Object class. From this point, where the term "Hierarchy" refers to a browsing view or scope, it is surprising to see these entries for ClassDescription here when you ask for &lt;i&gt;Hierarchy Implementors&lt;/i&gt;. What you expect to see, is only methods that you'd find as you navigated around in the Hierarchy Browser.&lt;br /&gt;&lt;br /&gt;Then there is a more pedantic side. It tends to be those who like to think of themselves as "I have ascended into the thirteenth circle of Smalltlak Uber-Knowledge." They know the zen-secret that there's a "crossing of the streams" that occurs at Object class. When a method is not found at Object class, the lookup for the method doesn't stop there, but continues up on the &lt;i&gt;instance&lt;/i&gt; side at Class, then ClassDescription, then Behavior, and finally Object (instance). The little up/down arrows we place next to methods, even show this. If you look at the first one, it shows that there is a super implementor of &lt;i&gt;needsComment&lt;/i&gt; for AlphaBlendedIcons, that is found farther up the search tree.&lt;br /&gt;&lt;br /&gt;These two notions of "hierarchy" when viewed from the class side, are at odds with another. When someone sees that menu option, which kind of "Hieararchy" are they more likely to think about at that moment. Should it be left the way it is, but reword the menu option to be "super/sub implementors?" What would you want it to do?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-107962954496187189?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/107962954496187189/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/08/ive-inherited-interesting-dilemma.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/107962954496187189'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/107962954496187189'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/08/ive-inherited-interesting-dilemma.html' title='I&apos;ve Inherited an Interesting Dilemma'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-Va-njuE5xbE/TlQ7MplmSaI/AAAAAAAAALw/QZ7KrqP13y4/s72-c/AlphaBlendedIconsHierarchy.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-1141787978116000797</id><published>2011-07-21T10:36:00.000-07:00</published><updated>2011-07-21T11:01:31.832-07:00</updated><title type='text'>OSX Lion: First Day Thoughts</title><content type='html'>I downloaded and installed &lt;a href="http://en.wikipedia.org/wiki/Mac_OS_X#Version_10.7:_.22Lion.22"&gt;Lion&lt;/a&gt; yesterday. Mostly, I'm still acclimating before drawing judgements and throwing darts. But one thing stands out already.&lt;br /&gt;&lt;br /&gt;There's this great story about &lt;a href="http://www.folklore.org/StoryView.py?story=Round_Rects_Are_Everywhere.txt"&gt;how Steve Jobs convinced Bill Atkinson that rectangles with rounded corners were a good thing&lt;/a&gt;. The idea being that we as humans tend to prefer them and so would naturally prefer them in our UIs. The rest is history. Over the years, more and more of our UI elements get sanded off corners.&lt;br /&gt;&lt;br /&gt;There is another pendulum that's been swinging along the Apple UI Design vector that annoys me. Color. Or lack thereof. It's no secret that Apple uses some of its frontline apps to feel out UI evolutions. Back in 2006, I remember discussing the latest iTunes version, and describing what I saw as an attempt on Apple's part to create "Lickable Motiff."&lt;br /&gt;&lt;br /&gt;The first thing that keeps hitting me with the subtle changes made to Mail and Finder, are that they both seem to have been through another bleach cycle. Mails top button bar has had all hue rinsed from it. Finder's side bar is nearly colorless. I keep thinking "Those icons are just glyphs from some foreign language. Ignore them." Maybe I should just spend more time in Terminal and use good ol' &lt;span style="font-weight:bold;"&gt;ls&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I understand some of the influences that drive Apple designers to do this. It's easier to harmonize sets of icons if you use less colors. It helps deal with colorblindness issues. Etc.&lt;br /&gt;&lt;br /&gt;On the other hand... I'd like to take the Apple UI designers on a walk around their campus. And point at things. And say "See? Color!" If we get rounded rectangles (problematic as they are to graphics libraries) because they show up in real life, why can't we have some color too?&lt;br /&gt;&lt;br /&gt;Who knows, maybe everyone at Apple wears black turtlenecks now, and they all really see less color. Yeah, maybe that's it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-1141787978116000797?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/1141787978116000797/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/07/osx-lion-first-day-thoughts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1141787978116000797'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1141787978116000797'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/07/osx-lion-first-day-thoughts.html' title='OSX Lion: First Day Thoughts'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-7201334361476111956</id><published>2011-07-14T09:12:00.000-07:00</published><updated>2011-07-14T10:36:10.322-07:00</updated><title type='text'>Rope: an evolved Chain</title><content type='html'>One of the areas my &lt;a href="http://objology.blogspot.com/2011/06/kicking-hash-out-of-dictionary.html"&gt;Chain&lt;/a&gt; did not come out ahead was in the area of adding truly new keys to a Dictionary (as opposed to just updating what already was stored at a given key) or removing them. Both of these operations potentially involve &lt;span style="font-style:italic;"&gt;#become:&lt;/span&gt; sends. While VisualWorks &lt;span style="font-style: italic;"&gt;#become&lt;/span&gt;: is very fast, it's not as fast as some other operations. And not all Smalltalk implementations have a fast &lt;span style="font-style: italic;"&gt;#become:&lt;/span&gt;. Here's the chart of how well Chain compared to IdentityDictionary for original key add/removal.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-cA3ygR1oVsA/TgUEeB68wlI/AAAAAAAAAHg/7A3WFTrnOdk/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 75px;" src="http://4.bp.blogspot.com/-cA3ygR1oVsA/TgUEeB68wlI/AAAAAAAAAHg/7A3WFTrnOdk/s1600/chart.png" alt="" id="BLOGGER_PHOTO_ID_5621904623800205906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;While I was on vacation, John Brant pinged me encouraging me to use a &lt;span style="font-style: italic;"&gt;#changeClassTo:&lt;/span&gt; strategy instead of #&lt;span style="font-style: italic;"&gt;become:&lt;/span&gt;. To do so, first I cloned the &lt;span style="font-style: italic;"&gt;Chain&lt;/span&gt; class as a new class called &lt;span style="font-style: italic;"&gt;Rope&lt;/span&gt; (and the &lt;span style="font-style: italic;"&gt;Empty&lt;/span&gt; variant as well).&lt;br /&gt;&lt;br /&gt;Then we make &lt;span style="font-style: italic;"&gt;EmptyRope&lt;/span&gt; a subclass of &lt;span style="font-style: italic;"&gt;Rope&lt;/span&gt;. This is important, because we need an &lt;span style="font-style: italic;"&gt;EmptyRope&lt;/span&gt; to have the same instance variable layout as a &lt;span style="font-style: italic;"&gt;Rope&lt;/span&gt;. &lt;span style="font-style: italic;"&gt;#changeClassTo:&lt;/span&gt; will only change the type or class of an object, if they have the same instance variable layout. We'll just make sure that never actually set or reference the &lt;span style="font-style: italic;"&gt;key&lt;/span&gt;, &lt;span style="font-style: italic;"&gt;value&lt;/span&gt;, or &lt;span style="font-style: italic;"&gt;nextKnot&lt;/span&gt; variables in the &lt;span style="font-style: italic;"&gt;EmptyRope&lt;/span&gt; subclass.&lt;br /&gt;&lt;br /&gt;In the case of adding a new key/value pair, when our &lt;span style="font-style: italic;"&gt;#at:put:&lt;/span&gt; reaches the end of the list, the &lt;span style="font-style:italic;"&gt;EmptyRope&lt;/span&gt; subclass can just implement it as&lt;br /&gt;&lt;pre&gt;&lt;code&gt;at: aKey put: anObject&lt;br /&gt;   self&lt;br /&gt;      setKey: aKey&lt;br /&gt;      value: anObject&lt;br /&gt;      next: EmptyRope basicNew.&lt;br /&gt;   self changeClassTo: Rope&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;And the only thing #removeKey: has to do in addition to the original #replace: trick is do a&lt;br /&gt;&lt;pre&gt;&lt;code&gt;   previousKnot changeClassToThatOf: self&lt;/code&gt;&lt;/pre&gt;to get the last link to be an EmptyRope.&lt;br /&gt;&lt;br /&gt;Most of the rest of the code stays the same. We can reduce a couple of duplicates since the classes are now in a parent-child relationship, rather than a sibling one.&lt;br /&gt;&lt;br /&gt;The at:put:/removeKey: test is the interesting one to rerun and see how things fair. First of all, we compare the new &lt;span style="font-style:italic;"&gt;Rope&lt;/span&gt; approach to the original &lt;span style="font-style:italic;"&gt;Chain&lt;/span&gt; one.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-RTjEwZbXGyQ/Th8j2O4BCjI/AAAAAAAAAIM/v83KeKx_75Y/s1600/chart2.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 150px;" src="http://3.bp.blogspot.com/-RTjEwZbXGyQ/Th8j2O4BCjI/AAAAAAAAAIM/v83KeKx_75Y/s1600/chart2.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5629257473849362994" /&gt;&lt;/a&gt;&lt;br /&gt;That shows some improvement across the board. The real test though, is how does it compare to the original IdentityDictionary?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-pwvcfQOYOS8/Th8kxAb2ooI/AAAAAAAAAIU/PA6BFMvOUHY/s1600/chart1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 75px;" src="http://4.bp.blogspot.com/-pwvcfQOYOS8/Th8kxAb2ooI/AAAAAAAAAIU/PA6BFMvOUHY/s1600/chart1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5629258483585426050" /&gt;&lt;/a&gt;&lt;br /&gt;The good news is, it's actually faster. Not by a huge amount. But it removes it from something you have to worry about.&lt;br /&gt;&lt;br /&gt;I've replicated the Rope code up to the Open Repository (package &lt;span style="font-style:italic;"&gt;TAG-Ropes&lt;/span&gt;). If you know you're using smallish dictionaries (size &amp;lt;= 15) and need to care about performance, then this might be the thing for you.&lt;br /&gt;&lt;br /&gt;It would be interesting to see how such an approach fared in &lt;a href="http://smalltalk.gnu.org/"&gt;GNU Smalltalk&lt;/a&gt; or one of the other Smalltalks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-7201334361476111956?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/7201334361476111956/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/07/rope-evolved-chain.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7201334361476111956'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7201334361476111956'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/07/rope-evolved-chain.html' title='Rope: an evolved Chain'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-cA3ygR1oVsA/TgUEeB68wlI/AAAAAAAAAHg/7A3WFTrnOdk/s72-c/chart.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-673833804257644363</id><published>2011-07-13T18:02:00.000-07:00</published><updated>2011-07-14T13:40:20.438-07:00</updated><title type='text'>Syntax Highlighting your Blog with highlight.js</title><content type='html'>I've had some people ask me how I got syntax highlighting for Smalltalk code on my blogger blog. Here's what I did:&lt;ol&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Download highlight.js&lt;/h4&gt;Go to &lt;a href="http://softwaremaniacs.org/soft/highlight/en/download/"&gt;Software Maniac's download page&lt;/a&gt;. Turn off the languages you're not interested in. Check the checkbox for Smalltalk. And hit the download button. You'll get a zip file that when unarchived has a whole directory structure of files, including the customized highlight.js file for your efforts. You need this customized version because it doesn't support Smalltalk in the stock version.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Host it somewhere&lt;/h4&gt;Find a net presence to host it at. Hopefully, you've either got your own or know someone who can host it for you. I was fortunate to fall into the second category.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Update your blog template&lt;/h4&gt;Edit your blog template (in &lt;b&gt;Edit HTML&lt;/b&gt; link under the &lt;b&gt;Design&lt;/b&gt; tab of your blog. You add the following lines near the end of your template&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt; &amp;lt;script src="http://yourhostedsite/highlight.pack.js" type="text/javascript"&amp;gt;&lt;br /&gt; &amp;lt;script type="'text/javascript'"&amp;gt;&lt;br /&gt;   hljs.initHighlightingOnLoad();&lt;br /&gt; &amp;lt;/script&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;You need to edit the yourhostedsite part appropriately.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Add additional CSS for your blog&lt;/h4&gt;You need to choose a css style you like from the downloaded package's style directory. Then use &lt;span style="font-weight:bold;"&gt;Design&lt;/span&gt; -&amp;gt; &lt;span style="font-weight:bold;"&gt;Template Designer&lt;/span&gt; -&amp;gt; &lt;span style="font-weight:bold;"&gt;Advanced&lt;/span&gt; -&amp;gt; &lt;span style="font-weight:bold;"&gt;Add CSS&lt;/span&gt; (at the bottom) and paste the contents of your preferred styles .css file into that.&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;h4&gt;Enclose code blocks appropriately&lt;/h4&gt;To have the highlighter apply to a chunk of code, you place your code in between &lt;i&gt;pre&lt;/i&gt; and &lt;i&gt;code&lt;/i&gt; tags. E.g.&lt;br /&gt;&lt;br /&gt;&amp;lt;pre&amp;gt;&amp;lt;code&amp;gt;&lt;br /&gt;  &lt;i&gt;...smalltalk code snippets...&lt;/i&gt;&lt;br /&gt;&amp;lt;/code&amp;gt;&amp;lt;/pre&amp;gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;At least... that's how I remember how I did it. It's been a month or so now. Hope that helps. And would love to hear of errors/corrections in the above.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-673833804257644363?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/673833804257644363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/07/syntax-highlighting-your-blog-with.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/673833804257644363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/673833804257644363'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/07/syntax-highlighting-your-blog-with.html' title='Syntax Highlighting your Blog with highlight.js'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-7025593084935181067</id><published>2011-07-13T15:10:00.000-07:00</published><updated>2011-07-13T15:27:31.219-07:00</updated><title type='text'>Making Performance Comparison Charts</title><content type='html'>My last post was submitted just before embarking on a multi-week multi-state driving family vacation. While I was gone, I received a couple of requests regarding the code actually used to draw the performance comparison charts in that post.&lt;br /&gt;&lt;br /&gt;I used &lt;a href="http://cairographics.org/"&gt;CairoGraphics&lt;/a&gt; to do it. Those that know me are likely not surprised by this. The code is just a big workspace blob, and is somewhat procedural.&lt;br /&gt;&lt;br /&gt;One of the challenges I wrestled with was how to turn numbers the numbers into percent increase or decreases. The easy method of just dividing one value by the other gives values that are not linear when drawn graphically. Or put another way, that is twice as fast draws differently than something that is twice as slow.&lt;br /&gt;&lt;br /&gt;I used this fun snippet to convert from aTime and bTime values into such a comparison:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;    (((originalTime max: newTime) /&lt;br /&gt; (originalTime min: newTime)) - 1.0) * (originalTime - newTime) sign&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The large workspace blob that works with a variable called &lt;i&gt;percents&lt;/i&gt; follows below, I put comment annotations to delineate the various sections. It may serve as a useful Cairo snippet.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;| max min surface bandHeight xInc text extents y |&lt;br /&gt;&lt;br /&gt;"compute some dimensions and create the surface"&lt;br /&gt;max := (percents fold: [:a :b | a max: b]) ceiling max: 0.&lt;br /&gt;min := (percents fold: [:a :b | a min: b]) floor min: 0.&lt;br /&gt;surfaceHeight := (max - min) * 75 min: 300.&lt;br /&gt;bandHeight := surfaceHeight / (max - min).&lt;br /&gt;surface := ImageSurface format: CairoFormat argb32&lt;br /&gt;         extent: 600 @ surfaceHeight.&lt;br /&gt;xInc := surface width / percents size.&lt;br /&gt;&lt;br /&gt;surface newCairoContextWhile: &lt;br /&gt;      [:cr | | matrix |&lt;br /&gt;&lt;br /&gt;"setup a default font"&lt;br /&gt;      cr&lt;br /&gt;         selectFontFace: 'Arial'&lt;br /&gt;         slant: FontSlant normal&lt;br /&gt;         weight: FontWeight bold.&lt;br /&gt;&lt;br /&gt;"flip the coordinate system so we draw from the bottom up, rather than normal y is down style"&lt;br /&gt;      cr fontSize: 11.&lt;br /&gt;      cr translate: 0 @ surface height.&lt;br /&gt;      cr scale: 1 @ -1.&lt;br /&gt;      matrix := cr fontMatrix.&lt;br /&gt;      matrix scale: 1 @ -1.&lt;br /&gt;      cr fontMatrix: matrix.&lt;br /&gt;&lt;br /&gt;"do rounded clip/border"&lt;br /&gt;      cr rectangle: (Point zero corner: surface extent) fillet: 10.&lt;br /&gt;      cr clipPreserve.&lt;br /&gt;      cr source: ColorValue black.&lt;br /&gt;      cr fill.&lt;br /&gt;&lt;br /&gt;"shift up to base line"&lt;br /&gt;      cr translate: 0 @ min * bandHeight negated.&lt;br /&gt;&lt;br /&gt;"draw columns"&lt;br /&gt;      percents keysAndValuesDo: &lt;br /&gt;            [:size :percent |&lt;br /&gt;            | rectangle baseHue x |&lt;br /&gt;            cr saveWhile: &lt;br /&gt;                  [cr&lt;br /&gt;                     rectangle: (Point zero&lt;br /&gt;                           extent: surface width @ (percent positive ifTrue: [max] ifFalse: [min])&lt;br /&gt;                                 * bandHeight)&lt;br /&gt;                              regular.&lt;br /&gt;                  cr clip.&lt;br /&gt;                  rectangle := Rectangle&lt;br /&gt;                           left: (size - 1) * xInc + 3&lt;br /&gt;                           right: size * xInc - 3&lt;br /&gt;                           top: 5&lt;br /&gt;                           bottom: -5.&lt;br /&gt;                  percent &gt; 0&lt;br /&gt;                     ifTrue: [rectangle top: percent * bandHeight]&lt;br /&gt;                     ifFalse: [rectangle bottom: percent * bandHeight].&lt;br /&gt;                  cr rectangle: rectangle regular fillet: 5.&lt;br /&gt;                  baseHue := (1 / 6 + (percent / 3) min: 1 / 3) max: 0.&lt;br /&gt;                  cr source: (ColorValue hue: baseHue saturation: 1 brightness: 0.85).&lt;br /&gt;                  cr fillPreserve.&lt;br /&gt;                  cr source: (ColorValue hue: baseHue saturation: 0.85 brightness: 1).&lt;br /&gt;                  cr strokeWidth: 4.&lt;br /&gt;                  cr stroke].&lt;br /&gt;&lt;br /&gt;"draw the column label"&lt;br /&gt;            text := size printString.&lt;br /&gt;            size = 1 ifTrue: [text := 'size=' , text].&lt;br /&gt;            extents := cr textExtents: text.&lt;br /&gt;            x := (size - 0.5) * xInc - extents width half.&lt;br /&gt;            y := percent positive ifTrue: [extents height negated - 2] ifFalse: [2].&lt;br /&gt;            y := y max: min * bandHeight + 2.&lt;br /&gt;            cr moveTo: x @ y.&lt;br /&gt;            cr source: ColorValue white.&lt;br /&gt;            cr showText: text].&lt;br /&gt;&lt;br /&gt;"draw axis lines"&lt;br /&gt;      min to: max&lt;br /&gt;         by: 1 / 2&lt;br /&gt;         do: &lt;br /&gt;            [:n |&lt;br /&gt;            cr moveTo: 0 @ (n * bandHeight).&lt;br /&gt;            cr lineTo: surface width @ (n * bandHeight)].&lt;br /&gt;      cr source: ColorValue white.&lt;br /&gt;      cr strokeWidth: 0.25.&lt;br /&gt;      cr stroke.&lt;br /&gt;&lt;br /&gt;"draw axis"&lt;br /&gt;      cr source: ColorValue white.&lt;br /&gt;      min to: max&lt;br /&gt;         do: &lt;br /&gt;            [:n |&lt;br /&gt;            n isZero&lt;br /&gt;               ifFalse: &lt;br /&gt;                  [text := (n + n sign) printString , 'x'.&lt;br /&gt;                  extents := cr textExtents: text.&lt;br /&gt;                  y := ((n * bandHeight max: min * bandHeight + 4 + extents height half)&lt;br /&gt;                           min: max * bandHeight - 4 - extents height half) - extents height half.&lt;br /&gt;                  cr moveTo: 4 @ y.&lt;br /&gt;                  cr showText: text.&lt;br /&gt;                  cr moveTo: (surface width - 4 - extents width) @ y.&lt;br /&gt;                  cr showText: text]].&lt;br /&gt;      cr moveTo: Point zero.&lt;br /&gt;      cr lineTo: surface width @ 0.&lt;br /&gt;      cr strokeWidth: 1.&lt;br /&gt;      cr stroke.&lt;br /&gt;&lt;br /&gt;"draw label"&lt;br /&gt;      text := '#at:put: - Chain vs CompactDictionary'.&lt;br /&gt;      extents := cr textExtents: text.&lt;br /&gt;      cr moveTo: (surface width half - extents width half)&lt;br /&gt;               @ (max * bandHeight - 4 - extents height).&lt;br /&gt;      cr showText: text].&lt;br /&gt;&lt;br /&gt;"write the file"&lt;br /&gt;surface writeToPng: 'chart.png'&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-7025593084935181067?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/7025593084935181067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/07/making-performance-comparison-charts.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7025593084935181067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/7025593084935181067'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/07/making-performance-comparison-charts.html' title='Making Performance Comparison Charts'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-6450054922218415687</id><published>2011-06-23T09:46:00.000-07:00</published><updated>2011-06-24T15:54:25.148-07:00</updated><title type='text'>Kicking the Hash out of Dictionary</title><content type='html'>&lt;h3&gt;What Led to This Post&lt;/h3&gt;&lt;p&gt;First of all, it was that I needed a break. I've been working on ARs, doing some embedded Linux stuff, working on Skinned Scrollbars, and Uniscribe at the same time. So yesterday afternoon, I thought I'd like to take a little journey.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;One of the patterns that has become kind of popular in VisualWorks of late is the "Properties Dictionary". There are some drawbacks to them, but one of advantages is they allow for a sort of "poor man's instance variable pool." Using them, one can store state by by name, in a structure that isn't quite as established as standard instance variables. Package's use them. Various parts of the RB use them. VisualPart's use it.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;These dictionaries have a similar usage pattern. They tend to be smaller in size. Their primary usage tends to be at:(ifAbsent:) and at:put:, where the keys are usually someone constant. Or in other words, the majority of the time, at:put: is replacing an existing value, rather than adding a new slot to the dictionary.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Which led to a bigger question even. Even without worrying about the consistency of keys, what about small dictionaries in general?&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Are small dictionaries that common?&lt;/h3&gt;&lt;p&gt;Here's a bit of code we can use to get a view on that question:&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;histogram := Bag new.&lt;br /&gt;Dictionary allInstancesDo: [:each | histogram add: each size].&lt;br /&gt;IdentityDictionary allInstancesDo: [:each | histogram add: each size].&lt;br /&gt;histogram&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Exporting the data and playing with GoogleDocs a bit, we come up with this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-5XkRU4JAWTo/TgUVY3TD4MI/AAAAAAAAAIE/XWE0saLNhSI/s1600/size_frequency.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 371px;" src="http://2.bp.blogspot.com/-5XkRU4JAWTo/TgUVY3TD4MI/AAAAAAAAAIE/XWE0saLNhSI/s1600/size_frequency.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621923226746872002" /&gt;&lt;/a&gt;&lt;br /&gt;At least in my image, smaller dictionaries actually take up more space then the large dictionaries (area under the red curve is greater than that of the blue curve). And obviously, there's a lot more of them than the larger dictionaries.&lt;br /&gt;&lt;p&gt;Another kind of analysis (which I did not do) would be to look at what the access rates of dictionaries are as a function of their size. In other words. Are we sending messages as often to the big dictionaries as we are the small ones?&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;Some Points of History&lt;/h3&gt;&lt;p&gt;Seeing that optimizing smaller dictionaries is an interesting pursuit, is not a new idea. The original Refactoring engine sported a specialized RBSmallDictionary. It exploited the fact that for its use cases, the sizes were usually only one or two. The overhead of hashing, probing, etc wasn't really worth it for these usually-one-element dictionaries. Having their own, also allowed them have a specialized removeAll that was very fast.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;When Steve Dahl added CompactDictionary for &lt;a href="http://en.wikipedia.org/wiki/Unicode_collation_algorithm"&gt;UCA&lt;/a&gt;, it looked close enough to RBSmallDictionary, that dropped RBSmallDictionary in favor of it. Both implementations are basically linear search dictionaries.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Over the last few releases, there have been a number of changes to hashing algorithms and Dictionary implementations in VisualWorks, primary instigated by &lt;a href="http://blogten.blogspot.com/"&gt;Andres Valloud&lt;/a&gt;, which have changed the value of CompactDictionary/RBSmallDictionary as well. Take a look at the speed boost of CompactDictionary versus IdentityDictionary when sending #at: with Symbols as keys.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-TnboKQbxr1o/TgUMgIqHWYI/AAAAAAAAAHw/nhcrF6BGQXs/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 150px;" src="http://3.bp.blogspot.com/-TnboKQbxr1o/TgUMgIqHWYI/AAAAAAAAAHw/nhcrF6BGQXs/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621913456061405570" /&gt;&lt;/a&gt;It's basically a draw at this point. The #at:put: story shows a moderate benefit for using a CompactDictionary over an IdentityDictionary when your size is 4 or less.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-ktLR_qz4hY4/TgUPXHlgcSI/AAAAAAAAAH8/IGViRVcbt8I/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://4.bp.blogspot.com/-ktLR_qz4hY4/TgUPXHlgcSI/AAAAAAAAAH8/IGViRVcbt8I/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621916599689703714" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I'm told, that in the way-back-machine, VSE played games with optimizing small dictionaries. I don't have any more details than that though, and would love it if someone could speak truth to that rumor.&lt;br /&gt;&lt;/p&gt;&lt;h3&gt;#at:(put:) Considered Harmful&lt;/h3&gt;&lt;p&gt;The conventional wisdom to gain better dictionary performance is to work on hash algorithms. Make them faster. Make them separate better. Certainly that work will yield results. I think Andres's work has shown commendable efforts in those areas.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Sometimes we have to step out of our box and think about the problem from a different view point though. All of the improvements in hash algorithms ignore another important aspect of Smalltalk optimization. At the end of the day, all of this work on Dictionary will still result in the low level primitives for at: and at:put: running. Not the dictionary methods, but the one that is like the one found on array&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt; anArray at: 4 put: anObject&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The problem with this is that Smalltalk VM's want to be very safe. A bit of work is done every time the at:(put:) primitives fire. First, the VM wants to make sure you passed it an integer. And then it wants to convert your Smalltalk integer representation into a machine one. And then it wants to make sure that number is greater than one, and less than the current size of the variable sized receiver. That means it has to go fetch the current size first. And if that's all OK, then it wants to figure out what the real offset is from the header of the object. So it has fetch how many fixed fields it has first, and then add that to the offset. And now it can finally assign a pointer in the objects body to the object being stored at that slot. Oh yeah, there's a check in there to determine if size was really big, then the body of the object is in LargeSpace. You do this kind of work for every single at: and at:put: you do, whether indirectly or indirectly. A higher level Dictioanry&amp;gt;&amp;gt;at:put: will have to first compute a hash, then candidate insertion point, and then probe via a low level at: to see if it has a collision or existing value, and then eventually do an at:put: when it gets everything straightened out. And there's the overhead of just sending the message.&lt;p&gt;&lt;br /&gt;How much slower is indexed access than fixed variable access? It's easy to write a little snippet that will give us a hint&lt;br /&gt;&lt;/p&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;| point array index |&lt;br /&gt;fixed := 3 @ 4.&lt;br /&gt;array := Array new: 1000.&lt;br /&gt;index := '888' asNumber.&lt;br /&gt;[100000000 timesRepeat: [array at: index]] timeToRun asMicroseconds&lt;br /&gt; asFloat / [100000000 timesRepeat: [point y]] timeToRun asMicroseconds&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;I get around 60% slower for VW 7.9 builds. But this is only a hint. It's not correct really. Because the &lt;i&gt;point y&lt;/i&gt; expression doesn't just measure fixed var access, but also a message send. So in reality, the disparity is farther. I noodled about this for a while, I'm curious if anyone has a better way of comparing the two access methods in a truer measure. Basically, what we want to compare is the speed of the byte code to "push a known index" vs the speed of the #at: send. &lt;br /&gt;&lt;h3&gt;A Dictionary with Fixed Slots&lt;/h3&gt;&lt;p&gt;This is something I've wanted to try for a while. A linked list implementation where each link exposes a dictionary like interface. I tried to come up with a good name for this thing, and then gave up and called it &lt;span style="font-style: italic;"&gt;Chain&lt;/span&gt;. It's actually implemented with two polymorphic classes. Here's what a Chain with two elements looks like&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-NVkiXoKHiOQ/TgOqtNCn8cI/AAAAAAAAAEo/d-O2oXApCRs/s1600/Drawing1.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 377px; height: 97px;" src="http://1.bp.blogspot.com/-NVkiXoKHiOQ/TgOqtNCn8cI/AAAAAAAAAEo/d-O2oXApCRs/s1600/Drawing1.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621524453460013506" /&gt;&lt;/a&gt;&lt;br /&gt;Chain and EmptyChain end up having the same basic set of methods. Both inherit from Collection. Most of the methods are a fun exercise in recursive programming. For example, here's the two #at:ifPresent: implementations&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;at: aKey ifPresent: aBlock&lt;br /&gt; ^key = aKey&lt;br /&gt;  ifTrue: [aBlock value: value]&lt;br /&gt;  ifFalse: [nextLink at: aKey ifPresent: aBlock]&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;and&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;at: aKey ifPresent: aBlock&lt;br /&gt; ^nil&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In fact most of the EmptyChain methods do simple things like raise an error, return nil, return a copy, or do nothing. The two that are kind of fun are #at:put: and #removeKey:.&lt;br /&gt;&lt;h3&gt;Chain #at:put:&lt;/h3&gt;&lt;p&gt;The Chain implementation of #at:put: is simple:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;at: aKey put: anObject&lt;br /&gt; aKey = key&lt;br /&gt;  ifTrue: [value := anObject]&lt;br /&gt;  ifFalse: [nextLink at: aKey put: anObject].&lt;br /&gt; ^anObject&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will handle the cases where we already have aKey in our Chain and just want to update the value stored at that key. When we have a new key though, it will make it through to the EmptyChain implementation:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;at: aKey put: anObject&lt;br /&gt; | newLink |&lt;br /&gt; newLink := Chain basicNew.&lt;br /&gt; newLink setKey: aKey value: anObject next: newLink.&lt;br /&gt; self become: newLink&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There's a at least two interesting things going on here. The firs is that we use basicNew to instantiate a new Chain link. The reason is that Chain new redirects to EmptyChain new by default. Since a "new Chain" should be an empty one.&lt;br /&gt;&lt;p&gt;Since an EmptyChain link doesn't know who references it, we use a #become: to insert the new link in the chain. We could implement these two classes as a doubly linked list, but that requires more space, more management, and VisualWorks #become: is very fast. The trick in using the #become: is that we initially set the newLink's nextLink var to point back to itself. Before we do the #become:, we have another link pointing to the EmptyChain, or perhaps it really is an empty chain, and application code is referring to the EmptyChain instance as the head of the collection. And now we have a new link pointing to itself. After the #become: call, the previous link (or application code) now points to the new link, rather than the empty chain. But we also want the new link to have a nextLink that points to the original EmptyChain. Since the #become: is two way, the new link's reference to itself, is now referencing the terminating EmptyChain.&lt;br /&gt;&lt;h3&gt;Chain #removeKey:&lt;/h3&gt;&lt;p&gt;John Brant and Don Roberts once shared this riddle with me. "How do you delete a single link in the linked list with a pointer only to the link you want to delete?" The apparent conundrum, is that without knowing what the previous link was, how do you update its nextLink pointer to reference the nextLink of the link to be deleted. The answer is, that you don't. Instead, what you do is turn yourself (the link to be deleted) into the next link by copying its key and value to yourself, and then updating your nextLink to the be nextLink of what you just copied. So in essence what you do, is turn yourself into a clone of the next link, and then remove the now redundant nextLink from the link chain.&lt;br /&gt;&lt;p&gt;This ends up being a polymorphic implementation of a private method called used to #replace: aPreviousKey. The Chain implementation is easy enough:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;replace: aPreviousLink&lt;br /&gt; aPreviousLink setKey: key value: value next: nextLink&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;When we're removing the last normal link of the Chain though, the one that points to the terminating EmptyChain, that one basically does the reverse of the at:put:, using the self referential link + become: trick to change places.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;replace: aPreviousLink&lt;br /&gt; aPreviousLink&lt;br /&gt;  loopSelf;&lt;br /&gt;  become: self&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Does it Make a Difference?&lt;/h3&gt;&lt;p&gt;Chain and EmptyChain were a lot of fun to code up. Where I was interested in Dictionaries of sizes around 10 or less, it was a really fun way to approach the problem. I did go into this wondering about performance though. How does it stack up against normal Dictionary usage? What follows are a series of performance graphs for different dictionary APIs. In most cases I used Symbols, they have the cheapest hash and = implementations, so we don't get lost in worrying about the overhead of those. Most of the charts show results for Dictionary sizes ranging from 1 to 15.&lt;h4&gt;Accessing Methods&lt;/h4&gt;&lt;p&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-GCzNM75v3tw/TgTiyXXEcvI/AAAAAAAAAEw/HToVRamNQYg/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://4.bp.blogspot.com/-GCzNM75v3tw/TgTiyXXEcvI/AAAAAAAAAEw/HToVRamNQYg/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621867589757334258" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-zgrpLligL3Y/TgTjOB_jMcI/AAAAAAAAAE4/yn-fxawJ3gE/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-zgrpLligL3Y/TgTjOB_jMcI/AAAAAAAAAE4/yn-fxawJ3gE/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621868065057878466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-VT7OHoQFYc0/TgTjpUIB3_I/AAAAAAAAAFA/D68RWDzkqMk/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-VT7OHoQFYc0/TgTjpUIB3_I/AAAAAAAAAFA/D68RWDzkqMk/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621868533781749746" /&gt;&lt;/a&gt;&lt;p&gt;The &lt;i&gt;(positive)&lt;/i&gt; indicates that the key was found, or in other words that the exception block was not followed. &lt;i&gt;(negative)&lt;/i&gt; indicates the exceptional block was evaluated.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-BN9B8ZrgaUc/TgTkVom02lI/AAAAAAAAAFI/mybUz8ulw6o/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-BN9B8ZrgaUc/TgTkVom02lI/AAAAAAAAAFI/mybUz8ulw6o/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621869295193872978" /&gt;&lt;/a&gt;&lt;p&gt;The performance for the negative path deteriorates sooner, because we have to traverse the whole chain to discover it's not there, so it becomes a function of the chain size.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-7FU25HNyhW8/TgTk5SzO7gI/AAAAAAAAAFQ/-3di0yTzXJM/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-7FU25HNyhW8/TgTk5SzO7gI/AAAAAAAAAFQ/-3di0yTzXJM/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621869907815624194" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-duz65ymPdcI/TgTllfj45JI/AAAAAAAAAFY/LrHFe_5yi74/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://4.bp.blogspot.com/-duz65ymPdcI/TgTllfj45JI/AAAAAAAAAFY/LrHFe_5yi74/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621870667155170450" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-6dwwOlnFmPA/TgTl9Ne3TsI/AAAAAAAAAFg/LyFnTbzgflE/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-6dwwOlnFmPA/TgTl9Ne3TsI/AAAAAAAAAFg/LyFnTbzgflE/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621871074619117250" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-9j6K48kxwmE/TgTnbrEKDZI/AAAAAAAAAFw/jju3zbG2yy8/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://3.bp.blogspot.com/-9j6K48kxwmE/TgTnbrEKDZI/AAAAAAAAAFw/jju3zbG2yy8/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621872697467866514" /&gt;&lt;/a&gt;&lt;p&gt;There's a bit of sawtoothing to this chart. It occurs (in part) because these APIs are inherently dependent on the actual Dictionary size, for the Dictionary case. Not reported size, but the amount of memory allocated behind the scenes for a Dictionary of that size. The actual #basicSize of the 1-15 sized Dictionaries is #(3 3 7 7 7 17 17 17 17 17 17 17 37 37 37).&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-DPGUXbtuUBE/TgTn2wff2aI/AAAAAAAAAF4/LSOiWc409Oc/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-DPGUXbtuUBE/TgTn2wff2aI/AAAAAAAAAF4/LSOiWc409Oc/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621873162781186466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-rLk4aAjBgb0/TgToTyW2aZI/AAAAAAAAAGA/cThpSDE4Jio/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://4.bp.blogspot.com/-rLk4aAjBgb0/TgToTyW2aZI/AAAAAAAAAGA/cThpSDE4Jio/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621873661497993618" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-50g_f9-IYi8/TgTrNjPYbZI/AAAAAAAAAGI/P7m6E5Jmpp4/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 150px;" src="http://1.bp.blogspot.com/-50g_f9-IYi8/TgTrNjPYbZI/AAAAAAAAAGI/P7m6E5Jmpp4/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621876852895804818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-7-NVrlI9LBk/TgTs70KNMaI/AAAAAAAAAGQ/qJIiqaKObiw/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 150px;" src="http://3.bp.blogspot.com/-7-NVrlI9LBk/TgTs70KNMaI/AAAAAAAAAGQ/qJIiqaKObiw/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621878747223110050" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-1Pdr17eaiks/TgTuneVhI3I/AAAAAAAAAGY/NH4XAKsc1-k/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-1Pdr17eaiks/TgTuneVhI3I/AAAAAAAAAGY/NH4XAKsc1-k/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621880596790846322" /&gt;&lt;/a&gt;&lt;p&gt;#size is the bane of our singly linked list. For a Dictionary, it's just a return of the tally instance variable. But the Chain has to enumerate all of its links each time to compute the current size. As the chain gets longer, it takes more and more time to compute the size.&lt;br /&gt;&lt;h4&gt;Enumerating&lt;/h4&gt;&lt;p&gt;I wasn't as exhaustive with this set, I figured by now the picture was becoming clear.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-F2D6YnKcJTk/TgT5Uw2AQII/AAAAAAAAAGo/YJjdrKr4dlM/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-F2D6YnKcJTk/TgT5Uw2AQII/AAAAAAAAAGo/YJjdrKr4dlM/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621892369969332354" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-M0pZDZxCUPE/TgT6YKZGCqI/AAAAAAAAAGw/oMIE_FoSk-A/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-M0pZDZxCUPE/TgT6YKZGCqI/AAAAAAAAAGw/oMIE_FoSk-A/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621893527878634146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-I7ZKTkX8dIU/TgT69Inb0EI/AAAAAAAAAG4/7AmnlN8ZCTk/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-I7ZKTkX8dIU/TgT69Inb0EI/AAAAAAAAAG4/7AmnlN8ZCTk/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621894163057070146" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-5v9QLDi7r1Q/TgT4ILSaazI/AAAAAAAAAGg/O-eDWYL9AGY/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-5v9QLDi7r1Q/TgT4ILSaazI/AAAAAAAAAGg/O-eDWYL9AGY/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621891054217882418" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-xUGdQXsjbRY/TgT88k99FzI/AAAAAAAAAHA/alMm67R7Rcg/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-xUGdQXsjbRY/TgT88k99FzI/AAAAAAAAAHA/alMm67R7Rcg/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621896352511104818" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-IQl2N9OPdGM/TgT-eVqPZiI/AAAAAAAAAHI/5u5KYB2j6zE/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 225px;" src="http://3.bp.blogspot.com/-IQl2N9OPdGM/TgT-eVqPZiI/AAAAAAAAAHI/5u5KYB2j6zE/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621898032029066786" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-t9BZuSUw-yw/TgUAe7wTA9I/AAAAAAAAAHQ/O7H6sXkUppk/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://2.bp.blogspot.com/-t9BZuSUw-yw/TgUAe7wTA9I/AAAAAAAAAHQ/O7H6sXkUppk/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621900241278272466" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-NU8NbNtqYT0/TgUCst9fC9I/AAAAAAAAAHY/DXTn_h4ZOWc/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 300px;" src="http://1.bp.blogspot.com/-NU8NbNtqYT0/TgUCst9fC9I/AAAAAAAAAHY/DXTn_h4ZOWc/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621902677116914642" /&gt;&lt;/a&gt;&lt;p&gt;#reject: is the same as #select:.&lt;br /&gt;&lt;h4&gt;Removing&lt;/h4&gt;&lt;p&gt;Removal is tricky to time. We need full dictionaries to remove from. It's actually the same problem as found with timing the #at:put: of initially new keys. So married the two together by measuring the time it takes to remove an existent key and then add it back.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/-cA3ygR1oVsA/TgUEeB68wlI/AAAAAAAAAHg/7A3WFTrnOdk/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 75px;" src="http://4.bp.blogspot.com/-cA3ygR1oVsA/TgUEeB68wlI/AAAAAAAAAHg/7A3WFTrnOdk/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621904623800205906" /&gt;&lt;/a&gt;&lt;p&gt;The Chain pays a heavy price in this one because #at:put:'ing a new item involves allocating a new link, as well using #become: to insert it. As a net, that's a little slower than the IdentityDictionary which doesn't need to allocate each time.&lt;br /&gt;&lt;h3&gt;On Beyond Dictionaries&lt;/h3&gt;&lt;p&gt;We could do more of the Dictionary APIs, but I think the above charts are more than enough to get the picture. For things like property Dictionaries, where unique keys are determined early on, and the size is usually small, an object like Chain can offer a bit of performance boost (if you've determined you're in a speed crunch; remember "Make it Work. Make it Right. Make it Fast.").&lt;br /&gt;&lt;p&gt;Chain has some other interesting properties though. Unlike Dictionary, Chain can use nil as a key. And unlike Dictionary, order is preserved. At least, the order that you add the initial keys. As a Chain grows, its enumeration order doesn't change. This brings to light an interesting possibility. What if we used a Chain in place of an OrderedSet? We could make something like Chain that left the values out, or just put nil in for the values and simply use the various key APIs. For small OrderedSets we'd likely get a significant speed jump.&lt;br /&gt;&lt;p&gt;Why stop with OrderedSet emulation though. Dictionaries are just generalized Sequences. Or put another way, a Sequence (e.g. Array, OrderedCollection, etc) is just a special kind of Dictionary that limits its keys to a contiguous range of integers starting at 1 and ending at some size. It turns out that making Chain respond to Sequence APIs such as #first, #last, #first:, #last:, #allButFirst:, #allButLast:, #any, #fold:, #reverse, #reverseDo: is a snap. &lt;br /&gt;&lt;p&gt;Want an growable array that can #do faster than an array? Check this out:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/-Io7PC5H79DI/TgULLOYy0GI/AAAAAAAAAHo/7Rd_P5GDhwU/s1600/chart.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 150px;" src="http://2.bp.blogspot.com/-Io7PC5H79DI/TgULLOYy0GI/AAAAAAAAAHo/7Rd_P5GDhwU/s1600/chart.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5621911997310488674" /&gt;&lt;/a&gt;&lt;br /&gt;In a variety of scenarios, the Chain will actually perform on par or faster with Sequences. Just don't send #size to them.&lt;br /&gt;&lt;h3&gt;Other Thoughts&lt;/h3&gt;&lt;p&gt;&lt;br /&gt;One could do a number of different things past this point. One could make different kinds of Chain subclasses for identity behavior versus equality. The trick one could use is to have the EmptyDictionary know the kind of class to use for normal links.&lt;br /&gt;&lt;p&gt;One could avoid the use the clever #become: trick to add and remove links, by creating private helper methods that the basic APIs called on, passing the necessary state along to do the work without resorting to clever #become: incantations.&lt;br /&gt;&lt;p&gt;One could play with having Chain links that stored more than one key-&gt;value pair in fixed instance variables. This would reduce the amount of link traversal via message sends relative to fixed var access, though code complexity would need to increase as it had to deal with partially populated links.&lt;br /&gt;&lt;p&gt;Lastly, one has to keep in mind what this exploration has been about. It's been about using fixed var access in preferences to indexed variables. And in never sending #hash to the keys, sending = only instead. The value of not using the #hash, goes down though as #hash methods get faster while = methods get slower. In other words, if you're keying with objects that have lengthy equality comparisons and fast hash comparisons, the inflection point in size where the Chain technique wins out over a traditional hash approach will shift to the left.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-6450054922218415687?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/6450054922218415687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/06/kicking-hash-out-of-dictionary.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6450054922218415687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6450054922218415687'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/06/kicking-hash-out-of-dictionary.html' title='Kicking the Hash out of Dictionary'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-5XkRU4JAWTo/TgUVY3TD4MI/AAAAAAAAAIE/XWE0saLNhSI/s72-c/size_frequency.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2239139130250473057</id><published>2011-05-31T09:39:00.000-07:00</published><updated>2011-05-31T09:59:13.454-07:00</updated><title type='text'>Discovering Uniscribe</title><content type='html'>I've been working on a Uniscribe interface to VisualWorks Smalltalk off and on for the last two weeks or so. One of the frustrating things for me so far, is the lack of a good post-doc resource to go to for help with this stuff. There's the MSDN docs, which are OK, but when you have questions beyond that, I have as of yet, not found any of the resources I'm used to using for this kind of thing, such as mailing lists, etc. And the amount of "tutorial" style pages out there is pretty small. So I thought I'd at least leave a trail of breadcrumbs here.&lt;br /&gt;&lt;br /&gt;There is of course the &lt;a href="http://msdn.microsoft.com/en-us/library/dd374095%28v=VS.85%29.aspx"&gt;Uniscribe Reference MSDN Docs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Another valuable resource I found was &lt;a href="http://maxradi.us/documents/uniscribe/"&gt;Uniscribe: The Missing Documentation &amp;amp; Examples&lt;/a&gt;, a post written by one of the folks working on Chrome, once upon a time.&lt;br /&gt;&lt;br /&gt;The other thing I discovered recently, is that where there are &lt;span style="font-style:italic;"&gt;OpenType&lt;/span&gt; variants of UniscribeFunctions, you want to use those. For example, use &lt;span style="font-style: italic;"&gt;ScriptShapeOpenType&lt;/span&gt;() instead of just &lt;span style="font-style: italic;"&gt;ScriptShape&lt;/span&gt;().&lt;br /&gt;&lt;br /&gt;Do I have a working binding between VisualWorks Smalltalk and Uniscribe? At a limited level, yes. I can deal with the standard kinds of Text emphases (#bold, #italic, #family, etc). Even #color. I'm not yet using any of the line breaking abilities (so it all comes out on one line). What can't I deal with... any string that results in more than one item. An item, in Uniscribe speak, occurs everytime the the writing system changes. So if you mix arabic and english, you get separate items for each range. But even more common, you get changes on any english punctuation. So the string 'abc,xyz' actually produces 3 items, one for the 'abc', one for the ',', and one for the 'xyz'. And currently... something isn't right with my interface when this happens. Item one is displayed correctly, but not the following items. When I figure it out, you can be sure there will be a followup post here.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2239139130250473057?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2239139130250473057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/05/uniscribe-1.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2239139130250473057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2239139130250473057'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/05/uniscribe-1.html' title='Discovering Uniscribe'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2750625333748010031</id><published>2011-05-19T20:02:00.000-07:00</published><updated>2011-05-30T21:28:49.468-07:00</updated><title type='text'>FinalizeAction</title><content type='html'>Each time I do one of these external interface things, I wrestle with the finalization problem. I have to deal with it in Cairo. In Pango. I'm currently working on Uniscribe interface, and have worked on CoreText interface. They all have this same pattern. Some external structure or opaque pointer which the library either initializes or creates for you, some functions that take the structure or opaque pointer and make stuff happen with it, and some function that frees the same. It's not enough to just use the free() interface that C provides.&lt;br /&gt;&lt;br /&gt;The common pattern, on the Smalltalk side is that you have sort of Smalltalk object that acts as a front (facade) for your external structure/opaque pointer. And the interesting part becomes how do I make it so that when I don't need the Smalltalk object anymore, and the wonderful garbage collector makes life easy for me, erasing it from existence, that the related external resources are let go via that appropriate release/free C function.&lt;br /&gt;&lt;br /&gt;In some part, I tried to deal with this in the Weaklings package, but the pattern is to "built on top" of the idea of weak slots. And it leaves part of the job to the programmer. Boris Popov tried to fix it in his version 18.1, but I resisted it, because it fundamentally changed the API.&lt;br /&gt;&lt;br /&gt;I had yet another go at this in the recent ExRegex package. I don't know if this is the right solution yet, but I like it best so far. What I want is a nice simple uncomplicated, not bound up in other subclasses or frameworks, way to indicate that when an object is ready to go away, some arbitrary action happens.&lt;br /&gt;&lt;br /&gt;The class FinalizeAction in that package, was my solution. It's a simple #ephemeron behavior (nothing to do with the ill named Ephemeron class). The ephemeral slot (the first instance variable of the an #ephemeron type object) is a reference to the object you wish to perform finalization services for. And it's other instance variable, is action. Which can be any object that responds to #value:, things like Blocks, or MessageChannels. Or even Symbols if you're using newer versions of VisualWorks (or load the simplest of all packages, SymbolValue, in older versions). What I liked about FinalizeAction was that it solved my problem with 1 class, 2 instance variables, 2 class variables, and 8 methods. Not bad. I like small solutions.&lt;br /&gt;&lt;br /&gt;So here's some simple examples:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;MessageSend&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| b |&lt;br /&gt;b := Pixmap extent: 10 @ 10.&lt;br /&gt;"..."&lt;br /&gt;(FinalizeAction for: b)&lt;br /&gt; action: (MessageChannel new receiver: Transcript selector: #print:)&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Block&lt;/span&gt; &lt;span style="font-size:85%;"&gt;(note we're using a zero arg block which demonstrates we're actually using the cull: API)&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| d |&lt;br /&gt;d := ByteArray new: 100000.&lt;br /&gt;"..."&lt;br /&gt;(FinalizeAction for: d)&lt;br /&gt; action: [ObjectMemory current spaceSummaryOn: Transcript]&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Simple Unary Message Send&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;| f |&lt;br /&gt;f := 'howdy.txt' asFilename.&lt;br /&gt;"..."&lt;br /&gt;(FinalizeAction for: f) action: #out&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;FinalizeActions have an instance registry to keep them alive until they fire. I have sought and sought for a scheme that doesn't involve some sort of registry. I thought I had one in the early part of the ExRegex spike, until the basic invariant of #ephemeron based finalization sunk in:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;You have to guarantee that your finalizer will stay alive longer than the object its performing services for, and without some sort of other path back to the roots of the garbage collector, there is no way to do that.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'm ruminating on where to go with this. Fold it into the Weaklings package? Or just clone it when I need it (given it's small size)? I'm also curious if the basic use API (as shown in the examples above) couldn't use some work to make it seem more natural. Putting a helper on Object would of course make things simpler, but I do try to keep this to a minimum.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2750625333748010031?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2750625333748010031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/05/each-time-i-do-one-of-these-external.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2750625333748010031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2750625333748010031'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/05/each-time-i-do-one-of-these-external.html' title='FinalizeAction'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-6110135138524490515</id><published>2011-05-16T11:27:00.000-07:00</published><updated>2011-05-16T21:57:09.993-07:00</updated><title type='text'>Regex not so Regular?</title><content type='html'>A couple of days ago, on the VWNC mailing list, there was a discussion about the Regex11 package. Regex11 was originally written by Vassili Bykov as a Regex library for Smalltalk. It's actually been around a while and served the Smalltalk community pretty well, I think, in part due to Vassili's excellent coding abilities.&lt;br /&gt;&lt;br /&gt;I think it's really cool that someone can sit down and write a complete Regex implementation in Smalltalk. This is part of the Smalltalk ethos. Being able to invent your own future. Write your own software, in any area you like. On the other hand, as I read the comments, I found myself wondering, "it's great that you &lt;span style="font-weight:bold;"&gt;can&lt;/span&gt; do this, but does that mean you &lt;span style="font-weight:bold;"&gt;should&lt;/span&gt;?" Of course, the answer varies. It depends on what your goals are. A certain part of me feels that I don't really want to care this much about how the implementation works. Isn't Regex one of those things that's grown up enough now, that we can just use off-the-shelf services provided by the host  platforms? If we just reuse those, we might get some speed (benefits of thousands of code monkeys tuning and tweaking them over the years), and some standardization.&lt;br /&gt;&lt;br /&gt;So I went on a little journey. Read on if what I discovered is of interest...&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The Package&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I put my work in a package called ExRegex. As in "External Regex", using the ExternalInterface features of VisualWorks to bind to an outside-of-smalltalk shared library. Plus I just liked the way ExRegex looked almost palindromic. And I made a Test package called ExRegex-Tests. No surprises here, pretty standard operating procedure.&lt;br /&gt;&lt;br /&gt;I only began to implement the substitution stuff; for now, it's just good for matching. One thing I did do differently than Regex11 was employ a symmetric pair of binary selectors for doing Regex matches.&lt;br /&gt;&lt;pre&gt;    '(a|b)c' ?= 'ac' --&amp;gt; true&lt;br /&gt;   'Travis' =? '(Senior|Griggs)' --&amp;gt; false&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The ? character always leans towards the side with the regex pattern.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The Tests&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I stole the tests from the Regex11-Testing package. I made my own SUnitToo copy of it. I soon found I wasn't satisfied with them. The original tests have a single test method. But said method fetches a &lt;span style="font-style: italic;"&gt;clauseArray&lt;/span&gt; which is a series of inputs, and expected outputs. There's 3 or 4 relatively involved methods between the loop in the single test method and actually executing a single regex match.&lt;br /&gt;&lt;br /&gt;What this means, is that when you get a failure, you don't know much. First you have to dig through the little framework of interpreting the &lt;span style="font-style: italic;"&gt;clauseArray&lt;/span&gt;. When I'm trying to understand how someone's Regex framework works, I don't want to understand how their Regex test framework works as well. I just want to see very simple lines of code, the kind I would put in a workspace.&lt;br /&gt;&lt;br /&gt;Secondly, as soon, as you hit a failure, you're done. The &lt;span style="font-style: italic;"&gt;clauseArray&lt;/span&gt; has 137 entries in it. So if it fails for any reason (error or assertion failure) on test number 22... you have no idea how the others work. Is it just this one test? Or do others fail too? Is there a common pattern amongst the failures?&lt;br /&gt;&lt;br /&gt;I think we forget sometimes, that just as easy as it is to write a little DSL or interpretation framework, it's just as easy to write a little bit of code that interprets that into real Smalltalk methods. It's easy to generate code and it's easy to compile it and it;s easy to install it. Here's what I did for this particular case:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;RegexTest new clauseArray keysAndValuesDo:&lt;br /&gt;[:index :array |&lt;br /&gt;array size &amp;gt; 2&lt;br /&gt;ifTrue:&lt;br /&gt;[ws := String new writeStream.&lt;br /&gt;ws&lt;br /&gt;nextPutAll: 'match';&lt;br /&gt;print: index.&lt;br /&gt;ws nextPutAll: ' &amp;lt;test&amp;gt; '.&lt;br /&gt;ws nextPutAll: ' | regex | '.&lt;br /&gt;ws nextPutAll: ' regex := ' , array first printString , ' exRegex. '.&lt;br /&gt;2 to: array size&lt;br /&gt;by: 3&lt;br /&gt;do:&lt;br /&gt;[:n |&lt;br /&gt;ws nextPutAll: ' self '.&lt;br /&gt;ws&lt;br /&gt;    nextPutAll: ((array at: n + 1) ifTrue: [' assert: '] ifFalse: [' deny: ']).&lt;br /&gt;ws&lt;br /&gt;    nextPutAll: ' (regex match: ';&lt;br /&gt;    print: (array at: n);&lt;br /&gt;    nextPutAll: ').'].&lt;br /&gt;RegexTest compile: (RBParser parseMethod: ws contents) formattedCode&lt;br /&gt;classified: 'tests match']]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I didn't even have to bother to format the code, I let the RB services do that for me. What I ended up with was nice easy methods to read like this:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/-i4lhBtYUO8g/TdF0Ck0ReEI/AAAAAAAAADc/LXmVvKx6-do/s1600/Screen%2Bshot%2B2011-05-16%2Bat%2B11.58.31%2BAM.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 307px; height: 185px;" src="http://3.bp.blogspot.com/-i4lhBtYUO8g/TdF0Ck0ReEI/AAAAAAAAADc/LXmVvKx6-do/s400/Screen%2Bshot%2B2011-05-16%2Bat%2B11.58.31%2BAM.png" alt="" id="BLOGGER_PHOTO_ID_5607390598644463682" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And when I run the tests from within the IDE I get nice feedback like this:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/-UlRBMtIXPcw/TdF07UrUxGI/AAAAAAAAADk/MeQ-5NVL3hE/s1600/Screen%2Bshot%2B2011-05-16%2Bat%2B12.02.10%2BPM.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center;cursor:pointer; cursor:hand;width: 400px; height: 257px;" src="http://1.bp.blogspot.com/-UlRBMtIXPcw/TdF07UrUxGI/AAAAAAAAADk/MeQ-5NVL3hE/s400/Screen%2Bshot%2B2011-05-16%2Bat%2B12.02.10%2BPM.png" alt="" id="BLOGGER_PHOTO_ID_5607391573564507234" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This made it much easier to unravel things that, well, started to unravel after that.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;So much for Regularity&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Regularity means (among others) "conforming to a standard or pattern." I'm not sure a more ironic name was ever chosen as a moniker for a "standard set" of pattern matching. The C library interface is pretty standard. You have 4 basic functions:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;regcomp()&lt;/span&gt; - builds up a regex structure based on a pattern and some flags&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;regexec()&lt;/span&gt; - compares an input source against the regex structure for matches&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;regerror()&lt;/span&gt; - makes human readable strings for your regex structure when parse errors exist&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;regfree()&lt;/span&gt; - used to free the various chunks of memory associated with the regfree structure&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I knew Regex's varied a little from platform to platform. What surprised me was that the Regex11 did stuff the C library one couldn't (e.g. \d as sugar for [0-9] and \s for separators). And vice versa, the C library variant will do [0-9]{1,3} (match 1 to 3 digits), but the Smalltalk Regex11 can't do the {1,3} thing. You'd have to live with + (1 or more) or repeat it 3 times.&lt;br /&gt;&lt;br /&gt;But the fun didn't stop there. While both are part of the standard libc, the BSD variant that one finds on MacOSX, is different than the one finds under GNU platforms, such as Linux. And not just in their behavior. While the 4 C functions are the same between the two, and the same symbolic defines for the flags exist, they actually map to different values. For example, the option RE_NOSUB (what you use when you just care if it matches or not, not where), is a 0x08 on a GNU platform and 0x04 on a BSD platform. And the regex_t structure, which you're responsible to allocate the memory for, is entirely different between the two. For a C program using these libraries, you just use the defines, and you're fine, but for a Smalltalk (or any other not-compiled-by-the-C-Compiler/Preprocessor language), that more intimate knowledge of what the symbolic values mean, becomes more important. Getting around these differences was interesting.&lt;br /&gt;&lt;br /&gt;Regular? Anything but. This is kind of alarming actually. It's not like these things give you an error when you try to use something like \d. It really just tries to match an escaped d (rather than a digit), and now it fails. The upshot is that you don't have much portability with these things, and as you move from environment to environment, language to language, platform to platform, you'd better have a pretty good test suite around your regexes to make sure they're still matching the way they were when you developed your original application. On this aspect, this is one time where the "do it all in Smalltalk" actually has a compelling advantage, depending on your constraints.&lt;br /&gt;&lt;br /&gt;There's an excellent &lt;a href="http://www.regular-expressions.info/refflavors.html"&gt;exhaustive table at this link&lt;/a&gt; that shows a number of common implementations, and how they compare across a whole plethora of different options.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;The Speed Factor&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;What about the speed issue? Again, it depends. For doing simple matches, Regex11 will come out faster. Less overhead in going across the C boundaries. Let's take a regex for matching IP addresses:&lt;br /&gt;&lt;pre&gt;'.*(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?).*'.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If we match this against simple strings like '192.168.3.128' and 'abc', Regex11 is faster. As much as 3 times faster. But if we match against larger strings, such as the guts of the IPSocketAddress class&amp;gt;&amp;gt;allAboutHostAddresses method (an expected match) and the result of Object comment (shouldn't match), then the tables turn quite a bit. The Smalltalk version is suddenly &lt;span style="font-weight: bold;"&gt;210 times slower!&lt;/span&gt;. This measures both the time to create the Regex object, as well as do the match.&lt;br /&gt;&lt;br /&gt;So, I guess it depends on what kind of Regex's you're doing, and what kinds of frequencies (remember, it should always be "Make it Work, Make it Right, Make it Fast").&lt;br /&gt;&lt;br /&gt;I don't know why exactly, the pattern above actually requires the leading and trailing .* values to match the ip patterns mid source, I had to add it for Regex11, but the ExRegex interface didn't need it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-6110135138524490515?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/6110135138524490515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/05/regex-not-so-regular.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6110135138524490515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/6110135138524490515'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/05/regex-not-so-regular.html' title='Regex not so Regular?'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-i4lhBtYUO8g/TdF0Ck0ReEI/AAAAAAAAADc/LXmVvKx6-do/s72-c/Screen%2Bshot%2B2011-05-16%2Bat%2B11.58.31%2BAM.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2885487311310178422</id><published>2011-05-05T12:12:00.000-07:00</published><updated>2011-05-05T12:47:39.316-07:00</updated><title type='text'>Easiest Example That Could Possibly Click</title><content type='html'>I'm a big fan of unit test cases. Mapped 1:1 with the objects they test (as opposed to "let's say it tests unit of functionality"). But I also write a lot of class side &lt;i&gt;example&lt;/i&gt; methods, for the sake of prototyping, feedback, and ad hoc testing. Especially as you get into UI development, this becomes very helpful. It's hard (not impossible) to test how the pixels end up looking and interacting with unit tests.&lt;br /&gt;&lt;br /&gt;The classic pattern you see in Smalltalk is&lt;br /&gt;&lt;code&gt;&lt;br /&gt;exampleMethod&lt;br /&gt;&amp;nbsp&amp;nbsp"self exampleMethod"&lt;br /&gt;&lt;br /&gt;&amp;nbsp&amp;nbspself&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbspexample;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbspcode;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbspgoes;&lt;br /&gt;&amp;nbsp&amp;nbsp&amp;nbsp&amp;nbsphere&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then what you do, is navigate to the method, highlight the comment and &lt;i&gt;do it&lt;/i&gt;. If you're doing it a lot, it gets tedious to select the comment and then execute it.&lt;br /&gt;&lt;br /&gt;So I made a simple little package called &lt;b&gt;RBEasyExampleMethods&lt;/b&gt;, put in the repository. It makes it so you can just double click on a method in the browser, and if it looks like an example, it runs it. It looks like an example when it's&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;a class side method&lt;/li&gt;&lt;br /&gt;&lt;li&gt;unary (no arguments)&lt;/li&gt;&lt;br /&gt;&lt;li&gt;starts with 'example' OR lives in a category that starts with 'example'&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;It should work with VisualWorks versions from quite a ways back. Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2885487311310178422?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2885487311310178422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/05/easiest-example-that-could-possibly.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2885487311310178422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2885487311310178422'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/05/easiest-example-that-could-possibly.html' title='Easiest Example That Could Possibly Click'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-1603433531380030081</id><published>2011-04-29T08:54:00.000-07:00</published><updated>2011-04-29T09:25:13.595-07:00</updated><title type='text'>Goodbye to an Old Friend</title><content type='html'>As I type this, two devoted Cincom engineers are working thru a large number of changes accrued for the last two weeks, integrating and building a development build for VisualWorks 7.9.&lt;br /&gt;&lt;br /&gt;And when they're done, an old friend, will have made a big step into retirement. The friend I speak of, is the very venerable ParagraphEditor object, around since the early Smalltalk-80 days.&lt;br /&gt;&lt;br /&gt;Why retirement? Well, he was old and in the way.&lt;br /&gt;&lt;br /&gt;For a long time, his replacement, TextEditorController has been doing most of the work. Most of the views in the system default to him, and often for those that don't, code exists to replace the default ParagraphEditor with a TextEditorController instance.&lt;br /&gt;&lt;br /&gt;He's in the way, because we'd like to actually do some work in this area, but because the responsibilities bounce back and forth between the two, it's really difficult. Not just to implement new features, but then to figure out how they should work for the more limited ParagraphEditor, if at all. Archeology work here at Cincom, convinces me that TextEditorController always was meant as an eventual replacement of ParagraphEditor.&lt;br /&gt;&lt;br /&gt;We're doing this a little different than when we folded the classes ApplicationWindow and ScheduledWindow together. In a current system, those two names refer to the same object. If you have method extensions or overrides, they end up in the same place. Because of the size and amount of extensions and overrides that get done to ParagraphEditor and TextEditorController, we've decided not to try and do anything clever like we did in the Window situation. The opportunity for confusion and image destruction just seemed to high.&lt;br /&gt;&lt;br /&gt;So ParagraphEditor stays around as a distinct class for the time being. But TextEditorController no longer exists under it, but has been placed at the same level. All references to ParagraphEditor in the system have been changed to TextEditorController. All class side services that ParagraphEditor provided (things like copy/selection memory) have been moved to TextEditorController, and the ParagraphEditor methods exist still, to forward over to the TextEditorController ones.&lt;br /&gt;&lt;br /&gt;At some point we'll empty out all of the instance behavior ParagraphEditor, and mark the class side methods as deprecated. And if I can find a nice API to help me, we might even make it so that when packages or parcels load that extend or override the former ParagraphEditor, you get a note that your methods aren't in the right place anymore.&lt;br /&gt;&lt;br /&gt;So ParagraphEditor will stay around, but literally, he'll just be a shell of his former self.&lt;br /&gt;&lt;br /&gt;So to ParagraphEditor we say Thank You. You've earned your place in history. Now enjoy your retirement.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-1603433531380030081?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/1603433531380030081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/04/goodbye-to-old-friend.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1603433531380030081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1603433531380030081'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/04/goodbye-to-old-friend.html' title='Goodbye to an Old Friend'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2035385177984746180</id><published>2011-04-28T16:54:00.000-07:00</published><updated>2011-04-29T00:27:05.950-07:00</updated><title type='text'>a := b + (b := a)</title><content type='html'>C programers, should they choose, can revel in some truly tricky bits of code. It's a fine line between simply elegant and truly evil. We don't get to have as much fun in Smalltalk, but sometimes...&lt;br /&gt;&lt;br /&gt;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."&lt;br /&gt;&lt;br /&gt;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:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  do a bunch of setup.&lt;br /&gt;  set a candidate size.&lt;br /&gt; &lt;br /&gt;    [increment the candidate size and allocate more stuff accordingly.&lt;br /&gt;    result := make the call.&lt;br /&gt;    result == needMoreMemory] whileTrue.&lt;br /&gt;  &lt;br /&gt;  commit to the final sizes&lt;br /&gt;  clean more stuff up&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;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 &lt;a href="http://en.wikipedia.org/wiki/Fibonacci_number"&gt;Fibonacci Series&lt;/a&gt;. I decided I'd like to increment my candidate size along the Fibonacci line.&lt;br /&gt;&lt;br /&gt;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&lt;br /&gt;&lt;code&gt;&lt;br /&gt;  a := b + (b := a)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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.&lt;br /&gt;&lt;br /&gt;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"?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2035385177984746180?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2035385177984746180/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/04/b-b.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2035385177984746180'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2035385177984746180'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/04/b-b.html' title='a := b + (b := a)'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-4543042752583936259</id><published>2011-04-27T08:24:00.000-07:00</published><updated>2011-04-27T08:58:46.873-07:00</updated><title type='text'>Burned By Bein' Lazy Again</title><content type='html'>Yep, it happened again. I spent a good 30 minutes plus, hunting down a bug that was caused by use of &lt;a href="http://en.wikipedia.org/wiki/Lazy_initialization"&gt;Lazy Initialization&lt;/a&gt;. One of those infinite recursion, open-lots-of-windows, tough-to-get-a-handle-on sorts.&lt;br /&gt;&lt;br /&gt;Over the years, since I was first introduced to this "pattern", this happens once a year or so. It would happen more, if I used it more. This recent case was a case where I had broke my personal rule a while back, and it caught up with me. Again.&lt;br /&gt;&lt;br /&gt;It's not a totally evil pattern, I see its value (and use it) for things like class var singletons.&lt;br /&gt;&lt;br /&gt;The problem I have with it is one of Predictability and Responsibility. It seems like an encapsulated thing to do. You 'grow' the state of an object as different callers call upon for it services. So the state comes into being only as its needed. For simple patterns, this works fine: &lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;foo&lt;br /&gt;  ^foo ifNil: [foo := 42]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and&lt;br /&gt;&lt;code&gt;&lt;br /&gt;bar&lt;br /&gt;  ^bar ifNil: [bar := 18]&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;No problems. It's hard to imagine what will go wrong at this point. What often happens though, is that objects evolve over time. Different people come along and maintain them. They do so, not with the whole object in mind, but just looking at one view. So someone discovers that foo and bar actually have some interplay. And we end up with&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;foo&lt;br /&gt;  foo ifNil: [self useConsistentFooBars ifTrue: [foo := self bar * 10]].&lt;br /&gt;  ^foo&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;And then someone later does something like&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;bar&lt;br /&gt;  bar ifNil: [self useConsistentFooBars ifTrue: [bar := self foo / 10]].&lt;br /&gt;  ^bar&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The thing is, you might get away with this for a while. It's quite possible that when this was done, all uses of the object were using a setter to set foo before either accessor is invoked. So things Just Work(tm). Until later when someone changes the order of the way the object is being talked to.&lt;br /&gt;&lt;br /&gt;In short, &lt;b&gt;as the nature of lazy initializers grows in complexity, the odds rise that the object has hidden expectations about how it has to be interfaced with&lt;/b&gt;. And that is anything but encapsulated. Now you have the internal implementation of the object leaking out in hard to see or document ways.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-4543042752583936259?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/4543042752583936259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2011/04/burned-by-bein-lazy-again.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4543042752583936259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4543042752583936259'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2011/04/burned-by-bein-lazy-again.html' title='Burned By Bein&apos; Lazy Again'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-4301008158849225721</id><published>2010-11-27T20:12:00.000-08:00</published><updated>2010-11-27T20:27:37.815-08:00</updated><title type='text'>One Page Smalltalk Primer</title><content type='html'>A couple years ago, I endeavored to put together a simple "one page explanation of Smalltalk." I thought I'd harvest it over to my new blog here, and in the process actually found there are were a few of them:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://dl.dropbox.com/u/8893516/SyntaxPrimer.pdf"&gt;One Page PDF I Wrote&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://c2.com/cgi/wiki?SmalltalkInOnePage"&gt;Ralph Johnson's from the venerable C2 Wiki&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;&lt;a href="http://www.simberon.com/SmalltalkSyntax.jpg"&gt;Single Slide by David Buck&lt;/a&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-4301008158849225721?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/4301008158849225721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/one-page-smalltalk-primer.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4301008158849225721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4301008158849225721'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/one-page-smalltalk-primer.html' title='One Page Smalltalk Primer'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-4973403090088483330</id><published>2010-11-24T10:41:00.000-08:00</published><updated>2010-11-24T10:56:32.133-08:00</updated><title type='text'>TAG-SortFunctions Redux</title><content type='html'>The &lt;a href="http://objology.blogspot.com/2010/11/tag-sortfunctions.html"&gt;original TAG-SortFunctions&lt;/a&gt; received relatively positive feedback, thank you.&lt;br /&gt;&lt;br /&gt;A couple things have happened between version 1 and the current version (4) that's in the Public Repository, based on feedback I received in various channels. One thing I haven't changed yet, is the method names #sortUp and #sortDown. It was proposed by one person that maybe these would better be called #ascending and #descending, so that code snippets read like&lt;br /&gt;&lt;code&gt;somePoints sort: #x ascending, #y descending&lt;/code&gt;&lt;br /&gt;I'm torn. I think it reads better in context, but not as well in isolation. &lt;i&gt;Which do you prefer better?&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The things that have changed are:&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;The Tests have been separated out into a separate package&lt;/li&gt;&lt;br /&gt;&lt;li&gt;It was pointed out that you can't always count on a per element accessor being able to reduce to a collatable value. For example, what if you want to sort the names of customers, but based on a given collation algorithm.&lt;br /&gt;&lt;code&gt;customers asSortedCollection: [:a :b | (UnicodeCollationAlgorithm collate: a with: b mode: #shifted) &lt; 0]&lt;/code&gt;&lt;br /&gt;How would that dovetail with this approach? So I added support for two argument blocks. You can send sortUp/sortDown to them too. Under the hood now, the SortFunction is two argument collation block, and all roads lead to creating one of them.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Because of that, you no longer need your flavor of Smalltalk to be able to do theSymbol value: trick.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Since it all boils down to collation, I did add a new binary method: &amp;lt;=&amp;gt;. This is called the &lt;a href="http://en.wikipedia.org/wiki/Spaceship_operator"&gt;Spaceship operator&lt;/a&gt; in some language environments. So... you're Smalltalk flavor has to be able to support 3 character binary selectors for this to port.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Despite seeming like a lot of changes, IIRC, the code actually ended up being smaller than the original.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-4973403090088483330?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/4973403090088483330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/tag-sortfunctions-redux.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4973403090088483330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/4973403090088483330'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/tag-sortfunctions-redux.html' title='TAG-SortFunctions Redux'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-1850835397922719802</id><published>2010-11-23T20:32:00.000-08:00</published><updated>2010-11-23T20:42:17.440-08:00</updated><title type='text'>In search of a method I can't name...</title><content type='html'>Every couple weeks/months, I want a collection transform method that's liked groupedBy:, but isn't quite the same. And it's kinda like collect:. But again, not quite the same.&lt;br /&gt;&lt;br /&gt;The idea is to return a "map" of the original series from original values to some derived value. For example, maybe we have a series of Strings, and I want to create a map from those Strings to their md5sum values.&lt;br /&gt;&lt;br /&gt;I can code this as&lt;br /&gt;&lt;code&gt;Dictionary withAll: (setOfStrings collect: [:each | each -&gt; (Security.MD5 new hash: 'Hello World')])&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;but I really would rather capture this as a common method. What would you call it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-1850835397922719802?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/1850835397922719802/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/in-search-of-method-i-cant-name.html#comment-form' title='16 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1850835397922719802'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/1850835397922719802'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/in-search-of-method-i-cant-name.html' title='In search of a method I can&apos;t name...'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>16</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-2056494654866236751</id><published>2010-11-22T10:03:00.000-08:00</published><updated>2010-11-22T11:23:01.312-08:00</updated><title type='text'>Smalltalks 2010</title><content type='html'>People have been blogging about the Smalltalks 2010 conference for nearly a week now. Before too much time passes, I need to throw in my accolades for the conference held in Concepción del Uruguay.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;In particular, to express gratitude to all the long hard work that the Argentinian natives such as Emilio, Gabi, Hernan, Jorge, Esteban, Andres, Leandro, Alfonsina and other unsung heros who I'm missing. Your efforts made not only a really cool conference, but also made it possible for someone like me--who would have otherwise been stressed about other things--to really enjoy the conference, both its enthusiasm and technical content.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;My first Smalltalk connected conference was OOPSLA 1994, held in Portland. I've been to a number of OOPSLAs, ESUGs, Smalltalks, Camp Smalltalks, and Smalltalk Solutions since then. Over the years, I've heard of lots of cool things people do &lt;b&gt;WITH&lt;/b&gt; Smalltalk. Lots of ideas about how to best use it. But never, have I been to a conference, where there was so much talk about what to do &lt;b&gt;TO&lt;/b&gt; Smalltalk. From Gilad's talk which pushes us to think about where we ought to go, especially with regards to modularity, to four (not 1, or even 2 or 3, but 4!) talks about original and innovative VM work (in some ways there was even more actually), to other talks such as the xTreams talk which pushes the idea of a completely brand new approach to streams (much more than just a refactoring). Just all and all a really cool conference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-2056494654866236751?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/2056494654866236751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/smalltalks-2010.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2056494654866236751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/2056494654866236751'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/smalltalks-2010.html' title='Smalltalks 2010'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-8356227599099316325</id><published>2010-11-19T09:36:00.000-08:00</published><updated>2010-11-19T10:46:35.914-08:00</updated><title type='text'>TAG-SortFunctions</title><content type='html'>Since the introduction of SymbolValue and Block culling, one of the things I've chased is how to do this same style of programming with sorting. For most sorting cases, you have a series of objects that you want to sort on some particular attribute. Maybe a sequence of customers you'd like to sort by name.&lt;br /&gt;&lt;br /&gt;So it's tempting to want to add a series of APIs like those we added at Key Technology. This was a sortedBy: method, and was implemented something like&lt;br /&gt;&lt;code&gt;sortedBy: aSingleArgBlock&lt;br /&gt;      ^self sorted: [:a :b | (aSingleArgBlock value: a) &lt; (aSingleArgBlock value: b)]&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The problems with this approach are a couple.&lt;br /&gt;&lt;br /&gt;First you end up paralleling any of the existing 2 arg block sorting APIs. So if you have sorted: method, you add the sortedBy: method, as above. And then when you have a sort: method, you have to add a sortBy: method. And when you have a reverseSort: method, you add a reverseSortBy: method. Ad continuum.&lt;br /&gt;&lt;br /&gt;Second, it doesn't capture the direction of the sort at all. It assumes you want to sort ascending. For descending, you'll have to implement even more methods.&lt;br /&gt;&lt;br /&gt;Third, it doesn't capture chained sorting patterns at all. For example, what if I want to sort customers by first their last name, then their first name. I've seen a couple sites, where they add yet more multi argument sorting methods to the system to capture stacks of sorting criterion.&lt;br /&gt;&lt;br /&gt;I sat down last night, and with tests, put together a TAG-SortFunctions package, published in the Cincom Public Repository. The basic idea was to use an object. Time and time and time again over the years, I rediscover the principle "there's an object waiting to be birthed here!" What this package does in principle is note that sorting by 2 arg blocks, doesn't have to be limited to 2 arg blocks. It's really about the value:value: interface. And we can introduce an object type that stands in for the simple block which captures the failings listed above.&lt;br /&gt;&lt;br /&gt;Here's some examples.&lt;br /&gt;&lt;br /&gt;Sort customers by last name in descending order.&lt;br /&gt;&lt;code&gt;customers asSortedCollection: [:each | each lastName] sortDown&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Sort customers by last name in ascending order, and then by first name in ascending order.&lt;br /&gt;&lt;code&gt;customers sorted: [:each | each lastName] sortUp , [:each | each firstName] sortUp&lt;/code&gt;&lt;br /&gt;or&lt;br /&gt;&lt;code&gt;customers sorted: [:each | each lastName] sortUp , [:each | each firstName]&lt;/code&gt;&lt;br /&gt;(the second sortUp is taken care of automatically)&lt;br /&gt;&lt;br /&gt;We don't have to stick to blocks either, we can use symbols. Here's an example that sorts a list of points by their x value in ascending order, but their y value in descending order.&lt;br /&gt;&lt;code&gt;points sort: #x sortUp, #y sortDown&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Some things to note.&lt;br /&gt;&lt;br /&gt;First, we don't have to add any new sorting APIs to the system. Just use the existing ones. Second, direction is easy to specify. The magic is all in the #sortUp/#sortDown methods. Third, we can express chains of sorting criterion by concatenating them with the , method.&lt;br /&gt;&lt;br /&gt;If this is useful to others, I'll make it more usable, by pulling the tests out of the package so it doesn't need SUnitToo. And you can lobby Cincom to include it in VisualWorks. Or port it to your own flavor of Smalltalk. I did my best to write it in such a way that it would work in Squeak or Gemstone, or whatever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-8356227599099316325?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/8356227599099316325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/tag-sortfunctions.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/8356227599099316325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/8356227599099316325'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/tag-sortfunctions.html' title='TAG-SortFunctions'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7515306875906042828.post-465097008418146324</id><published>2010-11-19T08:59:00.000-08:00</published><updated>2010-11-19T09:00:59.787-08:00</updated><title type='text'>First Post</title><content type='html'>For years I have run a blog hosted by Cincom Systems, Inc (my current employer). With the maintainer of that blog framework moving on to other pastures, I decided now would be a good time branch out and move on to a different blog hosting platform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7515306875906042828-465097008418146324?l=objology.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://objology.blogspot.com/feeds/465097008418146324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://objology.blogspot.com/2010/11/first-post.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/465097008418146324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7515306875906042828/posts/default/465097008418146324'/><link rel='alternate' type='text/html' href='http://objology.blogspot.com/2010/11/first-post.html' title='First Post'/><author><name>Travis Griggs</name><uri>http://www.blogger.com/profile/01599271142862167244</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
