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

adapt_boost_variant: how to say 'any sub-type of a variant'? #31

Open
akrzemi1 opened this issue Feb 8, 2016 · 8 comments
Open

adapt_boost_variant: how to say 'any sub-type of a variant'? #31

akrzemi1 opened this issue Feb 8, 2016 · 8 comments
Labels

Comments

@akrzemi1
Copy link
Contributor

akrzemi1 commented Feb 8, 2016

I am trying to do a type switch on two variants, as per the example below. My intention is to match the case where the left-hand object 'tank' has the sub-type TankC and the right-hand side object 'load' has any type. I managed to achieve the effect by listing two labels one immediately after the other, but I guess there must be a more direct way of expressing this?

#include <boost/variant.hpp>
#include <Mach7/code/type_switchN-patterns-xtl.hpp>
#include <Mach7/code/adapters/boost/adapt_boost_variant.hpp>
#include <Mach7/code/patterns/constructor.hpp>

struct TankA {};
struct TankB {};
struct TankC {};

struct Load1 {};
struct Load2 {};

typedef boost::variant<TankA, TankB, TankC> Tank;
typedef boost::variant<Load1, Load2> Load;

int interact(Tank const& tank, Load const& load)
{
  using mch::C;

  Match (tank, load)
  {
    Case (C<TankA>(), C<Load1>())
      return 61;
    Case (C<TankA>(), C<Load2>())
      return 62;
    Case (C<TankB>(), C<Load1>())
      return 71;
    Case (C<TankB>(), C<Load2>())
      return 72;
    Case (C<TankC>(), C<Load1>()) //
    Case (C<TankC>(), C<Load2>()) // I want these two cases to be one
      return 0;
    Otherwise()
      return -1;
  }
  EndMatch
}

int main()
{
  assert (interact(TankC(), Load2()) == 0);
}
@solodon4
Copy link
Owner

solodon4 commented Feb 9, 2016

Hi Andrzej,

Read the comment for XTL_FALL_THROUGH in config.h. Right now it is enabled,
but it shouldn't and I should have removed that functionality altogether
long time ago. The problem is that the static type of match0, match1 etc.
is different in each clause, so fall-through doesn't really make sense, not
in a library at least. In a language solution you may argue that their type
should be the join of their types, but that's a whole different discussion.
You don't really get a fall-through in your case, you get a second clause
checked after the first one.

Yuriy

On Mon, Feb 8, 2016 at 3:50 PM, Andrzej Krzemieński <
[email protected]> wrote:

I am trying to do a type switch on two variants, as per the example below
My intention is to match the case where the left-hand object 'tank' has the
sub-type TankC and the right-hand side object 'load' has any type I
managed to achieve the effect by listing two labels one immediately after
the other, but I guess there must be a more direct way of expressing this?

#include <boost/varianthpp>
#include <Mach7/code/type_switchN-patterns-xtlhpp>
#include <Mach7/code/adapters/boost/adapt_boost_varianthpp>
#include <Mach7/code/patterns/constructorhpp>
struct TankA {};struct TankB {};struct TankC {};
struct Load1 {};struct Load2 {};
typedef boost::variant<TankA, TankB, TankC> Tank;typedef boost::variant<Load1, Load2> Load;
int interact(Tank const& tank, Load const& load)
{
using mch::C;

Match (tank, load)
{
Case (C(), C())
return 61;
Case (C(), C())
return 62;
Case (C(), C())
return 71;
Case (C(), C())
return 72;
Case (C(), C()) //
Case (C(), C()) // I want these two cases to be one
return 0;
Otherwise()
return -1;
}
EndMatch
}
int main()
{
assert (interact(TankC(), Load2()) == 0);
}


Reply to this email directly or view it on GitHub
#31.

@akrzemi1
Copy link
Contributor Author

akrzemi1 commented Feb 9, 2016

Ok, so my example doesn't do what I intended. But my question still remains: is there a way to say "match TankC on the left-hand side and match anything on the right-hand side"? Like:

Case (C<TankC>(), match_anything)

The use case is this: in case I get TankC on the left-hand side, the type (and its value) on the other side is irrelevant and not needed to compute the result. In that case I would never need to access match1.

@solodon4
Copy link
Owner

solodon4 commented Feb 9, 2016

of course, just use the wildcard pattern _

#include <mach7/patterns/primitive.hpp>

using mch::_;

Case(C(), _) ...

Alternatively, Case allows specifying less arguments than subjects in which
case all missing patterns are assumed to be wildcard and match
unconditionally.

Btw, I started moving headers, just haven't finished yet.

Yuriy

On Tue, Feb 9, 2016 at 2:37 AM, Andrzej Krzemieński <
[email protected]> wrote:

Ok, so my example doesn't do what I intended. But my question still
remains: is there a way to say "match TankC on the left-hand side and
match anything on the right-hand side"? Like:

Case (C(), match_anything)

The use case is this: in case I get TankC on the left-hand side, the type
(and its value) on the other side is irrelevant and not needed to compute
the result. In that case I would never need to access match1.


Reply to this email directly or view it on GitHub
#31 (comment).

@akrzemi1
Copy link
Contributor Author

akrzemi1 commented Feb 9, 2016

The following program does not compile, even after using the wildcard pattern. I get an error about ambiguous class template instantiation (xtl::is_subtype). Omitting the second argument in Case() also does not work (static_assert fires). Note that I am using the macros defined in the header type_switchN-patterns-xtl.hpp - or am I supposed to use a different one?

-- Andrzej

#include <boost/variant.hpp>
#include <Mach7/code/type_switchN-patterns-xtl.hpp>
#include <Mach7/code/adapters/boost/adapt_boost_variant.hpp>
#include <Mach7/code/patterns/constructor.hpp>
#include <mach7/code/patterns/primitive.hpp>

struct TankA {};
struct TankB {};
struct TankC {};

struct Load1 {};
struct Load2 {};

typedef boost::variant<TankA, TankB, TankC> Tank;
typedef boost::variant<Load1, Load2> Load;

int interact(Tank const& tank, Load const& load)
{
  using mch::C;
  using mch::_;

  Match(tank, load)
  {
    Case (C<TankA>(), C<Load1>())
      return 61;
    Case (C<TankA>(), C<Load2>())
      return 62;
    Case (C<TankB>(), C<Load1>())
      return 71;
    Case (C<TankB>(), C<Load2>())
      return 72;
    Case (C<TankC>(), _)
      return 0;
    Otherwise()
      return -1;
  }
  EndMatch
}

int main()
{
  assert (interact(TankC(), Load1()) == 0);
}

@solodon4
Copy link
Owner

solodon4 commented Feb 9, 2016

For variant, that is the right header, other headers would only assume
subclassing. I'll have a look at this tonight - I probably need to add a
couple more subtyping specializations.

On Tue, Feb 9, 2016 at 12:28 PM, Andrzej Krzemieński <
[email protected]> wrote:

The following program does not compile, even after using the wildcard
pattern. I get an error about ambiguous class template instantiation (
xtl::is_subtype). Omitting the second argument in Case() also does not
work (static_assert fires). Note that I am using the macros defined in
the header type_switchN-patterns-xtl.hpp - or am I supposed to use a
different one?

  • Andrzej

#include <boost/variant.hpp>
#include <Mach7/code/type_switchN-patterns-xtl.hpp>
#include <Mach7/code/adapters/boost/adapt_boost_variant.hpp>
#include <Mach7/code/patterns/constructor.hpp>
#include <mach7/code/patterns/primitive.hpp>

struct TankA {};
struct TankB {};
struct TankC {};

struct Load1 {};
struct Load2 {};

typedef boost::variant<TankA, TankB, TankC> Tank;
typedef boost::variant<Load1, Load2> Load;

int interact(Tank const& tank, Load const& load)
{
using mch::C;
using mch::_;

Match(tank, load)
{
Case (C(), C())
return 61;
Case (C(), C())
return 62;
Case (C(), C())
return 71;
Case (C(), C())
return 72;
Case (C(), _)
return 0;
Otherwise()
return -1;
}
EndMatch
}

int main()
{
assert (interact(TankC(), Load1()) == 0);
}


Reply to this email directly or view it on GitHub
#31 (comment).

@solodon4
Copy link
Owner

Code compiles with Clang, so I guess it is an MSVC-specific issue. Not sure yet why.

As to static_assert, I remember now I added it deliberately because some of the patterns might have commas in them without being wrapped into ( and ). Preprocessor would then treat them as separate arguments, so it was more useful to have the compiler assert when the number of patterns was not matching the number of subjects.

@akrzemi1
Copy link
Contributor Author

Ok. Can you give me some background then? Sub-type matching works when the correct unambiguous specialization of subtype_dynamic_cast_impl is found (and returns a non-null pointer). But apparently there is no such specialization for mch::wildcard. So at some point there must be a decision that for mch::wildcard we do not use the XTL mechanism. Can you tell me where it is?

@akrzemi1
Copy link
Contributor Author

I am also experiencing similar problems with GCC.

@solodon4 solodon4 added the bug label Feb 26, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants