22

Eclipse has an option to warn on assignment to a method's parameter (inside the method), as in:

public void doFoo(int a){
   if (a<0){
      a=0; // this will generate a warning
   }
   // do stuff
}

Normally I try to activate (and heed) almost all available compiler warnings, but in this case I'm not really sure whether it's worth it.

I see legitimate cases for changing a parameter in a method (e.g.: Allowing a parameter to be "unset" (e.g. null) and automatically substituting a default value), but few situations where it would cause problems, except that it might be a bit confusing to reassign a parameter in the middle of the method.

Do you use such warnings? Why / why not?

Note:

Avoiding this warning is of course equivalent to making the method parameter final (only then it's a compiler error :-)). So this question Why should I use the keyword "final" on a method parameter in Java? might be related.

Community
  • 1
  • 1
sleske
  • 81,358
  • 34
  • 189
  • 227
  • 1
    In this case, I'd suggest throwing an exception rather than hiding the error. – Tom Hawtin - tackline Feb 09 '10 at 13:40
  • possible duplicate of [Why should I use the keyword "final" on a method parameter in Java?](http://stackoverflow.com/questions/500508/why-should-i-use-the-keyword-final-on-a-method-parameter-in-java) – nawfal Jul 05 '14 at 15:37
  • http://stackoverflow.com/questions/3972510/the-parameter-foo-should-not-be-assigned-whats-the-harm – Yousha Aleayoub Aug 31 '16 at 09:22

8 Answers8

15

The confusing-part is the reason for the warning. If you reassign a parameter a new value in the method (probably conditional), then it is not clear, what a is. That's why it is seen as good style, to leave method-params unchanged.

Mnementh
  • 50,487
  • 48
  • 148
  • 202
  • I agree that it is quite confusing. In general, if you're passing in a param, you should use that param, not reassign it to something else. – Jeff Storey Feb 09 '10 at 13:43
  • 4
    I don't agree - inputs often need to be sanitized. – danben Feb 09 '10 at 13:52
  • 12
    Sanitize it into a new local variable. – Mnementh Feb 09 '10 at 14:02
  • 8
    @Mnementh, if you create a new local variable for the purpose it can be tricky to pick appropriate names for all the similar variables. – finnw Feb 09 '10 at 14:15
  • 2
    @finnw: That's actually the biggest reason I frequently "break" the rule on this. I'm just not inventive enough. :-) – T.J. Crowder Feb 09 '10 at 15:16
  • 1
    @finnw/Crowder: ...and because of my lack of imagination, I personally am very fond of the semantic/pragmatic Hungarian prefix notation, enabling us to use the same name for object member variables (e.g. the "m_" wart), method parameters and local variables (e.g. "the..."). Not that I've managed to be consistent about it! – Pontus Gagge Feb 09 '10 at 15:46
11

For me, as long as you do it early and clearly, it's fine. As you say, doing it buried deep in four conditionals half-way into a 30-line function is less than ideal.

You also obviously have to be careful when doing this with object references, since calling methods on the object you were given may change its state and communicate information back to the caller, but of course if you've subbed in your own placeholder, that information is not communicated.

The flip side is that declaring a new variable and assigning the argument (or a default if argument needs defaulting) to it may well be clearer, and will almost certainly not be less efficient -- any decent compiler (whether the primary compiler or a JIT) will optimize it out when feasible.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 1
    It is not clear to me how reassigning an object reference, is going to make the object (that you no longer have a reference to) communicate information back to the caller. Could you please explain that to me? – Oscar Gomez Jun 04 '10 at 01:16
  • 2
    @OscarMk: My point was exactly that: It won't. :-) So (say) you receive the argument `obj`, and near the top of the function you assign a new reference to it if a certain condition exists. Near the bottom of the function you call `obj.foo()`. If you've assigned a new reference to `obj`, then obviously the caller's object won't receive the `foo` call, your replacement will -- but it's not obvious looking at the code at the end there that that will happen. – T.J. Crowder Jun 04 '10 at 01:35
9

Reassigning to the method parameter variable is usually a mistake if the parameter is a reference type.

Consider the following code:

MyObject myObject = new myObject();
myObject.Foo = "foo";
doFoo(myObject);

// what's the value of myObject.Foo here?

public void doFoo(MyObject myFoo){   
   myFoo = new MyObject("Bar");
}

Many people will expect that at after the call to doFoo, myObject.Foo will equal "Bar". Of course, it won't - because Java is not pass by reference, but pass by reference value - that is to say, a copy of the reference is passed to the method. Reassigning to that copy only has an effect in the local scope, and not at the callsite. This is one of the most commonly misunderstood concepts.

Winston Smith
  • 21,585
  • 10
  • 60
  • 75
  • 2
    Actually, Java methods are only call-by-value. Nevertheless, I don't think this has much to do with the question. – danben Feb 09 '10 at 13:54
  • @dan I think it's relevant. *Is it problematic to assign a new value to a method parameter?" - yes, it can be, because it may not do what someone expects. – Winston Smith Feb 09 '10 at 14:33
  • 3
    Right, but in this particular case you are referring to someone who does not understand how the language works. Compiler warnings are not going to protect against that. – danben Feb 09 '10 at 15:02
8

Assigning a method parameter is not something most people expect to happen in most methods. Since we read the code with the assumption that parameter values are fixed, an assignment is usually considered poor practice, if only by convention and the principle of least astonishment.

There are always alternatives to assigning method parameters: usually a local temporary copy is just fine. But generally, if you find you need to control the logic of your function through parameter reassignment, it could benefit from refactoring into smaller methods.

Pontus Gagge
  • 17,166
  • 1
  • 38
  • 51
  • 1
    *"Assigning a method parameter is not something most people expect to happen..."* I'll dispute that as a universal statement. In fact, I'd say in *functional* languages and similar (including JavaScript), it's darned near the norm. In my experience, it's less common in Java and C++, and neither common nor uncommon in C. Why that should be I don't know, but it may have something to do with the approaches people take to problem solving in different languages and environments. – T.J. Crowder Feb 09 '10 at 22:22
  • 1
    Nitpicking: in a **functional** language, assignment does not happen, only new bindings, much as imperative languages declare a new temporary variable. Actually, I would suggest that what you describe is **one** of the reasons JavaScript has a poor reputation, even though its design as a prototype based OO language is actually pretty nifty. It was once said of the Amiga that it was much better than its fanboys... – Pontus Gagge Feb 10 '10 at 08:48
  • 1
    The question is tagged Java, not Javascript or a functional language. For the usual imperative languages it is as it is wrote here. – Mnementh Apr 28 '14 at 15:20
2

Different compiler warnings can be appropriate for different situations. Sure, some are applicable to most or all situations, but this does not seem to be one of them.

I would think of this particular warning as the compiler giving you the option to be warned about a method parameter being reassigned when you need it, rather than a rule that method parameters should not be reassigned. Your example constitutes a perfectly valid case for it.

danben
  • 80,905
  • 18
  • 123
  • 145
0

I sometimes use it in situations like these:

void countdown(int n)
{
   for (; n > 0; n--) {
      // do something
   }
}

to avoid introducing a variable i in the for loop. Typically I only use these kind of 'tricks' in very short functions.

Personally I very much dislike 'correcting' parameters inside a function this way. I prefer to catch these by asserts and make sure that the contract is right.

Maurits Rijk
  • 9,789
  • 2
  • 36
  • 53
  • 5
    Sorry, but I think your example is the perfect case *for* this warning. I find it needlessly complicated. E.g., what if the function later grows (as functions always do), and you try to use n to, say print "Iteration out of "? – sleske Feb 09 '10 at 15:11
0

I usually don't need to assign new values to method parameters.

As to best-practices - the warning also avoids confusion when facing code like:

       public void foo() {
           int a = 1;
           bar(a);
           System.out.println(a);
       }

       public void bar(int a) {
           a++;
       }
rflexor
  • 424
  • 1
  • 4
  • 9
0

You shoud write code with no side effect : every method shoud be a function that doesn't change . Otherwise it's a command and it can be dangerous.

See definitions for command and function on the DDD website :

Function : An operation that computes and returns a result without observable side effects.

Command : An operation that effects some change to the system (for example, setting a variable). An operation that intentionally creates a side effect.

Community
  • 1
  • 1
Jean-Philippe Caruana
  • 2,617
  • 4
  • 25
  • 47
  • 3
    @Jean-Philippe: (I don't consider modifying method parameter good practice) The question is not about side effects. Actually changing a primitive parameter in Java as exactly zero side-effect seen that Java is "pass by value". You're introducing the concept of referential transparency and pure functions, which may be entertaining in the functional programming world. But here we're talking about Java and you'll find that in Java a *lot* of Java method actually are not referentially transparent. The original question is not about "setting a variable", it's about modifying a method parameter. – SyntaxT3rr0r Feb 09 '10 at 14:03