‘Stupid’ Question 17: Is use of Tuple, Anonymous Type and/or Out parameters a code smell?
This will spark quite a debate (I hope)! Continuing on the code smell subject I actually would like to challenge some opinions in regards to Tuple, Anonymous Type and out parameters in C#. These three have in common that they allow you to return multiple values from a function, but in three different ways. When I asked the Tuple question many argued that Anonymous Types would be better since they let you set meaningful names on the ‘properties’, while many argued that Tuple was a blessing since they could replace out parameters. I kind of don’t like using any of them, although I have to admit that I have been using Anonymous types, for private functions within a class mainly- why? I don’t know – it felt right as long as I kept them in the sandbox. But I want to know, are these considered code smells?
Is use of Tuple, Anonymous Type and/or Out parameters a code smell?
I’ve spent three days asking other developers and searching the internet for a good answer, and it probably doesn’t come as a surprise if I say that it depends? The majority of the senior developers I have asked have answered that:
- Out in TryParse is okay, but use it only when needed. Extensive use might indicate that the method is doing too much,- and therefore violating the single responsibility principle.
- Out is often overused, and has only a few specific scenarios were it has value
- Tuple seemed to be the least popular one, as it didn’t allow meaningful names (not semantic) and is bulky once you get beyond 8 elements
- Anonymous types are similar to Tuples but allow you to set descriptive names, and they do seem to be more accepted than extensive use of out parameters or Tuples.
- In short- the impression I got was that in most cases (99% as one developer put it) none of the above alternatives should be used since methods should be kept small and have a single responsibility (“Why would you want to return several values?”) - And it COULD indicate a lazy programmer, or an inexperienced one.
- Some suggested that it could be okay, if the they are used in private functions, and some developers did not see any problem in using them at all (“Creating a class seems overkill if you aren’t going to use it in several places”).
My conclusion: I’ll probably think through more before I use anonymous types, I haven’t used out much and haven’t used Tuples at all,- and I don’t see a reason to introduce them in my code right now. As for making a general statement about code smell – I think they MIGHT indicate a code smell and I am skeptical to use any of them, at least extensively. But, I would love to hear some more opinions on this,- and I know that you have one!
Thank you again for all of you that take a part in my daily questions, on the blog, twitter or work/private. I learn so much more from these talks and comments that I would ever be able to learn from books or courses. Please share comments here so others can learn too! Share your wisdom :D
Comments
Out is definitely a code smell, it's a good indicator that the method isn't side-effect free.
One important feature of Tuple and anonymous types is that that implement all the equality-stuff; Equals, GetHashCode. Tuple also implement IComparable (not sure if anonymous types do that). That can be very important if you use Linq. So if you ie want a multi-valued key for a Dictionary, Tuple is the way to go.
One reason that we started avoiding out parameters is that once you start using async (Task) methods, out is forbidden by the API. As moving toward using async methods seems to be a good thing for performance reasons in a number of cases, it seems that avoiding any API decisions that prevent the easier adoption of the async is a good thing.
I don't use tuple ever, rarely use the out keyword and use anonymous types often. In the example of returning co-ordinates; this may be ok for the person writing the code but how would anybody else consuming this code be able to make sense of the data? if it were me I would create a class to hold the information with meaningful properties, which ok takes a little longer to develop but is easier to read and understand by other developers. A good coding habit to adopt is to write code that is descriptive and easy to read and understand. Method names, property names, variable names - it all matters! it's better to have descriptive names than to have a 200 word summay in comments, which will never be maintained. As for anonymous types they are great to use but avoid them as a return type and don't expose them through the interface, generally other consumers won't understand the structure of the object and will have to read into the implementation to figure out how to use it etc. They do have their uses though, especially with LINQ and returning new types using the Select extension method. In alot of cases I see the var keyword and anonymous types mis-used in favour of lazy programming. Just because something works does it mean it's implemented the "right way"!. This is my opinion anyway.
Now, are we talking about the use of these in general, or as return types? "out" can only be used to return a value. I'd say one out parameter is ignoreable. Two or more would make me investigate the method. On the other hand, anonymous types CANNOT be used as a return value. I wouldn't consider it a code-smell, since I've rarely if ever seen one abused. I imagine they could be abused, but it would have to be near 50% of the time before it rises to the level of "code smell" Tuples are harder to categorize. They aren't like "out" parameters where any use is iffy, and it's just a matter of degree. Sometimes Tuples are perfect appropriate, others they're being abused. I'd case I'd have to phrase it as "If the code is hard to read/understand because of the use of a tuple, that's a code-smell"
Mattias: But a computed coordinate should have an "X" and a "Y", and should be used as both input and output to many method. In which case, it should have it's own class. Brad: We can debate whether or not "out" is a code-smell (see my previous comment), but I can see no connection between using an "out" parameter and having side-effects. TryParse() is the most famous "out" user and it has no side-effects. (and the most famous method WITH side-effects, Console.Write() has not "out" parameters)
Even for things like T.TryParse(...), an out parameter is not really needed. The .NET team could easily have introduced something like ParseResult, an immutable struct that has a boolean indicating success/failure, and something of type T to indicate the parsed value. Of course the out overload would have to remain to support pre-generic code.
@Eric: But then you couldn't use it in an if() statement. So, instead of Int x; if (Int32.TryParse(str, out x)) .... we'd have var result = Int32.TryParse(str); if (result.Success) .... on the whole, it's pretty much a wash.
I think debates like these have merit but should be kept in context. There are situations where these languages constructs are useful, but there should be a clear justification in their use. If they are sprinkled everywhere throughout your code, then there is a definite problem.
I steer clear of tuples in C# because the language support for them is horrible compared to the elegant way they are done in languages like Python. Would be lovely to be able to write something like: var (success,result) = int.TryParse("Hello World") I tend to use lightweight classes instead. Automatic properties has at least made the definitions of those classes more concise.
Last modified on 2012-08-07