[boost] Re: [boost.variant] It is possible to make a variant LessThanComparable

2003-09-01 Thread Alexander Nasonov
David Abrahams wrote:

 Dirk Schreib [EMAIL PROTECTED] writes:
 
 I would like a variant to be LessThanComparable if all
 BoundedTypes are LessThanComparable.

 In this example

   typedef boost::variantT1, T2, ..., TN V;
   V v1 = T1( x );
   V v2 = T2( y );
   V v3 = T1( z );

 v1  v2 should always be true. And v1  v3 should be the same as T1( x )
  T1( z ).

 I assume that the resulting variant class will be StrictWeaklyComparable
 if all
 BoundedTypes are StrictWeaklyComparable.
 
 Sounds like maybe you want dynamic_any.  Have you looked at Alexander
 Nasonov's work?

I would like to emphasize one difference with variant library. User should 
_add_ less operation to the list of supported operations to enable 
operator. This operator isn't enabled by default. This protects from 
undesirable effects because if the user added less I can assume that she 
knows what she's doing. But the problem of different order is still 
persist.

I think we should coordinate our work on variant and dynamic_any library. 
The discussed problem is one point where coordination is needed.

Both libraries work with some set of types by (i) storing value of one 
selected type and (ii) calling some operation for stored value. This is 
done with some differences, though. In assumption that typedefs for variant 
and dynamic_any fixed I can say that:
1. variant operates with _fixed_ set of stored types but with _open_ set of 
supported operations (through static_visitor)
2. dynamic_any has _open_ set of stored type but _fixed_ set of supported 
operations

There is also some differences in operation support. Variant's operation 
looks like:

struct print : static_visitorvoid
{
  std::ostream out_;
  print(std::ostream out) : out_(out) {}

  templateclass T
  void operator()(const T value) const
  {
out_  value;
  }
};

while dynamic_any operation looks like:

struct print : functionprint, void (std::ostream, const anyT)
{
  templateclass T
  void call(std::ostream out, const T value) const
  {
out  value;
  }
};

On one hand, variant uses operator() which is good for anonymous 
operations (obviously, it's not possible for dynamic_any):

variantint, char v(0);

// anonymous function is ok
apply_visitor(v, std::cout  _1);

 // error, attempt to call std::cout  v
for_each(v, v + 1, std::cout  _1);

// ok
for_each(v, v + 1, print(std::cout));

On the other hand, dynamic_any has better support for std algorithms, 
lambda, bind, etc (well, in variant case it's also possible by binding 
apply_visitor):

dynamic_any::anympl::listprint  a(0);

// ok, direct call
print()(std::cout, a);

// ok if result of print doesn't contain anyT (void doesn't)
// otherwise, bindR is required
for_each(a, a + 1, bind(print(), std::cout, _1));

Other advantage of dynamic_any is a possibility to mix normal arguments 
and anyT-based. Due to nature of dynamic_any it's not possible to call the 
operation containing two or more anyT-based arguments for arbitrary 
arguments. Call can be made only if all any arguments hold same type or 
are derived publicly from one type T stored by one any argument.
However, less works fine with arbitrary types because I added 
call_ex/no_call mechanism to the library.
In variant the set of stored types is fixed and all combinations can be 
considered (be careful, it may cause combinatorial explosion):

struct plus : variant::functionplus, variantT (variantT, variantT)
{
  templateclass T1, class T2
  typeof(v1 + v2) call(T1 v1, T2 v2) const
  {
// Note that T1 and T2 are in general
// different (in opposite to dynamic_any)
return v1 + v2;
  }

  templateclass T2
  std::string call(std::string v1, T2 v2) const
  {
return v1 + lexical_caststd::string(v2);
  }

  templateclass T1
  std::string call(T1 v1, std::string v2) const
  {
return lexical_caststd::string(v1) + v2;
  }

  // ...
};


variantstd::string,int,char s(s);
variantstd::string,int,char i(0);

variantstd::string,int,char s0 = plus()(s, i);
// s2 == std::string(s0)

--
Alexander Nasonov
Remove minus and all between minus and at from my e-mail for timely response


___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: [boost.variant] It is possible to make a variant LessThanComparable

2003-08-31 Thread Dirk Schreib
David Abrahams [EMAIL PROTECTED] wrote
 Eric Friedman [EMAIL PROTECTED] writes:
std::set my_variant, boost::variant_lessmy_variant 

 I had the same thought myself, though I'd be inclined to spend a
 little time searching for a better name than less, since it doesn't
 really mean that.  Maybe variant_before, using type_info::before as
 a precedent?

Maybe std::lessT is a precedent too?
Nearly everyone I know has written a small, little wrapper around
type_info to make it useable in the associative containers (and
the default std::lessT).

Dirk



___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost


[boost] Re: [boost.variant] It is possible to make a variant LessThanComparable

2003-08-31 Thread Dirk Schreib
Hello Eric,

Eric Friedman [EMAIL PROTECTED] wrote
 Dirk Schreib wrote:
  [...]
  In this example
 
typedef boost::variantT1, T2, ..., TN V;
V v1 = T1( x );
V v2 = T2( y );
V v3 = T1( z );
 
  v1  v2 should always be true. And v1  v3 should be the same as T1( x )

  T1( z ).

 For starters, I agree that v1  v3 should be the same as x  y.

Ok.

 I'm not so sure about v1  v2, though. I'm inferring that you believe that
 operator should be implemented as follows:

   template typename T1, ..., typename TN
   bool operator(
   const variantT1,...,TN lhs,
 , const variantT1,...,TN rhs
 )
   {
 if (lhs.which() == rhs.which())
   ... // compare using underlying operator
 else
   return lhs.which()  rhs.which()
   }

This is exactly what I want.

 While this certainly solves the problem of storing variants in associative
 containers by establishing an ordering, the ordering is rather arbitrary
and
 potentially confusing. Consider the following:

   typedef variantint, double var;
   bool result1 = int(3)  double(2.0); // false
   bool result2 = var(3)  var(2.0); // true

 On first glance, IMO most users would expect result1 == result2. With your
 ordering scheme, this would be untrue. Unfortunately, I do not believe the
 problem is specific to your ordering scheme.

Trying to establish an ordering between unrelated types where each type does
not
fall into it's own category is very difficult. My ordering scheme is very
easy and
simple because you never have to compare two different types.
Alternative solution would be to use

  typedef variantT1, T2 var;
  bool operator( T1 const lhs, T2 const rhs);

which usually does not exist. Even if it is possible to compare two
different types
with integral promotion or user defined conversion operators it will impose
problems on asymetry and transitivity.

  typedef variantdouble, std::string, int var;
  bool result1 = var(3.0)  var(2);  // false or true?
  bool result2 = var(3.0)  var(2.5); // false or true?
  bool result3 = var(2.5)  var(2); // false or true?

  // if (result2  result3) == result1 = true.

 Ultimately, I do not believe any ordering scheme will provide meaningful,
 straightforward semantics. Assuming I am correct, I propose that the
variant
 library offer your ordering scheme -- but only as an explicit comparison
 function, calling it variant_less. This would allow, for instance:

   std::set my_variant, boost::variant_lessmy_variant 

The default comparison operator for std::setT is std::lessT
(which just uses operator() ) and I would like this to work with
variant too. If there are no meaningful, straightforward semantics
the user will not put a variant into a set. If my ordering scheme
is the only one offered by variant, it can be the default too.

 P.S. The issue of equality comparison between variants is a bit more
 straightforward. However, we still have the following potentially
confusing
 situation:

   typedef variantint, double var;
   bool result3 = (int(3) == double(3.0)); // true
   bool result4 = (var(3) == var(3.0)); // false

I need exactly this behaviour...
 Thus, perhaps a boost::variant_equal comparison function is also in order.

...and don't have a need for this ;-)


Dirk



___
Unsubscribe  other changes: http://lists.boost.org/mailman/listinfo.cgi/boost