Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle an api which returns different data types for the same input data types?

How to handle an api which returns different data types for the same input data types?

Looking at the below example, apicall should return a date or a string depending on the input attribute:

#include <iostream>
#include <string>

using namespace std;

???? apicall(string datatype, string attribute)
{
    // code
}

int main(int argc, char** argv)
{
    string datatype = "Thomas"
    string attribute = "bithday"
    cout << apicall(datatype, attribute) << endl;

    string datatype = "Thomas"
    string attribute = "address"
    cout << apicall(datatype, attribute) << endl;
}

What could be in place of ???? (apicall return datatype) and how to handle these cases?

I am trying to understand these concepts as my experience to date has been with duck typed scripting languages.

like image 566
Greg Avatar asked Dec 04 '22 21:12

Greg


2 Answers

The ideal solution is to use a std::variant, which is a safe union type like.

This allows you to write the following:

using DateOrString = std::variant<DateType, std::string>;

DateOrString api_call(std::string, std::string) {
   // you can return both DateType and std::string
}

// ...
auto result = api_call("", "");
auto& str = std::get<std::string>(result);

Unfortunately std::variant is a C++17 feature. However different compilers already support it.

As already has been suggested, boost has a variant class and you can use it with any C++ standard.


As last option, you may implement a "variant-like" class which handles both a date and a string. Your function should return it.

Here a demo how to quickly implement that kind of class.

Note that that class is safe because the type is checked at runtime.

As a variant object, your callee function should branch on the type, something like:

auto result = api_call(/*...*/);
if (result.is_string()) {
   // result is a string
   const auto& str = result.get_string();
} else {
   // result is a date
   const auto& date = result.get_date();
}
like image 97
BiagioF Avatar answered Apr 10 '23 11:04

BiagioF


... returns different data types for the same input data types?

This is literally impossible. A function is defined with one (or zero) return types, and zero or more input parameter types.

The workarounds are:

  1. Write a single function returning a variant type, such as std::variant in C++17, or Boost.Variant if that's not available.
  2. Write multiple functions with different return types (the caller just has to choose the right one)
  3. Invert control, so that instead of returning a value, you pass an object capable of processing all the required types:

    struct APIHandler {
      virtual ~APIHandler() {}
      virtual void operator()(int) {}
      virtual void operator()(string) {}
    };
    void apicall(string name, string attr, APIHandler &h) {
      // dummy implementation
      if (attr == "address") {
        h("123 Woodford Road");
      } else if (attr == "birthday") {
        h(19830214);
      }
    }
    
    // implement your type-specific logic here
    struct MyHandler: APIHandler {
      void operator()(int i) override {
        cout << "got an int:" << i << '\n';
      }
      void operator()(string s) override {
        cout << "got a string:" << s << '\n';
      }
    };
    
    // and use it like:
    MyHandler mh;
    apicall("Thomas", "birthday", mh);
    apicall("Thomas", "address", mh);
    
like image 38
Useless Avatar answered Apr 10 '23 11:04

Useless