Hacker News new | past | comments | ask | show | jobs | submit login

Is using out for returning multiple values bad? Tuples seem the only good alternative, and those have only just been introduced.



It's not so much the multiple return as it is losing track of what and where state is being changed. The most common one I see is "populateList(ref myList)", from the callers side you have no idea if a new list is being created or just appended to, you don't know if the list has to be initialized or not, etc. Returning a new list and having the caller specify the assignment is much better.

Just yesterday I fixed a threading bug caused by some semantics around passing by reference and locking.


Without tuples, your best option is to create a class or struct that is used only as the return type for that method.


Yes, it leads to lots of bad procedural code. If you need multiple data items returned from something, they are clearly related and belong in an object. Well written code doesn't use out parameters at all, they are a bad feature and should be removed from the language.


If it's natural for a mathematical function to return a tuple, it should return a tuple; things being objects for the sake of it doesn't constitute an argument. For example: coordinates, swap function, a list partitioning function (returning two lists partitioned based on an element), etc.


A tuple is an object; it's a perfectly proper way to return multiple values from a function, out parameters are not. In fact I'm unsure what your comment has to do at all with anything I said, I'm discussing out parameters and why I don't like them and why it's better to return and object and then you say no return a tuple, which is an object, an instance of the class Tuple. You seem to be trying to disagree with my statement but you've actually supported my point.


Only an object-oriented programmer will say that a tuple is an object. A relational programmer or someone using a logic programming language wouldn't say the same thing.

A tuple doesn't have behaviour, inheritance, encapsulation, or data hiding. Tuples are language-agnostic.

An OO language has little choice but to represent tuples as objects, but to say that tuples are objects is no more true than saying that a user's account is an object, a TCP connection is an object, or a window on screen is an object - it mistakes representation for referent, it confuses the map with the territory.


A tuple is an instance of the class Tuple, an object by definition. It doesn't matter what a relational or logic programmer would prefer to call it, instances of classes are objects. I can add any behavior I like to those instances via extensions. Your tuple might not have any behavior, you might think of it as pure data, but that's a limitation of your view of things, not the reality. The language provides the ability to extend any class, your reality tunnel isn't the same as others.

> ut to say that tuples are objects is no more true than saying that a user's account is an object, a TCP connection is an object, or a window on screen is an object - it mistakes representation for referent, it confuses the map with the territory.

No, it makes the map useful to navigate the territory by accepting the abstraction of objects as a useful thing; there's a reason to say "everything is an object", it's a powerful ability. I'm a Smalltalk'er, everything literally is an object with methods even if/while/for/foreach statements are modeled with objects.

That you find it confusing or meaningless doesn't matter to me, it's my reality tunnel and it works well.


> That you find it confusing or meaningless doesn't matter to me, it's my reality tunnel and it works well.

This conversation, such that it is, is over: simultaneously insulting your co-conversant while explicitly and resolutely staying within your own perspective means there will be no communication, by your will. Good luck with that.


> Well written code doesn't use out parameters at all

What do you think of the Try pattern, i.e.:

  Result res;
  if (TryThing(out res)) {
  	// Do stuff, use res
  )
I always thought that was a good use for out, and C# itself uses it for TryGetValue in Dictionaries for instance.


I prefer higher order functional programming, TryGetValue looks ugly to me, I'd rather do...

    dictionary.WithValue(aKey, value => DoStuffWith(value));
The dictionary knows whether it has a value or not, I shouldn't be making decisions with if's about a dictionaries data when I can just hand some code to the dictionary and let it do the right thing.

Your other example.

     if (TryThing(out res)) {
  	// Do stuff, use res
     }
I'd rather a simple extension to Object enabling this on any value including null...

    TryThing().IfPresent(thing => thing.DoStuff());
I'm an old Smalltalk'er, we're accustomed to building such control structures into the class library rather than trying to use an if statement for everything. Once you have a clean syntax for lambdas you have the ability to create a better experience than constantly writing procedural code using the common if/while/for/foreach constructs. In Smalltalk we'd do something like...

   dictionary at: aKey ifPresent: [:value | value doStuff ]
That's much better than asking if the key exists with an if, or accessing the dic at a key and doing a null check with an if statement on the value.


Your suggestions require a continuation to handle the "else" part of the branch. In C# that would look significantly worse than the Try* pattern.


That's a matter of opinion, nothing looks worse to me than those out parameters and there's always a way to do things in a cleaner more expressive way than that ugliness. I find many Smalltalk idioms look and work just fine in C# and greatly reduce the amount of code I need to write.

C# still lacks quite a lot in comparison to Smalltalk, but it's slowly getting there year by year.


> Wht do you think of the Try pattern

I'd call it a valuable exception to the rule.


This would be a great place for Maybe<Result>


the purpose of try get was also to avoid boxing of value types


I didn't know that.

Couldn't the generic parameter of Some<T> be a nonboxed value type, though? Some<T> could even be a struct, to avoid object allocation.

Edit: although that would get boxed so it could fit in a Maybe<T>, so yeah, I see what you're saying!


It's been years and years since I used C# but at the time, ref and out parameters were critical for pinvoke, since pointer arguments are how Win32 functions generally return results.


Oh I'm sure there are valid reasons at the edge to use them, they just make for bad C# code when it's code using entirely the framework; they're overused, usually by programmers who never learned the functional or OO styles and are stuck in the procedural mindset.


The Visual Studio WCF/SOAP generators still generate code that uses out parameters - it's pretty much the only place I come across them, these days.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: