Saturday, November 27, 2010

One Page Smalltalk Primer

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:

Wednesday, November 24, 2010

TAG-SortFunctions Redux

The original TAG-SortFunctions received relatively positive feedback, thank you.

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
somePoints sort: #x ascending, #y descending
I'm torn. I think it reads better in context, but not as well in isolation. Which do you prefer better?

The things that have changed are:

  1. The Tests have been separated out into a separate package

  2. 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.
    customers asSortedCollection: [:a :b | (UnicodeCollationAlgorithm collate: a with: b mode: #shifted) < 0]
    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.

  3. Because of that, you no longer need your flavor of Smalltalk to be able to do theSymbol value: trick.

  4. Since it all boils down to collation, I did add a new binary method: <=>. This is called the Spaceship operator in some language environments. So... you're Smalltalk flavor has to be able to support 3 character binary selectors for this to port.

  5. Despite seeming like a lot of changes, IIRC, the code actually ended up being smaller than the original.

Tuesday, November 23, 2010

In search of a method I can't name...

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.

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.

I can code this as
Dictionary withAll: (setOfStrings collect: [:each | each -> (Security.MD5 new hash: 'Hello World')])

but I really would rather capture this as a common method. What would you call it?

Monday, November 22, 2010

Smalltalks 2010

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.

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.

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 WITH 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 TO 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.

Friday, November 19, 2010


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.

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
sortedBy: aSingleArgBlock
^self sorted: [:a :b | (aSingleArgBlock value: a) < (aSingleArgBlock value: b)]

The problems with this approach are a couple.

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.

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.

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.

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.

Here's some examples.

Sort customers by last name in descending order.
customers asSortedCollection: [:each | each lastName] sortDown

Sort customers by last name in ascending order, and then by first name in ascending order.
customers sorted: [:each | each lastName] sortUp , [:each | each firstName] sortUp
customers sorted: [:each | each lastName] sortUp , [:each | each firstName]
(the second sortUp is taken care of automatically)

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.
points sort: #x sortUp, #y sortDown

Some things to note.

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.

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.

First Post

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.