Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2005-07-27 12:53:08


From: FlSt_at_[hidden]
> Rob Stewart wrote:
>
> Using references instead of value copies is one of the points I wanted
> to think about. This would make the is_empty(), size() and values()
> functions unnecessary. The operator bool() is necessary for the duality
> of the junctions, because a false result of a comparison isn't mandatory
> an empty junction. And the be()-function exists just for completeness,
> but i think we can live without it. But when using container-references,
> how can I return junctions with a new container? Either there must be
> two types of junctions (one holding references and one holding a
> container) or a mechnism like this:

See below.

> This is what i meant with "two types of junctions". How do I determine
> the type of the result container? One operand has a std::set and the
> other one has a std::vecor, which type should the resulting container
> stored in the junction have? Should they depend on the operands?

Why must there be a result junction? See more below.

> >That approach obviates the limited container interface you have
> >created via size(), is_empty(), etc.
> >
> I should read the complete message before replying ;-) That's what I
> said above.

:)

> >BTW, the bool conversion should, probably, use the safe bool
> >idiom.
> >
> It's on my ToDo list. I had already a problem with operator bool() and
> unary operators. That's why the unary operators now class members,
> because my compiler (an outdated gcc 2.95) converted the junction first
> to bool and then applied the unary operator. Why?
> I read about the safe bool idiom in Matthew Wilson / Imperfect C++ /
> Chapter 24. I don't know whether the extra complexity justifies the
> advantage.

I got that book recently, but I haven't read it yet. I just read
his discussion of safe bool to be sure I knew to what you were
referring. The complexity is worthwhile, though it needn't be as
complex as his solution.

It's interesting to note that his use of the generator class is
erroneous until he puts in a "workaround" for Borland. On p404,
he's still using "typedef boolean_type::return_type," but
"return_type" is a dependent type, so standard C++ requires
"typename" so his "workaround" was to make the code correct!

> >>I see junctions as a expressive way to write comparisons and aritmethic
> >>operations on lists and as a alternative to loops.
> >>
> >Let's discuss the use cases. That discussion will form the basis
> >for later documentation, and will focus the design.
> >
> Porbaly the discussions of the Perl community are a good source to get
> an idea. I think they don't added this feature to Perl without a reason.

I took another look at the Perl links you gave in your original
post. Unless I've still missed something, no example applies
arithmetic operations to a junction. They are simply membership
queries. You probably got the other ideas from the "CPAN module
called Quantum::SuperPosition," whatever that is.

We have a fundamental disconnect that we must resolve. If there
is or should be more to junctions than I've mentioned, I need to
understand the use cases and rationale. It may also be that
you're trying to combine different concepts into the same set of
classes and we should tease them apart.

Let's look at two examples and see what they mean:

> But I think the most use cases are something like this, instead of
> writing loops:
>
> if( any_of( a ) < 42 ) { /* one element of list is smaller then 42 */ }

I understand that one. "If any of the elements in a is smaller
than 42, do something."

> b = any_of( a ) * 2; /* multiply all elements with 2 */

I don't get that one; see below. Multiply any of the elements in
a by 2? Which ones? How do you decide?

I suppose "any_of(a) * 2" could be construed as an alias for
"all_of(a) * 2," but what about "none_of(a) * 2" or "one_of(a) *
2?" The latter two are nonsensical, which makes the former two
questionable at best.

Besides, multiplying each element of a container by 2 is easily
done using Boost.Lambda or similar libraries, right? Why must a
junction support that?

> In the Quantum::Superpositions module manual page are examples to get
> the min/max of a list in one line of code, which is based on the
> resulting junction of a comparison:
>
> Minimum of a : any_of( a ) <= all_of( a )
> Maximum of a : any_of( a ) >= all_of( a )

That's supported by my equality operator approach, too.

> >You make a good point. Junctions are useful to adapt other
> >containers that match some concepts. That makes them more
> >general than they otherwise would be. We need to decide what
> >those concepts are, though.
> >
> The current implementation only needs a constructor for initializing
> with input iterators and forward-iterator support.

Boost.Range will expand that. However, my point was to contrast
the adapter approach to that of the conceptual_set that was
suggested.

> >>What do you think of this approach? Boost.Range gives us a wide
> >>range of types over which to operate, and putting the logic in
> >>the equality operators rather than the junction types gives us
> >>compile-time logic selection. The junction types merely serve as
> >>selectors for the appropriate equality operator.
> >>
> I think boost.range and junction would fit good together, but you forgot
> to adhire the duality of the result of a comparison. In the
> minumum/maximum example showed above the values of the resulting
> junctions were interesting.

I don't know what you mean by "adhere to the duality of the
result of a comparison" unless you mean that your version always
returns a new junction that can implicitly convert to a Boolean
for comparisons. I don't see the value of that.

My equality operator approach does the comparisons handily.

> There are three ways how to use the result in the current implementation:
>
> disjunction< Container > a, b;
>
> disjunction< Container > r = a <= b; // assign to another junction

Why?

> Container r_c = a <= b; // use values of the resulting junction ( if
> junctions are refs, then this isn't necessary )

Why?

> bool r_b = a <= b; // use boolean result

Yes.

If we can agree to forgo the arithmetic functionality you've
thought should be part of the junction classes, we can simplify
the design significantly. That, in turn, will make writing
documentation easier and will increase the chances of acceptance
into Boost.

-- 
Rob Stewart                           stewart_at_[hidden]
Software Engineer                     http://www.sig.com
Susquehanna International Group, LLP  using std::disclaimer;

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk