Lessons learned in Smalltalk: Cascades

Ik werk nu een jaar professioneel als Smalltalk ontwikkelaar en het leek me wel handig om op een rijtje te zetten wat ik allemaal geleerd heb over Smalltalk. Te beginnen met cascades.

Cascades in Smalltalk zijn een beetje te vergelijken met de With statement in Visual Basic:

1
2
3
4
With aPoint
  .x = 10
  .y = 100
End With

In Smalltalk geef je met een punt komma (;) aan dat je nog een message naar dezelfde ontvanger wilt sturen. En in tegenstelling tot Visual Basic kan je de ontvanger ook teruggeven, want handig is bij het initializeren van een object:

1
aPoint := (Point new) x: 10; y: 100.

Je hebt ook minder tijdelijke variabelen nodig hebt. Het voorbeeld van Martin Fowler over fluent interfaces;

1
2
3
4
5
6
7
8
9
10
11
12
private void makeNormal(Customer customer) {
  Order o1 = new Order();
  customer.addOrder(o1);
  OrderLine line1 = new OrderLine(6, Product.find("TAL"));
  o1.addLine(line1);
  OrderLine line2 = new OrderLine(5, Product.find("HPK"));
  o1.addLine(line2);
  OrderLine line3 = new OrderLine(3, Product.find("LGV"));
  o1.addLine(line3);
  line2.setSkippable(true);
  o1.setRush(true);
}

kunnen we in Smalltalk schrijven als:

1
2
3
4
5
6
7
8
makeNormal: customer
 
  customer addOrder:
    (Order new)
      addLine: (OrderLine  withAmount: 6; product: (Product find: 'TAL'));
      addLine: ((OrderLine  withAmount: 5; product: (Product find: 'HPK')) skippable: true);
      addLine: (OrderLine  withAmount: 3; product: (Product find: 'LGV'));
      rush: true.

En dan komen we al aardig in de richting van de fluent interface oplossing van Fowler.

1
2
3
4
5
6
7
private void makeFluent(Customer customer) {
  customer.newOrder()
  .with(6, "TAL")
  .with(5, "HPK").skippable()
  .with(3, "LGV")
  .priorityRush();
}

Ik kan de Smalltalk code nog verder verfijnen en tot een simpele interne DSL komen. Het blijft dan nog steeds Smalltalk en gaat niet tegen de natuur van de taal in zoals de Java fluent interface oplossing.

Het gebruik van cascades is als pattern opgenomen in Smalltalk Best Practice Patterns van Kent Beck. Hij geeft aan een cascade alleen te gebruiken als de messages bij elkaar horen en niet als ze toevallig naar dezelfde ontvanger verstuurd moeten worden.