96

Is it good/bad/acceptable practice to pass the current object in a method call. As in:

public class Bar{
    public Bar(){}

    public void foo(Baz baz){
        //  modify some values of baz
    }
}

public class Baz{
    //constructor omitted

    public void method(){
        Bar bar = new Bar();
        bar.foo(this);
    }
}

Specifically, is the line bar.foo(this) acceptable?

Cœur
  • 37,241
  • 25
  • 195
  • 267
diestl
  • 2,020
  • 4
  • 23
  • 37
  • 60
    Why would that not be acceptable ? It's common. – Denys Séguret Jul 03 '13 at 07:15
  • 3
    So... that's 8 yes's :) (And yes, i'm keeping it updated.) – Alex Gittemeier Jul 03 '13 at 07:18
  • 2
    non-static anonymous class automatically pass this reference of the super class, so this will be acceptable. the only caution would be to careful about circular references. – Mehul Rathod Jul 03 '13 at 07:18
  • Of course it is the good practice. – Ugur Artun Jul 03 '13 at 07:19
  • 1
    First time I had to pass `this` to a function it seemed weird to me, because I had never seen it before. But afterwards I learnt that it is in fact pretty common... – Carlos Campderrós Jul 03 '13 at 08:38
  • I've head to engineer all kinds of bad/terrible solutions to avoid passing `this` to a function. Including throwing exceptions etc. Passing `this` is definitely better :p. – diestl Jul 03 '13 at 09:28
  • 6
    There is one caveat though: you shouldn't pass this in constructor because that'd expose your object in an inconsistent state. People typically do that when they create callbacks (e.g. ActionListener) as anonymous inner classes and then pass that to another object. – Tamas Rev Jul 03 '13 at 11:02
  • 3
    @dystroy although I agree it is acceptable, implying that it is acceptable **because it is common** is really bad logic. Doing something because its common can get you into a lot of trouble – Carrie Kendall Jul 03 '13 at 15:18
  • Not really sure you understood what I meant.. as I said I agree with you. Just that in general, doing something because others do might lead down a dangerous road. – Carrie Kendall Jul 03 '13 at 15:22
  • 1
    @Carrie Kendall: that's slippery slope. Just because a construct is not necessarily bad does not mean that it's recommended to be used for all situations; likewise the possibility of misuse is not a reason to avoid a particular construct. There's time and place for everything. – Lie Ryan Jul 04 '13 at 01:27

10 Answers10

166

There's nothing wrong with that. What is NOT a good practice is to do the same inside constructors, because you would give a reference to a not-yet-completely-initialized object.

There is a sort of similar post here: Java leaking this in constructor where they give an explanation of why the latter is a bad practice.

Community
  • 1
  • 1
morgano
  • 17,210
  • 10
  • 45
  • 56
  • 18
    +1: good to point out the hazard in referring to 'this' in constructors. – Bathsheba Jul 03 '13 at 07:19
  • It is not necessarily a bad practice. For example, a `Car` constructor may create `Wheel` instances, a `Car` without `Wheel` would be incompletely initialized, while a `Wheel` without a corresponding `Car` would also be incompletely initialized. In this case, it may be acceptable in the Car's constructor to pass `this` to the Wheel's constructor. The other alternative would be to make both Car and Wheel have private constructor and use a factory function that constructs the Car, Wheel, and installs the Wheel on the Car; but should that be a static method on Car or static method on Wheel? – Lie Ryan Jul 03 '13 at 13:34
  • Obviously, you should create a `CarFactoryWheelInstallerProxy` that installs the wheels for you. – Kevin Jul 03 '13 at 15:26
  • 6
    @LieRyan `Wheel` is completely subordinate to `Car`, and IMO shouldn't know about `Car` at all. – Izkata Jul 03 '13 at 17:22
  • 3
    The ONLY bad thing about using `this` from within a constructor is if `this` is passed into a method or context from which the not-yet-fully-contructed object reference is published to untrusted or unknown clients (or client code that assumes it has a view to a fully constructed object). Passing `this` from a constructor to a package-private method that performs a common initialization is, in my opinion, not only acceptable but desirable. – scottb Jul 03 '13 at 17:26
  • @Izkata: but that doesn't always work. Often times the subordinate does need to know the car, such as to notify the superordinate about changes in the subordinate's situation. For instance, the wheel may be equipped with a mechanism to detect flat tire. Instead of having the car poll the wheel's flatness status, it's often more desirable to let the wheel notify the car when it's flat. – Lie Ryan Jul 03 '13 at 21:06
  • @LieRyan This question is about Java. Generally that would be done with `throw new FlatTireException();`, still no need to know about `Car`. – Izkata Jul 03 '13 at 21:54
  • @Izkata: the caller of Wheel may not necessarily be Car; for instance, it could be a Nail on the road that is currently above the call stack, not Car itself, thus the flat tire exception would be sent to Nail and the Car would never know that its tire are flat so the code to light the indicator lamp to notify the driver would not have been called. – Lie Ryan Jul 04 '13 at 00:58
  • This common design pattern is usually called the observer design pattern, the car is the observer, and the wheel the observed. Whatever caused the observed object's (Wheel) state to change will cause a notification to the observer (Car), without the Nail having to be aware of the relationship between Wheel and Car. – Lie Ryan Jul 04 '13 at 01:03
  • Is passing `this` as method parameter better than using a single instance as field variable in second class? I heard that accessing local variables is faster than accessing fields, so why not passing every current `Foo` instance as a parameter to `Bar` methods (via `this` keyword) instead of having a single `private Foo fooInstance` in `Bar` as field variable? Am I correct? – Alireza Mohamadi Jan 12 '17 at 07:58
156

There's no reason not to use it, this is the current instance and it's perfectly legitimate to use. In fact there's often no clean way to omit it.

So use it.

As it's hard to convince it's acceptable without example (a negative answer to such a question is always easier to argument), I just opened one of the most common java.lang classes, the String one, and of course I found instances of this use, for example

1084        // Argument is a String
1085        if (cs.equals(this))
1086            return true;

Look for (this in big "accepted" projects, you won't fail to find it.

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • 16
    -1 because there is no mention of the fact that bi-directional class relationships are more complicated than uni-directional relationships. It is vital to ensure that software is clear as possible. In the specific example above it would be more sensible to [Move Method](http://sourcemaking.com/refactoring/move-method) foo to the Baz class to avoid having a bi-directional reference between the two classes and to bring the behaviour and the data together. – JW. Jul 03 '13 at 16:38
  • 38
    -1 to an answer because you found in the question an additional minor detail on which you can comment ? Really ? – Denys Séguret Jul 03 '13 at 16:41
  • 2
    @dystroy No. I gave -1 because it is important to avoid bi-directional links if possible. Hence, I completely disagree with the answer. That's what the downvote is for. – JW. Jul 03 '13 at 17:10
  • @JW You disagree with the answer *yes* to *"Is passing 'this' in a method call accepted practice in java"* ? – Denys Séguret Jul 03 '13 at 17:11
  • 13
    @dystroy Yes I disagree with your opening phrase: "There's no reason not to use it". – JW. Jul 03 '13 at 17:12
  • 4
    In practice, in real code (contrary to OP's simplified example), passing `this` doesn't mean you add a bidirectional link, because of inheritance and interfaces for example. – Denys Séguret Jul 03 '13 at 17:17
  • 2
    @JW. You'd prefer `this.fooBy(new Bar());`? That is entirely personal style. I see no reason for your -1, either.. (And it's harder to read in some cases because the action (function) name has to be reversed) – Izkata Jul 03 '13 at 17:19
42

Yes, but you should be careful about two things

  1. Passing this when the object has not been constructed yet (i.e. in its constructor)
  2. Passing this to a long-living object, that will keep the reference alive and will prevent the this object from being garbage collected.
Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Stefanos T.
  • 550
  • 5
  • 7
  • 1
    Note that a constructor in Java is not really a constructor, it's probably more appropriate to call Java's constructor "initializer". Within Java constructor, the object has actually been allocated memory, this the object actually has already existed/constructed within the constructor. – Lie Ryan Jul 03 '13 at 21:15
  • 1
    Not really, the object may have some instance variables that have not been initialised yet, so that the object is not fully operative yet. So, in the constructor, you could pass this to a second object, that could invoke a method to the object that has not initialized all its instance variables yet. – Stefanos T. Jul 03 '13 at 23:11
  • yet, as long as the second object are aware that the passed object isn't initialized, and treats it as an opaque object, or only call methods that have been declared safe in such state, it will cause no problem to pass `this` to it. Doing that would have been impossible if the object hasn't been allocated. – Lie Ryan Jul 04 '13 at 00:49
13

It's perfectly normal and perfectly acceptable.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
5

this stands for the current object. What you are doing is sytatically correct but i don't see a need of this if you are calling the method in the same class.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136
  • 2
    In the example code, Baz.method() is an instance method which calls Bar.foo() with the instance of Baz as a parameter. So the OP is not calling a method in the same class. – user Jul 03 '13 at 09:12
  • @MichaelKjörling I think Juned is saying that, by moving the foo() method into the Baz class, there would be no need to pass `this` between the two classes. So, there is no need to add the extra complexity. – JW. Jul 03 '13 at 16:44
5

It is bad practice to pass the current object in a method call if there less complex alternatives to achieve the same behaviour.

By definition, a bidirectional association is created as soon as this is passed from one object to another.

To quote Refactoring, by Martin Fowler:

Change Bidirectional Association to Unidirectional (200)

Bidirectional associations are useful, but they carry a price. The price is the added complexity of maintaining the two-way links and ensuring that objects are properly created and removed. Bidirectional associations are not natural for many programmers, so they often are a source of errors

...

You should use bidirectional associations when you need to but not when you don’t. As soon as you see a bidirectional association is no longer pulling its weight, drop the unnecessary end.

So, theoretically, we should be hearing alarm bells when we find we need to pass this and try really hard to think of other ways to solve the problem at hand. There are, of course, times when, at last resort, it makes sense to do it.

Also it is often necessary to corrupt your design temporarily, doing 'bad practice things', during a longer term refactoring of your code for an overall improvement. (One step back, two steps forward).

In practice I have found my code has improved massively by avoiding bidirectional links like the plague.

JW.
  • 4,821
  • 5
  • 43
  • 60
  • You confuse a simplified example with the need to establish a bidirectional link. Passing this as parameter, as should be clear with many examples of the java.lang source code (for example the one you saw in my answer) doesn't mean you add a bidirectional dependency. This answer should have been a comment in my opinion. – Denys Séguret Jul 03 '13 at 17:19
  • @dystroy Thanks for adding a comment to explain why you downvoted. Its always good to know. I shall modify my answer to clarify that, by definition, a bidirectional association is created as soon as `this` is passed. – JW. Jul 03 '13 at 17:24
  • 1
    *"by definition, a bidirectional association is created as soon as this is passed"*. This makes clear where you fail to understand. Look at the example I give. There is no bidirectional link because the type of the argument in `equals` is Object. This is very common : the receiving method defines its argument as a more general class or as an interface. One of the reason such a pattern is used in java *is* to avoid unwanted dependencies. Before going longer I'd suggest you take a look at the **many** occurrences of passing `this` as argument in respectable java libraries. – Denys Séguret Jul 03 '13 at 17:37
  • Let's just agree to disagree. My life has become much easier since I have avoided passing `this` in my code, where possible. I'd recommend others to do so. – JW. Jul 03 '13 at 17:45
  • 2
    @JW: the reasoning given in this answer is irrelevant. It's always a bad idea to do X if there's something else that's simpler, for any value of X. – Lie Ryan Jul 04 '13 at 01:40
4

Yes. you can use it.Its just common in programming to pass this.But there are pros and cons about using that.Still it is not hazardous to do so.

Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • There are plenty of side effects. It adds complexity. – JW. Jul 03 '13 at 16:41
  • If those many side effects are there we couldn't find a single evidance like that in our java source code .see @destroys example from source code. – Suresh Atta Jul 03 '13 at 19:48
2

Just to add one more example where passing this is correct and follows good design: Visitor pattern. In Visitor design pattern, method accept(Visitor v) is typically implemented in a way it just calls v.visit(this).

Petr Zelenka
  • 63
  • 1
  • 5
1

Acceptable

Snippet from Oracle JAVA docs:

Within an instance method or a constructor, this is a reference to the current object — the object whose method or constructor is being called. You can refer to any member of the current object from within an instance method or a constructor by using this.

Using this with a Field

The most common reason for using the this keyword is because a field is shadowed by a method or constructor parameter.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Nargis
  • 4,687
  • 1
  • 28
  • 45
  • 2
    "You can refer to **any member of the current object**" -- that does not seem to answer the question "is it acceptable to **pass `this` as a parameter?**". – user Jul 03 '13 at 09:10
  • 2
    This is saying how you can do `this.some_variable` to refer to the class variable instead of to a local variable. It has nothing to do with passing `this` as a parameter. – Jose Salvatierra Jul 03 '13 at 12:27
0

Everything in java is passed by value. But objects are NEVER passed to the method!
When java passes an object to a method, it first makes a copy of a reference to the object, not a copy of the object itself. Hence this is pefectly used method in java. And most commonly followed usage.

blganesh101
  • 3,647
  • 1
  • 24
  • 44
  • 4
    "Everything in java is passed by value." - that's a very misleading initial comment. Actually all objects are passed by reference and all primitive types are passed by value. You've NEVER have a `this` reference to a primitive type, and therefore I think your "more info" is introducing confusion. – Stewart Jul 03 '13 at 11:05
  • 1
    @Stewart: He immediately makes it clear that he doesn't mean that whole objects are copied. – LarsH Jul 03 '13 at 13:34
  • 10
    @Stewart no, objects are _not_ passed by reference, rather _object references_ are passed by value. It's an important distinction - pass by reference would mean that if I have a local variable that refers to an object and pass that variable to another method, the method would be able to change which object my variable refers to, and this is definitely not something you can do in Java. The method _can_ mutate the state of the object through its own copy of the reference but it can't change my copy of the reference to point to something else. – Ian Roberts Jul 03 '13 at 13:54
  • @Ian I've never heard of any other definition of "pass by reference" except what you've just described - ie, a reference (pointer) is the value passed. With regard to this question we can say `Object that = this;` and then `this` and `that` are different references to the same object. Whichever one you pass into a method, inside the method you'd have a 3rd reference to the same object. – Stewart Jul 03 '13 at 16:28
  • 2
    @Stewart http://www.yoda.arachsys.com/csharp/parameters.html is a good article that explains the difference between passing by reference and passing references by value, in the context of C# which supports both. – Ian Roberts Jul 03 '13 at 16:31
  • @LarsH Yes he does, but (a) it's a discussion about the pros and cons of passing around `this` and (b) it makes it sound like passing by reference is the exception, and passing by value is the rule. Perhaps it's just me. – Stewart Jul 03 '13 at 16:33
  • @Ian That's fair enough, but it's not a construct which Java has. I take it that "passing by reference", here, is achieved internally by passing a reference to the reference, ie, it's doubly decoupled, a pointer to a pointer. – Stewart Jul 03 '13 at 16:37