1

I have a function in C language which takes 3 matrices as arguments; It performs matrix multiplication of first 2 matrices and stores the result in the 3rd one.

My question is what should I return from the function. Should I return the resultant matrix it self (rather the pointer to it) so that function calls can be chained togather like so :

display_matrix(multiply_matrix(A, B, C));

Or should I return 0 or 1 based on whether the operation was successful or not (incorrect dimensions might return failure)? In this case the line shown above would look something like this.

multiply_matrix(A, B, C);
display_matrix(C);

So, what would be the better way to do it? Or is it just a matter of choice?

3
  • 1
    It'a matter of opinion but I like the idea of returning status of the operation.
    – R Sahu
    May 10, 2017 at 15:35
  • Under what circumstances would matrix multiplication fail? May 10, 2017 at 16:37
  • 3
    Mismatched dimensions as mentioned in the question.
    – Useless
    May 10, 2017 at 16:43

3 Answers 3

9

Since your operation can fail, you need some way to represent this. The chaining design is nice-to-have, but is possible only if you don't need to return anything else instead.

The options are:

  • return success or failure codes

    • con: in this case you obviously can't use the function chaining style
    • con: you also need to pepper your code with tests and error handling
    • con: any operations whose result isn't checked may leave the out-param in an unexpected state
    • pro: if some operations does fail, you know exactly where it happened (assuming you don't copy-paste your error handling boilerplate incorrectly...)

    Your sample code should actually look something like:

    if ((rc=multiply_matrix(A, B, C)) != MAT_OK) {
      display_matrix_error(rc, A, B);
    } else {
      display_matrix(C);
    }
    
  • use some matrix equivalent of NaN to represent failed computations, and just pass them through your function chain silently.

    • pro: in this case you get the nice function chaining style
    • pro: you don't need explicit error-checking everywhere
    • con: you can't tell which step failed if a long chain of computations results in an invalid matrix

    Your sample code really will look like you posted:

    display_matrix(multiply_matrix(A, B, C));
    

    where the display function needs to know how to handle an invalid input.

7

Number of issues here. Let me tease them apart.

First, don't give back your result with both an out parameter and a return. That's just confusing. Pick one.

Second, c has no exception handling. Instead c functions either return errors or they handle/avoid them so that no error escapes. If you choose to return your result then you need a robust way of always returning something meaningful.

Third, if you return your error status and return the result in an out parameter please document this clearly.

0

In C it's not uncommon to return pointers. Returning a null pointer could signify failure. Plus returning a pointer avoids a potentially large amount of data copying.

So you can have both error returns and (maybe somewhat limited, depending on other choices you make) function chaining. (Note your matrix functions would need to accept input parameters as pointers as well).

Function chaining would have to deal with getting a null pointer on input. But this could be treated analogously to NAN values for floating point arithmetic. If a null ptr is passed to display_matrix() then a "Not a Matrix" message would be displayed. If multiply_matrix() received a null, if would return a null.

Finally if you need more diagnostic info than just "it failed", you could use an approach like C's errno which gives a failure reason.

6
  • 1
    Oh god no! Don't imitate the horribly broken errno pattern. May 16, 2017 at 3:27
  • @user1118321 I'm aware of difficulties with errno in a multithreaded environment, and with ambiguities WRT when errno changes, but are you referring to other "brokenness"?
    – Χpẘ
    May 16, 2017 at 4:28
  • 2
    The entire concept of an error stored at a static location that you have to know to check (and sometimes set, apparently) is extremely problematic. It's not just ambiguities of when to check it, but about not having any way to know that it even exists. When a function returns a value, it's easy to see that you have to check it just from looking at the function prototype. But when it sets a hidden variable at a magical location, you don't even know to check it, let alone when, you're pretty much guaranteeing failure for the user of that function. May 16, 2017 at 4:39
  • I disagree on some points. errno doesn't have to be a static location, it can be macro that evaluates to any number of things, including a thread local variable. I don't consider it magical, because all the C libraries I've seen that use it, document it's use. When a function returns a value, you can't unambiguously tell from prototype that it can signify an error. You must look at documentation. There is a great body of evidence that suggests success with its use. Also, it's a common pattern in hardware architecture: Machine Check Architecture for x64, AER for PCIe, APEI for ACPI, etc
    – Χpẘ
    May 17, 2017 at 17:26
  • @Χpẘ when a function returns a value of type struct { ErrorType error; TypeYouWant value; }, it's unambiguously an error signal. Some other symbol errno is magical because it does not form part of the function signature. It is popular in hardware because it lacks the abstractive power to have a better error handling channel
    – Caleth
    Aug 21, 2017 at 15:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.