6

I happened to create a mutable class like this:

class Mutable<T> {
    private T value;
    public Mutable() { this.value = null; }
    public Mutable(T value) { this.value = value; }
    T get() { return this.value; }
    void set(T value) { this.value = value; }
}

And then it's often used in a method like this:

boolean operation(String input, Mutable<Set<String>> dataOut) throws ... {
    boolean result;
    try {
         String data = doSomething(input);
         result = validate(data);
         if (result && dataOut != null) {
             List<String> values = Arrays.asList(data.split(", "));
             Collections.sort(values);
             dataOut.set(new LinkedHashSet<String>(values));
         }
    } catch(SpecificIgnorableException ex) {
         result = false;
         logger.debug(ex);
    }
    return result;
}

...which is just an example, could be any use case, where one would use ref or out parameters in C#, or non-const reference parameters in C++, or pointers to output parameters in C.

First, same could be done by using an array (with one element) instead of above custom type. Does it make sense to have this custom type which clearly states mutable, instead of using an implicitly mutable array?

Second, is this pattern bad and code smell in Java? Let's limit to cases where using out parameter would make sense in C#. Should every instance of this kind of Java code be replaced? With what?

hyde
  • 3,744
  • 4
  • 25
  • 35
  • in your example returning null or rethrowing the Exception (wrapped or not) up the stack to handle it there instead of a boolean success return value (which have been deprecated since exceptions) – ratchet freak Mar 28 '13 at 16:31
  • @ratchetfreak Exceptions are fairly heavy, and do not fit every situation. A good sign of return value being better is, if most code would have empty catch block (which gets replaced by non-existent `else` when return value is used instead). Opposite of success is not always failure. Changed code to imply logging only as debug measure. – hyde Mar 28 '13 at 16:36
  • 3
    ugh don't diss things just because they are "heavy", for most applications something "heavy" but easy to use is better than a "light" custom awkward construct, also no-one is forcing you to use the checked exception classes, when failure is a common result though a null return value is enough to signal an error – ratchet freak Mar 28 '13 at 16:49
  • In this particular example I'd have the method return the Set, with null (or perhaps empty) meaning false. – user949300 Dec 21 '13 at 20:13
  • @user949300 certainly possible, but how is that different from returning an array? – hyde Dec 21 '13 at 22:33
  • 2
    FWIW, I wouldn't make a `Mutable` when there's an existing `Holder` available with your Java distribution. (It's used for modelling _out_ parameters in JAX-WS; surprise surprise…) – Donal Fellows Dec 22 '13 at 15:50
  • An alternative seems to be [commons-lang's `MutableObject`](http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/mutable/MutableObject.html). If you're already using that library, this may convey your intent better than `Holder` does (using something from `javax.xml.ws` may seem odd). Also comes with a [bunch of non-boxing siblings like `MutableDouble`](https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/mutable/package-summary.html) – bacar Aug 11 '14 at 17:38

4 Answers4

13

The real question is "are functions with side-effects bad?"

Providing a reference to an explicit mutable ("out") variable is no different than providing a Map that you modify, or referencing a global variable from within the function. In all three cases, the function is permitted to modify something in a way that is hard to reason about. Consider, for example, a function that modifies the "out" parameter, then throws.

The counter-argument is that this is no different from a method call that modifies an object's private state and then throws.

Personally, if I'm writing a method that is focused on a "result", I would prefer creating a new class to hold it; classes are cheap in Java. If I'm writing a method that modifies an object's internal state, I generally don't return anything from the method.

parsifal
  • 483
  • 3
  • 5
  • 4
    C# has an idiom called `TryParse`. It relies on an `out` parameter to get the parsed value, and returns a boolean indicating success or failure. It's the only time I really use `out`; making a class just for a return value seems a bit pointless, unless you use it everywhere where you need a number and a success indicator. I suppose you could simply return a `Tuple`. – Robert Harvey Mar 28 '13 at 16:51
  • 2
    I would rather create a class than try to figure out what 'tuple.Item1' represents. – jhewlett Mar 29 '13 at 05:59
  • I think this is what I find clear yet simple about "out" parameters: they have a name, without requiring creation of a new type. And I think creation of extra type is clutter if it is only used as return type of single method, and does not have any custom behaviour (ie. methods other than setters and getters). – hyde Mar 29 '13 at 11:44
  • Plus one because the new return Type is going to be unit testable. And the method is future proof since changes to the structure of returned data are encapsulated by the Type – carbontax Dec 22 '13 at 17:27
4

First of all out and ref have nothing to do with each other. An out parameter in C# is just the only way the language has of returning multiple values from a function, short of creating a new type to use as the return value. Just because it's in the parameter list is only a syntax thing. There's no equivalent in Java.

I think what you've got there is a code smell because it's not really idiomatic Java. In your situation, I would just define a new class to use as a result value.

Scott Whitlock
  • 21,874
  • 5
  • 60
  • 88
  • I think out and ref have nothing to do with each other is a bit of a stretch, second para I'd agree with though – jk. Mar 28 '13 at 17:08
  • @jk - well, if you use a `ref` you're saying that the function is both reading and modifying that value, but if you're using an `out` then it's strictly an output, no different than if you'd used it on the left hand side of an assignment. – Scott Whitlock Mar 28 '13 at 18:00
  • I'd say C# out parameters are just syntactic sugar on top of ref parameters (not sure if there is bytecode level difference), so very similar from one point of view. A great feature to be sure, making a common use case of reference parameters distinct, self-documenting and compiler-enforceable. – hyde Mar 29 '13 at 11:51
  • 1
    @hyde: implentation-wise, you are correct, conceptually, you are incorrect. Conceptually, out parameters are simply an implementation of multiple return values. Consider F#'s TryParse: `let parsed, parsedValue = int.TryParse(input);`. Now, the declaration of tryparse still includes the byref, but that is really just implementation leaking into the language. They could have called it something else. Or they could have done it like perl where an array is returned and unpacked (parsed, parsedValue) = TryParse(input). – jmoreno Dec 21 '13 at 19:32
  • 1
    +1 There are in fact languages that allow for more than one return value. In languages that do not support this, you have to use ref/var/out, or return a struct/class containing the possible multiple values. – JensG Dec 21 '13 at 22:31
1

First of all, I don't think the get/set methods for the Mutable<T> accomplish much versus simply using an exposed field. If a class will have any behavior, using get/set methods will allow the class much more flexibility in how it implements that behavior, but your Mutable<T> has no behavior.

Secondly, while generics are nice, they do cannot handle most primitives efficiently in Java. You may thus need a MutableInt, MutableDouble, etc. in addition to the generic mutable [use of the generic form for Boolean may be okay, since there are only two possible Boolean values and both are cached].

Thirdly, calling a method which returns data in such fashion is somewhat awkward because it requires the caller to create a new object to accept the return data.

Given those constraints, however, I would posit that there are nonetheless cases where giving the caller an object it can mutate is nonetheless the right approach. If an object wants to provide a means of asking its location, having a method which return Point will have an inherent ambiguity as to whether the returned object is "attached" to the object's position and also whether it will remain so. By contrast, a method which accepts a Point from the caller and updates its coordinates to match the object's position implies no such ambiguity, since there would be no plausible reason for a point which was independent of the object's position not to remain so.

supercat
  • 8,335
  • 22
  • 28
1

Generally, this kind of pattern should be avoided because its usability. It is not so obvious how to call it correctly, comparing to simple single return value function.

However, it has its own merit performance-wise for returning value of primitive types or an instance that already exists, especially in Java where you cannot return struct and returning new instance of an object every time might not be an option for tight loop. Let's compare it to .Net C# Dictionary<T,U>'s TryGetValue method:

public bool TryGetValue(
    TKey key,
    out TValue value
)

It is the same pattern as yours, and it is there for performance reason because without this method the code must be

if (dictionary.ContainsKey(key)) {
    int value = dictionary[key];
}

Which is slower because same lookup will occur twice (let alone multithreading for now). However, using ContainsKey is more clear in this case and most coders will use it for trivial lookup rather than using TryGetValue.

So the bottom line is, it depends on how would you use it. From your code, the overhead of return value initiation seems to outweigh the performance benefit of the pattern already. However, you might want to provide this function to leave the room for some optimisation later.

tia
  • 965
  • 5
  • 9