1. 32
    1. 4

      Absolutely wonderful article!

      The only nit I will pick is that the idiomatic C code for something where we care about failure is something like:

      error_t x(int *y, size_t n, int z, size_t* indexOut) {
        /* implementation elided */
      }
      

      Thus, we separate the error from the data returned. I think the overall points they make still stand, though.

      1. 3

        Thanks for the kind words.

        I’ve been out of the loop with C for a while. I’ll update the article! Is this a recent(ish) trend? I was aware some standard library functions use the -1 convention.

        1. 6

          I won’t presume to know how widespread it is, but it’s done exactly to fix the cases where a sentinel value is still theoretically within the range of the data.

          I dislike returning -1, for example, because if doing pointer arithmetic or something like that one can still mistakenly do math without the compiler complaining. An explicit error value and type being returned cannot be abused as readily, at least by accident.

          I especially dislike sentinel values in the case of, say, dedicated routines for handling integer operations and catching overflows and underflows–those are cases where, for example, (-1) might conceivably show up during normal use.

          In the case of finding indices of something, the index type should be size_t, because (somehow) max int there could still be a valid index. It’s paranoid, but it is what it is.

    2. 3

      How does Rust stack up here? I’d like to see it in the comparison.

      Otherwise, great job!