4

I've been mainly programming PHP, and I recently started with C++.

In PHP the return of a function can be of any type, so you can do checks like this:

public function doSomething()
{
    if (! this->userHasAttribute()) {
        return false;
    }
    return "you are logged in.";
}

So basically, if the user would not be logged in doSomething would return false, else it returns a string.

Since in C++ you return strictly one datatype, how would you approach this?

How to structure those checks/policies, because clearly you dont want to have them inside a function itself (or you will be throwing exceptions everywhere you do a minor check).

Please correct me if I said anything incorrect.


I also came across this post, talking about why the Single Entry Single Exit notion exists in the first place. Someone said that the strongest argument in favor or SESE has vanished.

https://softwareengineering.stackexchange.com/a/118717/269571

  • 3
    Even if you can do this in PHP it would be a bad habit. A function should do one thing, in this case check if the login was a success and then return either true or false (and have a proper name that tells what it's doing). Returning a message here is bad for many reasons (eg what do you do if you need internationalization?). The calling function (most likely a controller in MVC) can then take the result and decide what to do (possibly calling another function). So maybe either redirect back to login page. Anything display related like showing a text should go into the view component. – thorsten müller Apr 14 '17 at 6:33
  • @thorstenmüller yeah exactly, but how would you structure those checks in your application? What object, or objects, should perform checks before a particular function is called – Melvin Koopmans Apr 14 '17 at 6:37
  • Sorry, never used C++ for web development. Anyway, a rough outline: The controller would be the main object created first. The controller gets the login & password passed. It creates an object (passing on the params to the constructor) 'login' (residing in the models section) which also holds your return function. Then depending on results decides to redirect or create a view object. If you don't redirect you have different options, either have different views for success/failure or a single class that gets success/failure as param (or the login object itself) so it can decide what to display. – thorsten müller Apr 14 '17 at 6:49
  • 2
    Possible duplicate of Style for control flow with validation checks – gnat Apr 14 '17 at 6:58
  • 3
    While both of the answers provide a working solution in no way to they provide a solution with current good practices - that is separation of concerns. If good code is what you are after do as @thorstenmüller suggests, have a function A to check whether a user has been logged in and another function using the result of the function A and based on the return value rendering a specific text. Just so you know, the sample code you provided is one of the reasons why people grew to hate PHP, because API of functions was unpredictable and they could return pretty much anything. – Andy Apr 14 '17 at 12:08
4

One way of achieving this in C++ is via std::optional (upcomming in C++17) or boost::optional (external library).

It can wrap any type and basically allows you to check if a value has been set or not.

#include <iostream>
#include <optional>
#include <string>

std::optional<std::string> doSomething()
{
    if (! userHasAttribute()) {
        return {};
    }
    return "you are logged in.";
}

int main()
{
    auto result = doSomething();
    if (result)
    {
        std::cout << *result;  
    }
}
0

You can return more than one result & result type in C & C++ but you need to do it differently, you have a couple of options:

  1. Return an enumerate type with one entry for each possible result and have a separate decode/log function that gives the text of the appropriate message. Important to remember - your decoder/log must be able to handle invalid values. One nice way of doing this in C++ is to create a type/class that has the values as an enumerate but has it's own decoder or output method that looks up the text to output.

  2. Pass into the function one, or more, pointers that allow the function to pass supplementary information back. In your example above you would return a bool for success or failure but also use a string pointer passed into the call to pass back, as opposed to return, a text message of why that was the result. Important things to remember in this case:

    • Possible Null pointers as inputs - need to check for them!
    • All paths though the code should set both the return value and the message.
    • Possible string overflows if you write a string to a location & possible memory leaks if you pass back a pointer to a dynamically created value.
    • Any pointers that are passed in should be marked static if not intended to be written to.
    • Clear comments & documentation of what such pointers are, must point to, etc. /* Note that the following is very rough and does not have the checks for null pointers, etc. DO NOT USE FOR PRODUCTION CODE you may also need to play about with where the const goes.*/ public function doSomething(const char** Message // pointer to where to pu an Output message to supplement the result ) { bool result = FALSE; if (! this->userHasAttribute()) { *Message = "You are not logged in"; } else { *Message = "you are logged in."; result = TRUE; } return result; }
  3. You can modify class members to provide more detailed results or even, (horrid don't do it), global variables.
  4. You can also do nasty things like always returning a string then parsing the string for specific content, e.g. does the returned value start with "OK", or even nastier, (but I have seen it done), pass back a null terminated string with the result value after the 0x00 I do not recommend either of these options!
  • Could you give a coding example to illustrate what you're saying? – Melvin Koopmans Apr 14 '17 at 6:44
  • The third options seems very gross haha I dont plan on doing that 😅 – Melvin Koopmans Apr 14 '17 at 6:45
  • @MelvinKoopmans: The 3rd example is intended as an example of what not to do! But I have seen it lots of times unfortunately. – Steve Barnes Apr 14 '17 at 6:49
  • 1
    I have seen some APIs that write error codes to a separate field that one is supposed to read by calling another function, often called GetLastError. I wonder how it wages against returning the string, because it is cheaper and less error prone than allocating and parsing the string but it is easier to ignore. – Theraot Apr 14 '17 at 7:07
  • 1
    In C++, most of the drawbacks to suggestion #2 can be avoided by using references instead of pointers, and std::string instead of const char*. I.e.: bool doSomething(std::string& out_message). That way you won't have any null pointers or leaks. For types that are not default constructible, a reference to an unique pointer clearly transfers ownership of the out-param value to the caller, e.g. bool doSomething(std::unique_ptr<std::string>& out_message) though now the caller has to do null-checks again. May I edit your answer accordingly? – amon Apr 14 '17 at 11:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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