hana: Policy for returning references and copies

Currently, Hana does not make any guarantee about what is returned from methods like at or at_key. Indeed, the documentation for at_key just says

Returns the value associated to the given key in a structure, or fail.

This makes no guarantee that a reference to the value in the map should be returned. Indeed, the following code currently fails because at_key returns a copy of the value, which is a temporary int:

#include <boost/hana.hpp>
using namespace boost::hana;

int main() {
    auto map = make_map(
        make_pair(int_<0>, 0)
    );
    map[int_<0>] = 3;
}

The error is:

error: expression is not assignable
    map[int_<0>] = 3;
    ~~~~~~~~~~~~ ^

This causes serious usability problems. On the other hands, if we had a special Iterable generating values on the fly (for example an infinite Iterable generating the fibonacci sequence), we wouldn’t be able to return a reference. Hence, the resolution is not exactly clear.

Another related problem is to determine a policy for when to return a container of references. For example, consider the following code, which was submitted to me in a private email:

#include <boost/hana.hpp>
#include <iostream>
using namespace boost::hana;
using namespace boost::hana::literals;

struct Person {
    BOOST_HANA_DEFINE_STRUCT(Person,
        (int, age)
    );
};

int main() {
 Person john{30};
 members(john)[0_c] = 0;
 // fails because the expression is not assignable
}

This is because members returns a container holding copies of the members of the struct, not references to it. While it seems that it would be more useful to return a sequence of references, it would also create lifetime issues when the Person is a temporary.

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 15 (11 by maintainers)

Commits related to this issue

Most upvoted comments

Sorry if this is a little late in the conversation. In the OP example with the struct, I think it would be beneficial to change the usage to be more like an asynchronous callback interface that you would expect in something like javascript. That way the reference would only be available within the context of the callback. (I couldn’t get the Struct to unpack references so I used a tuple for an example.)

#include <boost/hana.hpp>
namespace hana = boost::hana;
using namespace boost::hana::literals;

struct at_t {
  template <typename S, typename I, typename Fn>
  constexpr auto operator()(S&& s, I, Fn&& fn) const {
    return hana::unpack(std::forward<S>(s),
      [&](auto&&... x) {
        return std::forward<Fn>(fn)(
          hana::arg<I::value + 1>(std::forward<decltype(x)>(x)...)
        );
      }
    );
  }
};
constexpr at_t at{};

int main() {
  auto john = hana::make_tuple(30);
  at(john, 0_c, [](auto& arg) { arg = 35; });
  BOOST_HANA_RUNTIME_ASSERT(john[0_c] == 35);
}

This sort of interface would also make wrapping a reference in an optional a lot less scary. ☕