Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Returning object of a component client from another component action fails #2420

Closed
hkaiser opened this issue Dec 5, 2016 · 3 comments
Closed

Comments

@hkaiser
Copy link
Member

hkaiser commented Dec 5, 2016

I am trying to return an object of a component client from an action defined in another component. Passing the same object in action as argument seems to work fine, but returning produces an error. What is the correct way of doing it ?

Minimal code for what I want :

#include <hpx/hpx_init.hpp> 
#include <hpx/include/actions.hpp> 
#include <hpx/include/components.hpp> 

#include <utility> 

struct foo_server : public hpx::components::component_base<foo_server> 
{ 
}; 

using foo_server_type = hpx::components::component<foo_server>; 
HPX_REGISTER_COMPONENT(foo_server_type, foo_server); 

struct foo : public hpx::components::client_base<foo, foo_server> 
{ 
   public: 
   using base_type = hpx::components::client_base<foo, foo_server>; 

   foo() = default; 

   foo(hpx::id_type id) : base_type(std::move(id)) 
   { 
   } 

}; 

struct bar_server : public hpx::components::component_base<bar_server> 
{ 
   foo get_foo() { 
       //return hpx::new_<foo_server>(hpx::find_here()); 
       return foo(hpx::find_here()); 
   } 
   HPX_DEFINE_COMPONENT_DIRECT_ACTION(bar_server, get_foo, get_foo_action); 
}; 
using bar_server_type = hpx::components::component<bar_server>; 
HPX_REGISTER_COMPONENT(bar_server_type, bar_server); 

HPX_REGISTER_ACTION(bar_server::get_foo_action); 

struct bar : public hpx::components::client_base<bar, bar_server> 
{ 
   public: 
   using base_type = hpx::components::client_base<bar, bar_server>; 

   bar() = default; 

   bar(hpx::id_type id) : base_type(std::move(id)) 
   { 
   } 

   hpx::future<foo> get_foo() { 
       bar_server::get_foo_action act; 
       // This async statement gives compilation error 
       return hpx::async(act, hpx::find_here()); 
   } 

}; 

int hpx_main(int, char*[]) 
{ 

   bar b(hpx::find_here()); 
   auto res = b.get_foo().get(); 

   return hpx::finalize(); 
} 

int main(int argc, char* argv[]) 
{ 
  return hpx::init(argc, argv); 
}

Compilation fails with error :

test.cpp: In member function ‘hpx::lcos::future<foo> bar::get_foo()’: 
test.cpp:54:26: error: could not convert ‘hpx::async(F&&, Ts&& ...) [with F = bar_server::get_foo_action&; Ts = {hpx::naming::id_type}; decltype (hpx::detail::async_dispatch<type
name hpx::util::decay<Action>::type>::call(forward<F>(f), (forward<Ts>)(hpx::async::ts)...)) = hpx::lcos::future<hpx::naming::id_type>; typename hpx::util::decay<Action>::type = 
bar_server::get_foo_action](hpx::find_here(hpx::error_code&)())’ from ‘hpx::lcos::future<hpx::naming::id_type>’ to ‘hpx::lcos::future<foo>’ 
        return hpx::async(act, hpx::find_here());
@AntonBikineev
Copy link
Contributor

just for a note, clang says:

ex.cc:54:15: error: no viable conversion from returned value of type 'future<typename traits::promise_local_result<typename hpx::traits::extract_action<get_foo_action>::remote_result_type>::type>' to
function return type 'future<foo>'
                return hpx::async(act, hpx::find_here());
.......
/usr/local/include/hpx/runtime/components/client_base.hpp:78:24: error: no matching conversion for functional-style cast from 'future<hpx::naming::id_type>' to 'foo'
                return Derived(future<id_type>(shared_state));

@hkaiser
Copy link
Member Author

hkaiser commented Dec 6, 2016

The problem is a result of several issues:

  • Direct actions currently don't support returning futures (clients are just special futures, and they are treated as such by HPX). This needs to be fixed at some point.
  • hpx::async for actions unfortunately behaves differently if compared to hpx::async for local functions. The former automatically unwraps futures, the latter does not automatically unwrap those (the same holds for clients). This is an unfortunate inconsistency which we might want to fix at some point in the future as well.
  • The client implementations in the given code example miss a special implicit (converting) constructor from future<id_type>

Given these restrictions, the following code does what the OP needed:

#include <hpx/hpx_init.hpp>
#include <hpx/include/actions.hpp>
#include <hpx/include/components.hpp>

#include <utility>

///////////////////////////////////////////////////////////////////////////////
struct foo_server : public hpx::components::component_base<foo_server>
{
};

using foo_server_type = hpx::components::component<foo_server>;
HPX_REGISTER_COMPONENT(foo_server_type, foo_server);

struct foo : public hpx::components::client_base<foo, foo_server>
{
    using base_type = hpx::components::client_base<foo, foo_server>;

    foo() = default;

    // note: this constructor now creates a new component instance 
    foo(hpx::id_type id) : base_type(hpx::new_<foo_server>(id)) {}

    // additional converting constructor
    foo(hpx::future<hpx::id_type> && id) : base_type(std::move(id)) {}
};

///////////////////////////////////////////////////////////////////////////////
struct bar_server : public hpx::components::component_base<bar_server>
{
    foo get_foo()
    {
        return foo(hpx::find_here());
    }

    HPX_DEFINE_COMPONENT_ACTION(bar_server, get_foo, get_foo_action);
};
using bar_server_type = hpx::components::component<bar_server>;
HPX_REGISTER_COMPONENT(bar_server_type, bar_server);

HPX_REGISTER_ACTION(bar_server::get_foo_action);

struct bar : public hpx::components::client_base<bar, bar_server>
{
    using base_type = hpx::components::client_base<bar, bar_server>;

    bar() = default;

    // note: this constructor now creates a new component instance
    bar(hpx::id_type id) : base_type(hpx::new_<bar_server>(id)) {}

    // additional converting constructor
    bar(hpx::future<hpx::id_type> && id) : base_type(std::move(id)) {}

    // note the client function returns a foo, not a future<foo>, 
    // remember clients are 'futures' too, just special ones
    foo get_foo()
    {
        bar_server::get_foo_action act;
        return hpx::async(act, hpx::find_here());
    }
};

///////////////////////////////////////////////////////////////////////////////
int hpx_main(int, char*[])
{
   bar b(hpx::find_here());
   auto res = b.get_foo().get();

   return hpx::finalize();
}

int main(int argc, char* argv[])
{
  return hpx::init(argc, argv);
}

@hkaiser
Copy link
Member Author

hkaiser commented Jan 5, 2017

This can be closed as the OP has resolved his problems

@hkaiser hkaiser closed this as completed Jan 5, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants