Simplicity
The other day, I pushed up a post on the simplicity and power of Smalltalk, using the #factorial method in class SmallInteger as an example. Here's the entire implementation within the superclass, Integer:
factorial | tmp | self < 0 ifTrue: [^self class raise: #domainErrorSignal receiver: self selector: #factorial errorString: (#errFactorialInvalid << #dialogs >> 'Factorial is invalid on negative numbers')]. tmp := 1. 2 to: self do: [:i | tmp := tmp * i]. ^tmp
So ignoring the error handling, the basic code is 3 lines. In one place. Sure, it relies on the ability of SmallInteger objects to auto-promote themselves - but the point is, as a developer, I don't need to worry about those details - it just works, and gives me the right answer. I also made the point that developers can create code that has the same kind of power - a quick look at #become: will explain what I mean. It's not a method to be used lightly, but - when you need it, it's invaluable.
If I wanted to write #factorial in Java, would I be able to write one method in one place? Would the issues of correct type get in the way, and force me to consider utterly irrelevant implementation details? That was the point I was making. The fewer "make the compiler happy" issues I need to deal with, the better off I am. At the end of the day, the compiler isn't my customer.
Update: Here's a Java implementation. Sadly, it won't work with numbers bigger than 20. Kind of makes my point, I think.





Comments
[Jules] April 20, 2006 10:10:52.000
In Haskell, it's even better (without errorhandling):
fac n = product [1..n]
(with errorhandling):
fac n | n > 0 = product [1..n]
There are many languages that don't have issues with smallints and largeints, Haskell handles them automatically, for example. Ruby does too, but the problem is that they're not "mainstream".
I really like the way Smalltalk handles ifTrue/ifFalse with closures/code blocks, where Ruby has a keyword for that.
[] April 20, 2006 12:32:37.000
Sure, in something like C++ you have to declare that you want to use your favorite arbitrary precision integer library, if that's what you desire. I thought Smalltalk fans would be all for that. You know, using libraries instead of adding language features.
template <class T> T fact(T n){ T f = 1; if(n<0) throw std::invalid_argument("arg to fact negative"); for(; n>1; f*=n, --n); return f; }[] April 20, 2006 12:44:21.000
template <class T> T fact(T n){[] April 20, 2006 12:56:49.000
Arg. It has a "BUG", I guess that's what happens when the preview feature doesn't work correctly. I guess it's slightly better than the Javascript editor, where there's no preview available at all. And do you really get that much spam that you need have rate limited posting?
There was a server error accepting your comment. You must leave at least 300 seconds between comment attempts.
Re: Simplicity
[ James Robertson] April 20, 2006 13:12:24.000
Comment by James Robertson
Yes, I get a lot of spam attempts. I look at my logs periodically, and if I didn't have a throttle, I'd get hosed.
Another annoyance with the Java implementation
[ Troy Brumley] April 20, 2006 13:20:33.000
Comment by Troy Brumley
As written, the Java implementation is a bit like putting lipstick on a pig. While I prefer the recursive nature of the Java implementation from an esthetic view, I don't like that it repeats the three guard clauses every time through in addition to the overhead of recursion. There should either be a private factorial method which counts on the guard clauses in the public factorial method, or it should go through the repeated multiplication as the Cincom Smalltalk version does.
fee fie foe fum I smell a java strawman
[Isaac Gouy] April 20, 2006 13:37:33.000
As before, here's the entire SML implementation shown on Wikipedia
a quick look at #become: will explain what I mean
How so? The factorial example demonstrates arbitrary precision arithmetic on numbers. Numbers are immutable:
would I be able to write one method in one place?
This Smalltalk implementation only provides arbitrary precision integer arithmetic - even in Java we can write one method in one place if we only ever use arbitrary precision integer arithmetic.
public static BigInteger factorial(BigInteger n) { return n.compareTo(BigInteger.ONE) <= 0 ? BigInteger.ONE : n.multiply( factorial(n.subtract(BigInteger.ONE)) ); }blame Princeton CS
[Isaac Gouy] April 20, 2006 13:44:56.000
Troy wrote I don't like that it repeats the three guard clauses every time... as the Cincom Smalltalk version does
The Smalltalk example code is part of Cincom's product, the Java example code is something James' grabbed off the web - it isn't anything to do with Java the language or libraries.
So, can you show us the real implementation?
[ Troy Brumley] April 20, 2006 14:48:19.430
Comment by Troy Brumley
In Smalltalk, we can see the library implementation. In Java, I don't know. My Mac is at home, and I don't have a Java environment on this PC, so I can't go looking to figure out what might be in the Java libraries. Google returned no items for my search "java.math.factorial source" while Yahoo! found quite a few hits, but nothing I felt was pertinent.
So, Isaac, can you delve into the library?
what might be in the Java libraries
[Isaac Gouy] April 20, 2006 15:04:14.460
afaik the easiest way is to look at the JavaTM API Specification index.
afaik after a decade they still haven't found a reason to add a factorial method to the standard libraries - maybe a coalition of university professors lobbied to prevent them ruining their first term class assignment :-)
[] April 20, 2006 15:10:24.801
If it is going to be part of the standard library, then you'd probably want to implement it with a good algorithm.
[Daniel Berger] April 20, 2006 15:56:47.820
If this is Smalltalk's idea of simplicity, I'll be sticking with Ruby, thanks.
naive factorial in Smalltalk
[Isaac Gouy] April 20, 2006 16:50:03.974
Daniel, we could write a naive factorial in Smalltalk like this
[] April 20, 2006 18:50:35.679
Just for the heck of it, in Ruby...
instance method
[Isaac Gouy] April 20, 2006 20:51:56.313
Would this correspond to the Smalltalk?