ldionne / dyno

Runtime polymorphism done right
Boost Software License 1.0
975 stars 43 forks source link

Interface for using `te::concept_map` for static dispatch #8

Closed griwes closed 7 years ago

griwes commented 7 years ago

Have you considered providing an interface that'd allow using the concept maps of this library for static dispatch, basically to provide a compile-time mechanism for customization points? Shouldn't be too hard to implement, judging by looking through the implementation.

I'm mainly interested in this because I've been working on a customization points thingy myself, although with slightly less Hana and slightly more Boost.PP (which is currently mostly necessary for my vision of the interface due to how we don't have reflection yet), and I'd love to be able to compare bananas to bananas.

The main difference between what I did (which I can hopefully get online soon) and what you did that I've been focused more on providing a customization point mechanism that sucks somewhat less than what's been available to date, and you've focused on providing runtime behavior; this is in essence very similar and requires a lot of common features.

Just few comments/questions not exactly related to the issue, I hope you don't mind putting them here:

  1. Are you going to present a talk about this at C++Now? (I've proposed a talk that's supposed to talk about my approach, so hopefully we can get some discussion about both the approaches if we both end up giving talks at the conference.)
  2. I believe (but I'm biased, so what do I know? :D) my end user interface is nicer than yours, unless until you hit templates, where the macro'd approach starts to get not very customizable at one point. More on point though, did you consider how te might look like when reflection becomes available? Mine should be mostly 1:1 identical, I wonder if yours is as easily translatable at the end user interface level.
  3. Have you thought about solving the problem of having to exit all of your namespaces to specialize the variable template in namespace te from some levels of end-user namespaces?
ldionne commented 7 years ago

Have you considered providing an interface that'd allow using the concept maps of this library for static dispatch, basically to provide a compile-time mechanism for customization points?

Yes, I have, but I have been focusing on the application to type erasure exclusively so far. Technically speaking, we could even generate "archetypes" of some sort using these concept definitions, which would enable some sort of separate checking. But that would require writing all your code using compile-time strings to refer to methods, which is messy.

Without going so far down that road, however, it would be possible to ask whether a type models a concept, and then basically implement a library version of concepts lite on top of that. I fear that using this at any kind of non-trivial scale would be prohibitively slow at compile-time, though.

Just few comments/questions not exactly related to the issue, I hope you don't mind putting them here:

I'm planning on doing some refactoring of concepts and concept maps, which should make it easier to implement. But, at least for now, the focus is on type erasure.

  1. Are you going to present a talk about this at C++Now?

No, not specifically. I plan to use the type erasure library as an example of using Hana in a non-trivial way, but I won't talk in depth about the library.

  1. I believe (but I'm biased, so what do I know? :D) my end user interface is nicer than yours, unless until you hit templates, where the macro'd approach starts to get not very customizable at one point.

I would love to see your interface.

More on point though, did you consider how te might look like when reflection becomes available?

When full reflection is available, what we could do is use structs to define runtime concepts. The method signatures and names would be used in place of the DSL I'm using right now. Also, we would then most likely be able to generate the wrapper on top of te::poly automatically, or with very little user input. Finally, we might be able to generate some default concept maps automatically, but that's not clear to me yet. Overall, that would be quite nice, but it would solely be a "wrapper" on top of the existing logic.

  1. Have you thought about solving the problem of having to exit all of your namespaces to specialize the variable template in namespace te from some levels of end-user namespaces?

No, and that's a real pain. The only solution I can think of is to use ADL in some way, since that's the only piece of C++ I know of that can lookup across namespaces like it does, but then you'd need to define your concept map in a function and place that function in an associated namespace of the type you're defining the concept map for. Something like:

namespace lib {
  struct SomeConcept : ... { };
}

namespace my {
  struct Foo { };
  constexpr auto concept_map(lib::SomeConcept, Foo) {
    return te::make_concept_map<lib::SomeConcept, Foo>(
      "f"_s = []() { ... }
    );
  }
}

// Then, in `te`, we create the vtable with something like this, which picks
// up the right `concept_map` because of ADL:
auto vtable = te::vtable<lib::SomeConcept>{concept_map(lib::SomeConcept{}, my::Foo{})};

This solution doesn't work because we need to construct Foo{}, etc..., but the idea can maybe be tweaked. I'm not sure how much I like the idea of defining a function that returns the concept map.

griwes commented 7 years ago

You can see my WIP here, though it doesn't yet compile with clang <5 due to some obscure injected class name bug that Richard Smith fixed on trunk recently: reaver-project/reaverlib#43.

The interface is very nice when you're either "deriving" an instance (: public counter) or when you explicitly state there's some typeclass instances inside the type; but when you have a sealed type, you still need to get out of all of your namespaces to reach namespace reaver somehow and I'm not particularly happy with this.

ldionne commented 7 years ago

Thanks for sharing. I personally don't like your approach better, as I find the macros make it harder to see what's going on. More magic, basically. But hey, I guess we're both the worst persons to judge on that since we're biased.

In any case, deriving from the type class definition is not an option in my case, because I want to get rid of inheritance and classic vtables.

griwes commented 7 years ago

There's inheritance and classic vtables in the current implementation of erased, but : public typeclass doesn't involve vtables - it's just to inherit the implementation of the structure I'm using to avoid ADL and other such tricks. It's like derives in haskell.

I'd say both our involve magic, and my point of view is that the end user needs to understand just the interface, not its implementation.

ldionne commented 7 years ago

There's inheritance and classic vtables in the current implementation of erased, but : public typeclass doesn't involve vtables - it's just to inherit the implementation of the structure I'm using to avoid ADL and other such tricks.

Ah, sorry, I did not look at the implementation closely enough.

I'd say both our involve magic, and my point of view is that the end user needs to understand just the interface, not its implementation.

Sure.

ldionne commented 7 years ago

I'm going to close this now. We can still talk here without problem, but I just want to close the issue.