AnyAny icon indicating copy to clipboard operation
AnyAny copied to clipboard

Do you see a way to add associated types?

Open uselessgoddess opened this issue 3 years ago • 6 comments

For example, it might look something like this:

template <typename T>
struct Deref {
  struct Target {};

  static auto do_invoke(const T&) -> Target&;

  template <typename CRTP>
  struct plugin {
    auto deref() const {
      return aa::invoke<Deref>(*static_cast<const CRTP*>(this));
    }
  };
};

template <typename Ptr>
struct Deref<std::shared_ptr<Ptr>> {
  using Target = std::remove_extent_t<Ptr>;

  static auto do_invoke(const std::shared_ptr<Ptr>& self) -> Target& {
    return *self.get();
  }
};

This is convenient because Self is responsible for the associated type itself. In this example, the opposite is true https://github.com/kelbon/AnyAny/blob/c4603b3959c5f8e8b9a104b09bb53025b1ff776f/examples/functional_paradigm.hpp#L22-L30

However, it doesn't work because result_t get return type from Method<aa::interface_t>, but Target is unique for all types. This can be fixed, but for dyn call via poly_ref/any_ it will require explicit aanotation

uselessgoddess avatar Jul 31 '22 07:07 uselessgoddess

For example, it might look something like this:

template <typename T>
struct Deref {
  struct Target {};

  static auto do_invoke(const T&) -> Target&;

May be you can require typename T::Target; But anyway you need to return same type for all, so Target need to be same for all types, so its useless. (i think rust has same requirements for Dyn traits, apart from the fact that rust has no cast to smaller requirements)

kelbon avatar Jul 31 '22 14:07 kelbon

But anyway you need to return same type for all, so Target need to be same for all types, so its useless.

It's not useless. For example, any type that was written in the type_traits style can be rewritten. In Rust and Swift, they really have more privileges. Dyn constraint really stricter.

Associated types will reverse the implementation. This helps to better perceive where this type comes from.

  • outside - template param (we pass result type to get result)
  • inside - associated param (we get concrete result for Self type)

Also compare :)

template <typename T>
struct Iterator {
  struct Item {};

  static auto do_invoke(const T&) -> std::optional<Item>;

  template <typename CRTP>
  struct plugin {
    auto next() const {
      return aa::invoke<Iterator>(*static_cast<const CRTP*>(this));
    }
  };
};

template <>
struct Iterator<MyIter> {
  using Item = std::size_t;

  static auto do_invoke(const MyIter& self) -> std::optional<Item> {
    // impl
  }
};

. . .

// i hope it works))
template<typename Item>
struct Constraints {
  template <typename T>
  struct iterator {
    static auto do_invoke(const T&) -> std::optional<Item>;

    template <typename CRTP>
    struct plugin {
      auto next() const {
        return aa::invoke<iterator>(*static_cast<const CRTP*>(this));
      }
    };
  };
};

template<>
struct Constraints <std::size_t> {
  template<typename T>
  struct iterator {
    static auto do_invoke(const T&) -> std::optional<std::size_t> {
      // impl
    }
  };
};

uselessgoddess avatar Jul 31 '22 15:07 uselessgoddess

Although maybe it useless

uselessgoddess avatar Jul 31 '22 15:07 uselessgoddess

Can you show how you see interfaces with template parameters? I can do it somehow like this: godbolt But I'm sad that I can't use Method<Self>::Type. We need to know the Type

Probably it possible with static_ref (if make it smartest), but i'm not C++ programmer to make this code work

template <typename Output>
using Oof = /* template<typename Self> Foo<Self, Output>*/;

template <typename Self, typename Output>
auto foo(aa::static_ref<Self, Oof<Output>>& ref) {
}

uselessgoddess avatar Aug 01 '22 12:08 uselessgoddess

Can you show how you see interfaces with template parameters?

template<typename A, typename B>
struct foo {
  template<typename T>
  struct trait {
    static X do_invoke(T& self) { return X{}; } 
  };
};

template<typename T>
using trait_foo_int_double = foo<int, double>::template trait;
// or
using h = any_with<foo<int, double>::template trait>;

kelbon avatar Aug 01 '22 13:08 kelbon

Can you show how you see interfaces with template parameters?

template<typename A, typename B>
struct foo {
  template<typename T>
  struct trait {
    static X do_invoke(T& self) { return X{}; } 
  };
};

template<typename T>
using trait_foo_int_double = foo<int, double>::template trait;
// or
using h = any_with<foo<int, double>::template trait>;

Oh, no. Here is an example from godbolt, but with this style - https://godbolt.org/z/b8jK4bPK8

uselessgoddess avatar Aug 01 '22 13:08 uselessgoddess

Oh no, bro. When I have time, I will definitely try to make it.

uselessgoddess avatar Aug 25 '22 12:08 uselessgoddess

Oh no, bro. When I have time, I will definitely try to make it.

I'm always happy with ideas, but it seems impossible to do something adequate here

kelbon avatar Aug 25 '22 13:08 kelbon

Oh no, bro. When I have time, I will definitely try to make it.

I don't remember exactly what the discussion was, but I'm just throwing off a random thought here

template<typename T>
struct trait {
  static void do_invoke(T& self);

  template<typename U = T>
  consteval auto associated_type() {
    return std::type_identity<U::type>{}; 
  }
};

kelbon avatar Sep 13 '22 07:09 kelbon

It seems to me Trait::type will be enough. И dynamic invoking must be non erasure this type:

aa::poly_ref<Trait, aa::where_eq<Trait, ConcreateAssocType>>

And I'm not sure. Will it be consistent in the context of C++? In addition, we have different views on the use of aa:

// I would do it like this

template <typename T>
struct draw {
  struct metadata {};

  static auto do_invoke(const T& self, std::span<uint8_t> buf) -> metadata;
};

struct DrawA {};

template<>
struct draw<DrawA> {
  using metadata = size_t;

  static auto do_invoke(const DrawA& self, std::span<uint8_t> buf) -> metadata {
    // DrawA impl
  }
};

struct DrawB {};

template<>
struct draw<DrawB> {
  using metadata = size_t;

  static auto do_invoke(const DrawB& self, std::span<uint8_t> buf) -> metadata {
    // DrawA impl
  }
};
// But you prefer the imperative style more
template<typename metadata>
struct draw {
  template <typename T>
  struct method {
    static auto do_invoke(const T& self, std::span<uint8_t> buf) -> metadata;
  };
};

struct DrawA {
  auto draw() const {
    // DrawA impl 
  }
};

template<>
struct draw</* metadata */ size_t> {
  static auto do_invoke(const DrawA& self, std::span<uint8_t> buf) -> size_t {
    self.draw();
  }
};

struct DrawB {
  auto draw() const {
    // DrawA impl 
  }
};

uselessgoddess avatar Sep 15 '22 08:09 uselessgoddess