What's wrong with this.?

I just saw yet another piece of Java code using this antipattern:

public class Foo {
    protected Thingy  thingy;
    protected WhatsIt stooWhacker;
    public Foo(Thingy thingy, WhatsIt stooWhacker) {
        this.thingy      = thingy;
        this.stooWhacker = stooWhacker;

I have always found this style repulsive, but this time I finally realised why.

There are variables that have a wide scope. They need to follow clear and consistent naming rules, and they should be look the same everywhere. In this example, the instance variables thingy and stooWhacker have wide scope. When I go looking for stooWhacker within its scope, every occurrence I find should be the instance variable.

There are variables that have a narrow scope. They can follow ad hoc rules. There is no point in giving a variable that is confined to ten lines a long name, and there is no sense in usurping the name of a wide scope variable.

This example violates these principles. The method parameters, with a very narrow scope indeed, usurp the instance variables' names, forcing the instance variables to be coded not just oddly, but differently.

Instead, write

    public Foo(Thingy thingy_, WhatsIt stooWhacker_) {
        thingy      = thingy_;
        stooWhacker = stooWhacker_;

or use some other decoration scheme, but use it on the method parameters, not the instance variables.

It may be of interest that there are object oriented programming languages in which you can't use the "this." anti-pattern. Eiffel is one. Smalltalk is another. This example in Smalltalk would look something like

Object subclass: #Foo
  instanceVariableNames: 'thingy stooWhacker'
    pvtThingy: aThingy stooWhacker: aWhatsIt
      thingy      := aThingy.
      stooWhacker := aWhatsIt.
  class methods:
    thingy: aThingy stooWhacker: aWhatsIt
      ^self basicNew pvtThingy: aThingy stooWhacker: aWhatsIt

From this perspective, we can see that the "this." anti-pattern goes with an approach to writing a constructor that proclaims too much about the internals of the class. The arguments of the constructor should be named from the perspective of the clients of a class, not from the perspective of the implementor. If you find yourself wanting to use internal names as part of an external interface, perhaps you have not sufficiently separated the interface from the implementation.