www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Flagging special conditions on return from a function call

reply Denis <noreply noserver.lan> writes:
Is there a preferred idiom in D for flagging special conditions 
when returning from a function call? Here "special conditions" 
refers to expected situations (e.g. reaching the end of 
something, like EOF) rather than outright errors (so 
exception-try-catch is inappropriate).

I've come across many ways for a function to return both a value 
and flag, including:

(1) Assign an unused value for the flag (e.g. -1 when the 
function returns an int), and return the combined value/flag.
(2) Return a tuple with the value and the flag
(3) Return a struct or tuple with named value and flag members
(4) Set the function return value normally, and put the flag in 
an "out" variable passed as an argument to the function
(5) Return the flag, and put the value in an "out" variable 

(6) Use two separate functions, one that returns the value, and 
another that can be called afterwards to check the flag (like 
eof(), for example)
(7) Use a side effect and set a designated global variable

I'm sure there are others.

* Is there a preferred approach?
* Which ones are discouraged?
* General recommendations or guidelines?

If there is a best practice, I'd rather learn it sooner than many 
lines of code later.

(In the interest of brevity, I'll limit my own comments in this 
post to the following: In the past, I've tried to adhere to KISS. 

possible to combine the value and flag that way, in which case 
one of the other methods must be used.)
Jun 22 2020
parent reply Simen =?UTF-8?B?S2rDpnLDpXM=?= <simen.kjaras gmail.com> writes:
On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:
 (1) Assign an unused value for the flag (e.g. -1 when the 
 function returns an int), and return the combined value/flag.
This happens in some Phobos algorithms, and might be the most common on this list.
 (2) Return a tuple with the value and the flag
 (3) Return a struct or tuple with named value and flag members
Would certainly work, but I don't think it's common in D.
 (4) Set the function return value normally, and put the flag in 
 an "out" variable passed as an argument to the function
 (5) Return the flag, and put the value in an "out" variable 

these are probably the most common way (except for exceptions) to signal these cases.
 (6) Use two separate functions, one that returns the value, and 
 another that can be called afterwards to check the flag (like 
 eof(), for example)
 (7) Use a side effect and set a designated global variable
Global variables are frowned upon, so probably not this. :p One thing I feel is missing here (perhaps because std.variant.Algebraic is egregious): (8) Return a Maybe!T or Algebraic!(T, ErrorCode) It's what I personally would prefer, but I have only rarely seen it in D code. Given a properly written Maybe, this could enforce proper handling of the error case, either by throwing on trying to get at Maybe!T.getValue when it's holding None, or by presenting an interface that only compiles when both cases are covered, like fun().match((T t) => t, () => Error()). -- Simen
Jun 22 2020
parent reply Denis <noreply noserver.lan> writes:
Perhaps this thread would have been better titled "Returning a 
value and a status", and the question phrased as "What are your 
preferred techniques?".

I'm planning to port some of my programs to D, so I'd like to 
standardize on one or two techniques for handling this very 
common situation, in a way that suits the language. I'd 
appreciate hearing from others about what you do.

---

On Tuesday, 23 June 2020 at 06:52:29 UTC, Simen Kjærås wrote:
 On Tuesday, 23 June 2020 at 04:01:45 UTC, Denis wrote:
[...]
 (4) Set the function return value normally, and put the flag 
 in an "out" variable passed as an argument to the function
 (5) Return the flag, and put the value in an "out" variable 

these are probably the most common way (except for exceptions) to signal these cases.
Good to know. Both of these techniques (or something similar) are used in Perl too. The choice seemed to depend on which one the author thought would be more useful as the return. [...]
 by presenting an interface that only compiles when both cases 
 are covered, like fun().match((T t) => t, () => Error()).
A complete solution wrapped in a tidy package -- I like it. Thanks for sharing.
Jun 23 2020
parent reply Paul Backus <snarwin gmail.com> writes:
On Tuesday, 23 June 2020 at 16:14:20 UTC, Denis wrote:
 by presenting an interface that only compiles when both cases 
 are covered, like fun().match((T t) => t, () => Error()).
A complete solution wrapped in a tidy package -- I like it. Thanks for sharing.
If you're open to using Dub packages, I'd recommend sumtype [1] as an alternative to the standard-library Algebraic. It has much better compatibility with things like function attributes ( safe, nothrow, etc), mutability qualifiers, CTFE, and betterC, and also produces substantially more efficient code [2]. [1] https://code.dlang.org/packages/sumtype [2] https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html
Jun 23 2020
parent Denis <noreply noserver.lan> writes:
On Tuesday, 23 June 2020 at 21:34:25 UTC, Paul Backus wrote:

 If you're open to using Dub packages [...]
Because this is going to be used in almost every program I write, I need to eliminate outside dependencies as an option. Nonetheless, thanks for this suggestion.
 [2] 
 https://pbackus.github.io/blog/beating-stdvisit-without-really-trying.html
I did read your blog post: that's an impressive result. Good to know that well-written D code can be competitive with C. Denis
Jun 23 2020