Tao Wen , a friend of mine and a new ThoughtWorker, put a comment on my last article.
so, you think the consistent thing means a lot? But how do you think the gracious or elegant feeling mean to the real expressiveness of business requirements? We can see lisp is very successful in researching area because of the simplicity nature inside which is also true to Smalltalk. But why they aren't successful in biz world? I think that is the problem you should further study, "how can the consistent feeling mean something to our everyday programming life?".
First of all, I should admit that I'd never thought about this question before, becasuse I think hankering after consistent concepts is some nature of us. The question enlightens me to thinking deep. Here are my points.
1.Complexity
Inconsistent concepts bring complexity.I'll give two examples.
First one is something in Lisp. Lisp has a very simple computing model called λ Calculation. There are three elements in this computing model: Function, λ Operator and · Operator. λ Operator picks up free variable from the function, and · Operator applies the variable with a concrete value. The whole evaluation-application thing is what we called symbolic algebra in math.For example, if we've a function whose expression is x + y.
((λx (λy . x + y)·3)·4)
=((λx. x+3)·4)
=4 + 3
=7
Since Lisp is kinda implementation of λ Calculation in computer, we could do the same thing in Lisp (and its dialects).
(define f (lambda x (lambda y (+ x y))))
(apply (apply f 3) 4)
or we could use some syntax sugar
(define (f x y) (+ x y))
((f 3) 4)
Most of things in Lisp are focus on evaluation, and the evaluation should be done in a simple consistent way: evaluating, applying value and then returning the value without any change to enviroment. It is the very same way that we do something in math.
But variable assignment was introduced to Lisp, so some functions which change enviroment instead of simple evaluating came to Lisp.For example:
(define (bad-f x y)
(begin
(set! z 5)
(+ x y)))
That bad function changes value of symbol 'z' while evaluating x + y. It is the variable assignment which breaks the consistent concepts. The consistent concepts suggests that function should do and only do evaluation. We must find a more complicated computing model to replace the simple elegant mathematical one.Here inconsistent brings complexities in computing model.
The other example comes from Java. Java is considered to be an object-oriented programming language with single root type system. Conceptually speaking, everything should be an object.But for some perfermance reason, Java has some primitive types (such as int, double, float etc.) too.Those primitive types introduced a algebraic world which paralleled to the object world, and broke the consistent concepts.Althought Java has some wrapper classes for those primtive types, they are not enough for filling the gulf between object and algebra.
We could use new Integer(3) to represent 3 in object world, but we could not simply translate
3 + 4 * 5
to
new Integer(3) + new Integer(4) * new Integer(5)
Algebraic calculation and object message sending are totally different. Although we could do that in Java 5, it also has lots of differences.Auto-boxing treats object as primitive instead of operator overloading in C++ which treats operator as object message sending.So in my opinion, auto-boxing in java5 is awful. Assginments and storage of primitive type and object have lots inconsistent semantics too. This inconsistent would bring complexity when we use Collection API(Remember Primitive Collection in Commons Collection Project? )
2. Side-Effect
The mainly cause of side-effect is putting some inconsistent concepts together. I'll also give two examples.
First example is the well-known side-effect in functional programming, which is caused by mixing Von-Nouma-style-things into λ Calculation. There are lots of discussion about this topic in functional programming community.It's meanless to repeat that again.
Second example comes from half-blooded object-oriented languages, for we'll find both object-oriented things and procedure-oriented things in these languages, and it'll be much more easier to write code in procedural way instead of object-oriented way.For example, we'd write code like this:
1if (order.getState() == Order.CANCEL)
2 do something for cancel;
3else if(order.getState() == Order.PAID)
4 do something for paid;
5else if(order.getState() == Order.DELIVERY)
6 do something for delivery instead of :
1public abstract OrderState {
2
3 protected Order _order;
4
5 protected OrderState(Order order){
6 _order = order;
7 }
8
9 public abstract void handler();
10}
11
12class CancelState extends OrderState {
13
14 public void handler() {
15 do something for cancel;
16 }
17}
18
19order.getState().handle(); For the keywords, it's convenient to write procedural codes as first segment, but for easy maintenance, it's better to write object-oriented codes as the second one.There are two inconsistent way to write code, and the side-effect is depend on how object-oriented the language is. It's more easy to write code like first one in C++ , and more easy to write code like second one in Ruby and Smalltalk. Actually, it's very hard for me to write code like first one in Smalltalk.
3. Constructing Software in a Recursive Way
There is a more large topic, maybe I'd better talk about this latter.
4. Elegance
Some aesthetic feelings comes from consistent concepts.I'll have the feeling of elegance if I could understand some complicated things via some consistent concepts.Take Newtonian System and Maxwell formula for example, they both are the elegant way to resolve problem via few consistent concepts.