(bool success, string errormessage, foo addedItem)
as a return type. A big step up from Tuple<bool, string, foo>!
instead of "bool TryGetSomething(int param, out MyType outvar)", I rather prefer (bool, MyType) TryGetSomething(int param)
Past that, the best tool in an OO language for returning multiple different values is to return a named class created for the task.
It ends up being more readable. Safer, too, since, unlike for tuples, you can refuse to give up a result when the operation failed. It's also more ergonomic to use, since you can make it mappable. That way you can chain together a bunch of things that might fail, and pass along any errors, without having to stick a bunch of extra if-statements into your code.
TValue? TryGetValue<TKey, TValue>(TKey key)
and have it work with any possible TKey. Unless they've fixed this in the past couple years, you get stuck writing your own option type to be able to also work with reference types, which is always fun to try and get past code review, or you fall back on the out parameters idiom, which is not composable.Unnecessary because class types already allow null. I would not be surprised if a method e.g. public Customer TryFindCustomer(int id); returns null if it can't find the customer.
Of course, if you want to return either a customer or an error details, then you need another type or generic wrapper.
I've never liked to see much use of Either because it has the same readability issues as tuples.
if(TryGetSomething(3, out MyType outvar)) { ... }Also, for your example,
Option<MyType> tryGetSomething(int param) is probably better than either.
if (TryGetSomething(int param, out var value)) {
// use it here
}
If you returned a tuple you'd have to destructure both variables, and have a separate line for the if and the declaration.Any query beyond the most trivial has a schema that depends on the query, and does not map to any entity other than the types of the expressions in the select clause. Tuples, combined with a nice API (I'm more familiar with jOOQ than LINQ these days, but it should apply to LINQ too) mean you preserve type safety when working with your query results.
Specifically you're making a ton of Dtos or similar objects just to bundle values together and transfer them between layers. You can use anonymous objects, but then the return type is simply "object", which isn't descriptive enough. Plus anonymous objects are flagged to not cross assembly boundaries without wild hacks.
Tuples work in situations where you'd otherwise use a small Dto, which is then combined with a larger Dto further up the food chain. And since it is self-descriptive you're not losing much clarity over the small Dto.