Tags

, , , ,

Time for a more technical post, related to my day job rather than my night job.

In my capacity as a web dev, I do server-side programming, mostly in Java. But my background from way back is in Smalltalk. Both are object-oriented languages, though there are several main differences (you may detect a hint of bias here):

    • Smalltalk is completely OO, Java is mostly OO.
    • Smalltalk doesn’t have “primitives” that aren’t objects, and even nil (unlike Java’s null) is an object.
    • Smalltalk is easy to learn initially, has the simplest syntax imaginable (simply “object message”, which always returns an object so you can chain), yet you can do so many things more elegantly than in any other language I know. Java comes with syntactical baggage from its C background, has many times more reserved keywords than Smalltalk’s five, and can be… cumbersome.
    • Smalltalk is what programming should be, Java is what programming is to most programmers (and here I’ll shamelessly bundle Java with C, dot Net, and so on).
    • Despite the above, Smalltalk is a niche language and Smalltalkers are a dying breed while other languages flourish.

I can imagine non-Smalltalkers smirking condescendingly by now, or at least sitting there with an eyebrow raised skeptically, wondering whether it’s worth reading on. If you are one of those, especially if you do Agile development, I’d recommend at least reading the shorter of the two articles I mention at the end of this post. (Plus, that way you’ll have to scroll past some Java code that may catch your interest after all.)

Occasionally while programming in Java, I find myself wishing that some of the Smalltalkish Ways Of Doing Things (TM) were available to me in Java. So, a while back (I think it was after I read that block closures had yet again been moved back to a future Java release), I decided to try to bring some Smalltalk into Java with a few simple little classes and methods. Do you absolutely need this? Not at all. Is it at least useful? Maybe, but probably only to some. Is it fun wrapping your head around different concepts and playing with something new? Heck, yeah. The complete source code is linked at the bottom of the post.

Some examples of defined methods

One of Smalltalk’s best features is the ability to pass around “block closures”, that is, to define a piece of code (with or without variables of its own) and to pass it to other objects or methods as though it were any other variable.

The easiest example works with an on-the-fly instance of java.lang.Runnable.

In Smalltalk, to do something with a block of code over a range of numbers, you’d use from:to:do:. The arguments are inserted after the colons, and typically parameters are prefixed with the article “a” or “an” to indicate that it’s just a possible value. (Personally, I think this makes code more readable in Java as well.) So the method definition could look like this: from: aStartingNumber to: anEndNumber do: aBlock. Let’s look at this translated to Java. We’ll use a Runnable instance as a simple no-argument block and simply iterate over the number range.

public static void fromToDo(int aFromIndex, int aToIndex,
    Runnable aRunnable) {
  for (int i = aFromIndex; i <= aToIndex; i++) {
    aRunnable.run();
  }
}

To use Smalltalk’s timesDo: method, then, you’d simply call the method we’ve just defined with 1 as the from index.

public static void timesDo(int aNumber, Runnable aRunnable) {
  fromToDo(1, aNumber, aRunnable);
}

Now let’s get a bit trickier. We’ll use some collections (which have made their way to Java from Smalltalk, of course), some generics (because Java is strongly typed and wants to know types up front), and some reflection. The aim is to try and implement Smalltalk’s select: and reject: methods that operate on collections to select or reject elements that meet certain conditions. Since they’re rather similar, we’ll refactor the common code while we’re at it.

public static <ListType, ArgumentType> List<ListType> select(
    Collection<ListType> aCollection,
    BlockClosureBooleanWithOneArgument aBlockClosure) {
  return selectOrReject(true, aCollection, aBlockClosure);
}

public static <ListType, ArgumentType> List<ListType> reject(
    Collection<ListType> aCollection,
    BlockClosureBooleanWithOneArgument aBlockClosure) {
  return selectOrReject(false, aCollection, aBlockClosure);
}

private static <ListType, ArgumentType> List<ListType> selectOrReject(
    Boolean shouldSelect, Collection<ListType> aCollection,
    BlockClosureBooleanWithOneArgument aBlockClosure) {
  List<ListType> selectedValues = new ArrayList<>();
  for (ListType eachElement : aCollection) {
    if (eachElement == null && !shouldSelect || eachElement != null
        && shouldSelect == aBlockClosure.runWith(eachElement)) {
      // i.e. it's null and reject, or both true or both false
      selectedValues.add(eachElement);
    }
  }
  return selectedValues;
}

Note the other convention I’ve carried across from Smalltalk, to prefix variables used in an iteration with “each”, to emphasise that we do this for each value. The BlockClosureBooleanWithOneArgument we’re using is a simple interface defined as follows:

public interface BlockClosureBooleanWithOneArgument {
  public <ArgumentType> Boolean runWith(ArgumentType anArgument);
}

One more example before we get to how to use these methods. Smalltalk’s inject:into: is a wonderfully versatile method, but it can take a moment or two to wrap your head around it initially. You inject an initial value into a block of code, and execute this on a collection. So you have aCollection of things, and tell it, “starting with anInitialValue, execute aBlock on each of your elements”: aCollection inject: anInitialValue into: aBlock. (See how wonderfully the code reads almost like a simple English sentence, especially if you follow some simple naming conventions? Hence the name “Smalltalk”.) What would it look like in Java? Glad you asked. Here’s one possibility (I actually have two more implementations using reflection in my code which you can download below):

public static <ResultType, ListType> ResultType injectInto(
    ResultType anInitialValue, Collection<ListType> aCollection,
    BlockClosureWithTwoArguments aBlockClosure) {
  ResultType result = anInitialValue;
  for (ListType eachElement : aCollection) {
    result = aBlockClosure.runWith(result, eachElement);
  }
  return result;
}

Obviously BlockClosureWithTwoArguments is defined just like for one argument, except… with two. (I actually don’t like people starting method bodies with “result = …” and returning the result at the end, but in this case I don’t actually see a more elegant way. Maybe “updatedValue” would have been a better name than “result”?)

Some examples of how to use them

That’s all well and good, but the above examples wouldn’t be very useful without showing how they can be used. In my source code (see below), I’ve done this in a test class, both to show how the methods can be used and as a control of their correctness. The class with my Smalltalk code is called… drumroll… Smalltalk, while the test class is SmalltalkTest.

A very simple usage of from:to:do:, or fromToDo() since we’re looking at the Java version, could be to append a character a certain number of times (yes, you could use timesDo() for that, but let’s imagine we’re in code where we have the from index and to index and don’t feel like subtracting).

@Test
public void testFromToDo() {
  final StringBuilder builder = new StringBuilder("10as:");
  Smalltalk.fromToDo(1, 10, new Runnable() {
    @Override
    public void run() {
      builder.append('a');
    }
  });
  assertEquals("10as:aaaaaaaaaa", builder.toString());
}

To test our select() and reject() methods mentioned above in a simple use case, let’s use reflection to call the method startsWith() of the String class.

@Test
public void testSelectAndReject() throws Exception {
  String[] testStringArray =
      { "Test1", null, "Test 2", "", "Another Test",
          "Yet another test", "Test...3" };
  List<String> testStrings = Arrays.asList(testStringArray);
  String[] stringArrayStartingWithTest =
      { "Test1", "Test 2", "Test...3" };
  String[] stringArrayNotStartingWithTest =
      { null, "", "Another Test", "Yet another test" };
  List<String> stringsStartingWithTest =
      Arrays.asList(stringArrayStartingWithTest);
  List<String> stringsNotStartingWithTest =
      Arrays.asList(stringArrayNotStartingWithTest);
  Method startsWithMethod =
      String.class.getMethod("startsWith", String.class);
  List<String> selections =
      Smalltalk.select(startsWithMethod, testStrings, false, "Test");
  List<String> rejections =
      Smalltalk.reject(startsWithMethod, testStrings, false, "Test");
  assertNotNull(selections);
  assertNotNull(rejections);
  assertEquals(stringsStartingWithTest, selections);
  assertEquals(stringsNotStartingWithTest, rejections);
  assertEquals(stringsStartingWithTest.size()
      + stringsNotStartingWithTest.size(), testStrings.size());
}

If the lights all turn green on your tests, you know the code correctly selected the test strings that start with “Test” and rejected the others. (I’m using JUnit 4 here, which, you guessed it, comes from SUnit testing in Smalltalk, where all good things come from, including Agile development.)

Simple, yes. Let’s get trickier then. Everybody’s favourite example, the Fibonacci sequence, using injectInto() since it’s all about starting with a collection (in this case simply the set of natural numbers) and using them to inject an initial value into a simple algorithm to calculate the next value.

@Test
public void testInjectInto() throws Exception {
  Integer[] numberArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  List<Integer> numbers = Arrays.asList(numberArray);
  List<Integer> fibonacciList = new ArrayList<>();
  fibonacciList.add(1);
  Integer[] expectedArray = { 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 };
  Collection<Integer> expected = Arrays.asList(expectedArray);

  BlockClosureWithTwoArguments fibonacciBlock =
      new BlockClosureWithTwoArguments() {
        @SuppressWarnings("unchecked")
        @Override
        public <ReturnType, FirstArgumentType, SecondArgumentType>
            ReturnType runWith(
                FirstArgumentType aFirstArgument,
                SecondArgumentType aSecondArgument) {
          List<Integer> eachList = (List<Integer>) aFirstArgument;
          Integer eachIndex = (Integer) aSecondArgument;
          Integer lastNumber = eachList.get(eachIndex - 1);
          eachList.add(lastNumber
              + (eachList.size() > 1 ? eachList.get(eachIndex - 2)
                  : 0));
          return (ReturnType) eachList;
        }
      };

  assertEquals(expected,
      Smalltalk.injectInto(fibonacciList, numbers, fibonacciBlock));
}

Not nearly as tricky as it may look at first glance – just think about how the sequence works and it should become obvious. We’re starting with a list that initially only has a “1” in it and, in each iteration, adding to the list the sum of the last two items in the list (or just the last one if there’s only one to take care of the base case). It’s not the sort of thing you typically do in everyday coding, but I’m sure if you look for it, you’ll spot opportunities where something like this could be useful. Keep in mind that the definition of your code block, however complex, only needs to be done once; the code can then be re-used wherever needed in a quick one-line call.

Show’s over

That’s pretty much it. If you’d like to, take a closer look by downloading the full source code. Feel free to download/use/ignore as you see fit. It has the following Java methods (some with several versions) and unit tests based on the original equivalents Smalltalkers will recognise:

    • fromTo()
    • fromToDo()
    • fromToDoWithIndex()
    • timesDo()
    • doWith()
    • select()
    • reject()
    • collect()
    • detect()
    • contains()
    • includes()
    • injectInto()

If you spot any mistakes, have any suggestions, improvements, or any other comments/questions, please let me know below in the comments.

Finally, I’d like to direct anyone who may be interested to two great articles I’ve found that have really resonated with me.

Why Smalltalk isn’t just “another language”, written by Dafydd Rees in 2010. Not all that long, but makes some great points about Smalltalk and Agile.

Why Java Isn’t Smalltalk: An Aesthetic Observation, written by Sigrid E. Mortensen back in 2001 (so old, in fact, that the only place I still found it is in an archived version of the original site). It’s a fair bit longer, but well worth the read, as it makes some excellent points about the value and impact of losing elegance and simplicity in programming.

Cheers,

AMC