"this" keyword question

Started by
13 comments, last by dilyan_rusev 11 years ago
@0r0d: You're right - people with a clean slate should start using the best habit available, which isn't 'this->'.

PS. Why not set the intellisense delay to 0 (as i have done)? It needs a bit of getting used to, but well worth it.

I never considered that. wacko.png I'll check if my IDE (QtCreator) has that feature and enable it (Edit: Can't find it. I guess I can get used to using the keyboard shortcut). I'll also check if it can visually distinguish from local and member variables (Edit: hmm, yes it can, and it was already enabled. I hadn't noticed it - I'll make it more apparent in the coloring).

If it can, and after getting used to it for a month or two, I might do a 'Replace All' of my 'this->' to ''. It might cause a few compile-time errors, but it'll cause no run-time errors in my codebase, so it'd be less than an hour's work to fully convert the code itself. The real conversion delay is how long it takes me to change. Probably only two weeks or so.
Advertisement

The real conversion delay is how long it takes me to change. Probably only two weeks or so.

That's usually the main reason why people dont change coding styles, although obviously it's mandated when you go to work someplace... normally. As far as myself, I try to logically analyze what I do and change if there's a more effective/efficient way. If the only reason to not change is that I'm used to it, then I just force myself. It's a small hit up front, but it always pays off in the end. This definitely means that when I look at very old code, I can see big differences, but if it's code I'm using again then I just go through as I see it and edit it to the new style. With tools like Visual Assist, changing the names of variables is extremely easy and fast.

Two examples that spring to mind:

1) passing the current class as a parameter to a function (covered by Servant of the Lord), and ...

2) calling an overloaded constructor in the same class, ie something like:


class Test
{
    public Test(int param)
    {
            
    }
 
    public Test(int param1, int param2) : this(param1)
    {
            
    }
} 

[size="2"]Currently working on an open world survival RPG - For info check out my Development blog:[size="2"] ByteWrangler

It's been covered fairly thoroughly by now in this context, but "this" is one of those keywords you may never have to use depending on your coding style. In my personal stuff, I don't decorate my member variables, so I end up using the keyword a lot, as it's typically advised *not* to mangle your parameter names just so you avoid typing "this". Parameters are part of your interface, and you want that as clean as possible. Typically, if you don't decorate your fields (for instance with m_*, or *_), the best name for that field is the one you probably call it in the first place, so why hunt for another?

There is however, another, more important (since there's not really any other way to do this one) application of the "this" keyword that I'm surprised hasn't been mentioned: self-returning. Very important for fluent interfaces. Some examples:


public class MyStringBuilder
{

  //constructor and stuff
  public MyStringBuilder Append(string newString)
  {
    //memory reallocation stuff -- probably push onto the end of a vector/list
    //depending on language.
    return this;
    
  }

  public string ToString()
  {
    //do stuff to turn our array into a string.
  }

}

public class WidgetContainer
{
  //fields and constructor and stuff
  public WidgetContainer addCheckBox( /*parameters*/ )
  {
    widgets.add(new CheckBox( /*args*/ );
    return this;
  }

  public WidgetContainer addRadioButton( /*parameters*/ )
  {
    widgets.add(new RadioButton( /*args*/ );
    return this;
  }

  //et al.
}

//meanwhile... somewhere in main.

var sb = new MyStringBuilder();
sb.append("Hello").append(", ").append("World").append("!"); //a contrived example.

var wc = new WidgetContainer();
wc.addCheckBox(200,300).addCheckBox(200, 310).addCheckBox(200, 320).addButton(200, 330, "Start!", someCallbackFunctor);

EDIT: I had never seen those Extension Methods before... That's really cool.

In my previous work place we were required to use "this" (it was part of the naming convention). At my current job, it is the opposite - it is a bit closer to the Java convention (used only in constructors IF there is a naming conflict... which isn't a poor programming practice for constructors).

I've been doing it both ways for years, and I tend to disagree with 0r0d. It does not decorate *only* fields, but methods as well. Before I started using this (which is slow because of the '.', but a lot faster than c++'s '->' which involves Shift as well), I thought it was slow, inefficient and that it littered the code. And then I changed my mind :) The reasons for this are:

  • In a huge code base, it is really important what comes from where
  • Coloring is cool, but is slow as hell, often buggy, even on powerful, high-end machines
  • Most of the time, I read code. When you deal with a huge code base, with tons of stuff you haven't written, you want to be able to easily analyze the API.
    • First, this immediately tells you the scope of variables and methods.
    • Second, this tells you immediately what is static, and what is instance-bound.
    • For that matter, part of the naming convention was to prefix static methods with their class names even inside the class itself. To your eyes it might seem as an abomination, but it is quite helpful when you swim in unfamiliar code.

Overall, the benefits are that you get a lot of information about the code with just a glance.

The downside (especially with prefixing static methods) is that you often get well beyond the 80 characters per line limit. And nothing kills readability more than horizontal scrolling. This is why we had unofficial coding conventions about how to split the code on multiple lines, so that it remains readable.

@SeraphLance - For the sake of readability and API extendability, don't use method extensions or method chaining. For that matter, fluent API != method chaining. Here are some reasons why I've come to dislike both after years of using them (and designing APIs with them)

  • When you see timeInSeconds.Normalize(), you've got no clue what is going on. Is this a method? Is this an extension method? Which class provides this extension? Nothing stops Joe to add the next extension method in another class. The IDE can help you, but you don't have this information at first glance, so it slows down readability
  • Extension methods depend on the namespace. So you have two problems:
    • Namespace pollution - when you put too many extension methods in some global namespace (God forbid you put anything in System!)
    • Discoverability - it is very difficult for end users to use your API. What happens usually is that they find out some of your methods "don't work" when they haven't included the right namespace, or they don't ever discover them.
  • Extension methods are static,
    • ... and they inherit all the Builder pattern problems with extensibility. Normal methods can be made virtual and extended by the end user. Static methods are defined in a completely independent class (hopefully one), so they can't be overridden. What's more, they can only access the public members of the class they extend, so extension methods might have bad performance or may not even be able to implement the required functionality without an interface change.
    • You might want to add a method with the same name in the next version of your API... what happens then? Obviously you can't for readability's sake, but then you have to come up with some unintuitive name.
  • Method chaining is bad for debugging. What most users of the API tend to is is stack method calls on a single line. When you don't chain methods, stepping into the correct method is a piece of cake, because, of course, you will invoke no more than one method per line, right?
  • Method chaining is bad for readability. I cringe when I see how most people write their Linq queries... it is a very bad idea to have no coding style about vertical space, yet most work places don't have one. So you have lots of different coding styles when invoking the method chain.
  • Fluent APIs are extremely difficult to come up with. For every non-trivial fluent API, you've got different faces for the concepts you're abstracting. If you put in inheritance, you usually end up all your faces as generic classes with a lot of generic parameters, like Base<TImplementation, TWhatIActaullyNeed> (this happens because you want auto-completion to work when the user chains the super class methods of a derived class). It is way more complicated than composition and/or decorator pattern (which is difficult in terms of discoverability in itself.

This topic is closed to new replies.

Advertisement