Question

I am currently a junior engineer and keen on learning best practices and expanding my experience. My question concerns any static programming language such as Java, C#, C++ etc.

When I am writing code, I like making it easy to read. In my opinion, reading code should be like reading a book. It should be fluent and elegant. Then, even if I do not need to use them, I like prepending this, superbase keywords whenever I can. Ditto for current class name when I want to use constants or static variables/methods.

Consequently, another developer can quickly have a long shot. He knows this method or var is in the current class or in mother class without needed to move to declaration. You may say to me it is really easy to do that with recent IDE. However, I know a bunch of guys who are still working with Vim, Emacs or other editors without these fancy features.

When explaining it, I like comparing my practices to a drama book. We have all read at least one of them, such as Macbeth from Shakespeare. Who has never felt frustrated to go back at the beginning of the book to know who is that character and what part he has in the plot? You did that so many times, right?

My question can be associated to literate programming practices. However, I assumed Donald Knuth's recommandations are more about commenting and adding macros to your code.

So I would like to know your opinions and feedbacks about these practices. Am I doing too much? Should I keep it simpler? Am I breaking OOP rules?

Here is a code sample:

class Bar {
    protected int _motherVar;

    public aBarMethod() { }
}

class Foo extends Bar {
    private static List<String> _strings;

    private int _myPrivateVar;

    public void aMethod() {
        super.aBarMethod();

        this._myPrivateVar++;
        super._motherVar -= 2;
    }

    public static String anotherMethod() {
        String outcome = "";

        for (String s : Foo._strings) {
            outcome += s;
        }

        return outcome;
    }
}
Was it helpful?

Solution

I'd advise against using this. in this fashion, not because it is in itself a bad idea. (Python, for example, forces you to do this with self. and python has a well-deserved reputation for readability.) But rather because the language doesn't enforce it. Because the language doesn't enforce it, it is easy to forget it on an individual line, which will then may confuse a future reader of the code. Same goes for super.. The compiler doesn't make you do it, so you may forget, and when you forget, the missing super. becomes misleading to someone who assumes it will always be there.

Using a prefix like _ or my or m_ is better because the compiler will force all instances to match. You can't forget that, so any reference to that attribute will be obvious as a member of the attribute.

That said, @kent-anderson's point in the comments is well taken. Ideally, you want to keep the classes and methods small enough that this sort of thing isn't needed. If, for example, you don't reference globals, avoid using superclass attributes directly and keep method names to 10-20 lines, it is pretty easy to see what are locals (as they are declared right there) and what are attributes on that object (everything else.)

OTHER TIPS

I think all three (this., super., and private member prefixes) are superfluous:

  • this. is superfluous if you have relatively small methods, which you should (rule of thumb: does one thing; code fits in a single screen). In a small method you can easily tell apart method-local and instance/class variables.
  • super. is superfluous because classes should be relatively small (due to single responsibility principle), so you should easily see if a member you access is or isn't in a current class.
  • Prefixing private members with underscore (or any other special prefix) is superfluous because you shouldn't care if something is private or not when using it in a method (you should only care if it is accessible), and if you have to care, this is probably a code smell of some sort, e.g. you're joggling a state of some public variable. (@StevenBurnap's point is valid, but you can forget to prefix (especially after refactoring) a member name with underscore just as easy as you can forget to prefix it with this. when accessing, so I think it doesn't help as well.)

Of course, if you have 1000+ lines of crap in a single class, all those things start to matter, but it is not a solution, but rather a prosthetic. I've seen people do that a lot, and it never helped my reading a bad code.

I'd only like to point out the following: This use of super

super.aBarMethod();

is actually harmful because it disables dynamic dispatch for this call. This means that if a sub-class overrides aBarMethod, you will still call the one defined in Bar, not the overriding one. Probably not what you'd expect. What was supposedly meant to be a stylistic nuance turned out to change the semantics of the code! It might work as expected now, but as you start refactoring later (moving method definitions around) your code will start to break in subtle ways. If you think that overriding the method would be a bad idea anyway, you should forbid it by declaring aBarMethod as final.1 In any case, the call inside Foo should read

this.aBarMethod();

(Where the this is disposable but I like it and you seem to like it too.) Since Foo inherits aBarMethod, it actually belongs to this so referring to it via this makes perfect sense. Only if you really mean to disable dynamic dispatch, refer to it via super. A common use case (though of questionable style) is if you want to extend a method that wasn't designed for this. For example, you could add to the toString method of your super class.

class Base {
    @Override
    public String toString() {
        return "base";
    }
}

class Derived extends Base {
    @Override
    public String toString() {
        return super.toString() + " & derived";
    }
}

Calling toString on a Derived object will yield "base & derived".

Personally, I always feel dirty if using the super keyword in my Java code. The only exception is calling the super-class constructor via super(…), which is fine. Sometimes, if overriding the toString, equals, hashCode and clone methods inherited from java.lang.Object using super (as in the example above) can hardly be avoided.


1 Doing so is generally a good idea. Some people – including me – prefer to make any method either abstract, final or empty. There is also a Checkstyle rule to enforce this. If you are concerned about good and consistent coding style, you'll probably like Checkstyle if you are not already using it.

I am not sure about Java, but C# has a whole set of framework design guidelines, that includes naming conventions for public and protected members. Protected fields are not recommended. Use protected properties instead.

Licensed under: CC-BY-SA with attribution
scroll top