Language Smell

A LanguageSmell is a CodeSmell that occurs due to the inability of the language to express the concept cleanly. Sometimes called an "idiom" or a "pattern." (Not all patterns are like this, but some are.)

Examples:

Solutions:


Some examples from the C++/Java family of languages:

Iteration

Is the Collection.contains() method a pattern? No, it's just a method call, because the Java language allows you to abstract away the concept of "contains". You only have to spend one word to express the concept, "See if this collection contains this particular object."

There are lots of concepts, though, that Java can't express directly. Iterating over a collection, for example. That's why I had to train my fingers to bang out code like:

    Iterator it = noodles.iterator();
    while (it.hasNext()) {
        Noodle n = (Noodle) it.next();
        n.doSomething();
    }
This isn't exactly a CodeSmell - this code is about as good as it can be in Java. It's more like a LanguageSmell - a piece of code that alerts you to a problem that can't be fixed without modifying the language. It's duplicated code, plain and simple - but you can't get rid of the duplication because Java can't express those kinds of concepts. In other languages, I can express the concept of iteration using just one word:

    noodles.each  {  |n|  n.doSomething  }
(It's not just a matter of adding a "foreach" statement to the language; there are all sorts of related LanguageSmells. Take a look at the Smalltalk or Ruby collection classes, if you're interested.)

[But you can get rid of that duplicated code. Java canexpress a "foreach" concept. Take a look at the collections package at JakartaCommons for example:

    CollectionUtils.forAllDo(noodles, doSomethingFunctor);
]

Um... looking at the JavaDoc for the JakartaCommons collection stuff, it looks to me like you've left out a bunch of the code. If you include the code for creating the actual "closure" object, it'll look like this:

    CollectionUtils.forAllDo(noodles, new Closure() {
        void execute(Object n) {
            ((Noodle) n).doSomething();
        }
    });
Is that really any less wordy than the normal Iterator version?

No, not if you're creating a new Closure class each time. I expected doSomethingFunctor to be an existing one.

Sure, you can share the block definition, if you ever have loops with identical blocks. How many of your "for" and "while" loops have identical blocks? (That's almost a serious question, actually. I've never bothered to count. It might be interesting to count up all the loops in a program and see what percentage have identical blocks. I'm betting it's almost zero, though.)

As a different kind of counterexample, C# has a foreach, but sure smells like Java to most. "SmellsLike?" would seem to be a more defining characteristic--something central to the language, since I can add or remove features and have the same core smell.

Interesting. Adding a foreach statement doesn't fix the smell, because the "each" method is just one example of the kind of method you need blocks for. Here are some more examples:

    boys = people.select  {  |p|  p.isMale  }

ages = people.map { |p| p.age }

aMaleOver18 = people.find { |p| p.isMale && p.age >= 18 }

hourglassPointer.showDuring { doSomethingExpensive() doSomethingElseExpensive() }
If C# had added general-purpose blocks, this smell would go away. As it is, though, the foreach statement doesn't help much. I agree that C# has a lot of the same LanguageSmells that Java does.

Update: Java 5 has new semantics that behave like foreach:

    for(Noodle n : noodles ) {
        n.doSomething();
    }

But you still need to simulate Blocks with inner classes for the other cases. One could argue that using an iterator for finding an element as in your example is suboptimal, as some Collections are drastically faster when they can perform a binary search.


Factories

A more interesting example is the discussion on whether to UseFactoriesToBuildObjects. That whole discussion feels like a LanguageSmell to me, because I've worked in languages where the issue just doesn't exist.

Why do we need factory objects? Well, because in Java and C++ (and lots of other languages), a "new" statement always references a hard-coded class:

    c = new Car();  // always instantiates a Car object
If you want to be able to specialize the kind of car that you create, you need to modify this code. Maybe you use a FactoryMethod:

    c = newCar();
Or maybe you use a AbstractFactory:

    c = carFactory.newCar();
So every time you instantiate an object in Java, you have a decision to make: do I want to do it the normal way with "new", or use some sort of factory thing? That's what sparks discussions like the one on the UseFactoriesToBuildObjects page. My father was recently considering using factories for all instantiations, because he often wants to be able to substitute MockObjects for testing purposes.

In some languages, it isn't an issue:

    c: car new.
In the SelfLanguage, there's no such thing as hard-coding a class name. All you can do is send messages; the above code is approximately equivalent to the Java code:

    c = car().new();
If you want to specialize the kind of car you create, you override the "car" slot to hold whatever kind of car you want, or to hold a method that chooses a type of car based on runtime state. You can do it for a single object, or a whole class of objects, or an entire subsystem, or globally. And you get this flexibility everywhere, with no extra effort or thought, and no cost at all in readability or complexity.

or to hold a method that chooses a type of car based on runtime state Example?

Above in Java:

    c = car().clone();
But requires that car() returns a Cloneable Object.

This looks silly at first, but use Interfaces for typing and combine it with anonymous inner classes and it removes a lot of needs for hard-coding class names.

related AbstractConstructor, NewConsideredHarmful, DependencyInjection

Bracha's NewspeakLanguage? and a new language effort by a few developers at Google - NoopLanguage? - both support DependencyInjection at the language-level, which largely means supporting abstraction of constructors.


CategoryCodeSmell CategoryRefactoring


EditText of this page (last edited October 13, 2013) or FindPage with title or text search