Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2002-09-05 17:43:14


----- Original Message -----
From: "Sylvain Pion" <pion_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Wednesday, September 04, 2002 10:31 PM
Subject: Re: [boost] Formal Review for Interval Library beginning

> On Wed, Sep 04, 2002 at 04:47:01PM -0300, Fernando Cacciola wrote:
> > > I haven't looked at the library yet
>
> Do you think it's appropriate to send a strong recommendation in this case
?
>
Fair enough.
Maybe you're right here, but recall that I've read closely *all* the
messages for the review.
I intended to approach the issue about interval relational expressions, and
their related operators, functions and policies from a general POV, not as
it pertains to this specific library. I've choosen this approach not because
I have no interest in actually evaluating this specific submission, but
because I saw this as a very general problem.
I have a very specific interest in this library and although I haven't said
so already, I really liked what I saw of it so far. It is just that I
haven't got the time to look closer yet.

> > Therefore, I strongly recommend that if comparison policies are
retained,
> > their return type shall not be left user-specified and tribool shall not
be
> > supported as an option.
>
> I beg to differ.
>
> You have not read carefully my email which shows tribool is not the
panacea,
> have you ?
>
Yes I did. I read carefully all the messages.

>
> Here's another drawback of tribool I just thought about.
> If I'm correct, for :
>
> if (x<y && y<z())
>
> tribool forces the evaluatation of the second condition, whereas bool
doesn't.
>
> Even without any indeterminate state whatsoever.
>
Right. I was aware of this language issue, I just didn't notice that tribool
overloads operator &&.

> bool has a standard well defined meaning which everybody knows.
Agreed.

> Going to tribool changes a lot of things in subtle ways, and I simply
> don't think it's only for the better.
Me too. Please read below, I'll try to re-explain what I meant in my
previous post.

>
> For my own application, where I re-use template code (which assumes exact
> arithmetic), notifying overlaps by exceptions, I want bool. I don't want
a
> different logic that changes my program in manners difficult to predict.
> Basically that would force me to review all my code to see if there can be
a
> culprit somewhere (and maintain this thinking for new code).
>
OK.

> Moreover, as we want to offer some compatibility with other IA libraries
> (and none of them has a 3-state return type, but all of them are useful,
> not the result of the dream of a possible fancy application somewhere),
> we'd better allow bool and the comparison policies mecanism for
flexibility.
>
OK.

>
> I think there are guide lines for C++ beginners in books such as Meyers'
> which basically say :
> - do not overload operators && and ||.
> - do not abuse implicit conversions.
>
> You are advocating both.
No. I'm advocanting none... read below.

> Did you _really_ think about the consequences hidden behind the fancy tool
?
> I'm not sure.
>
Which fancy tool? tribool?
I didn't think of all *its* consecuences becasue I wasn't thinking of
tribool as the solution... see right below:

It seems that I was not clear at all.
I've never meant to say that tribool is a good solution or that it is better
than comparison policies.
What I meant to say is that I interpret comparison policies on one hand, and
tribool on the other, as two alternative approaches to the same problem, and
that they overlap so much in purpose, that the design should choose only one
and don't offer both.

Perhaps is this last assertion which is wrong, and the source of your
misreading of my post.
So I'll try to explain why do they overlap and why only one of them should
be offered:

Q: What was the original objection to the comparison policies?
Unless I've missread something, the original objection was that they loose
contextual information about the semantic of relational boolean expressions.
That is, it was raised that code like the following is a bit unclear in
unusual ways:

my_interval x,y ;
my_interval z = std::max(x,y);

because the semantics of the operator '<' is hidden in the typedef for
'my_interval'.

Let's call this problem: 'non-locality'.
(because I need to look outside the scope, in some typedef, the meaning
(x<y))

AFAICT, initially it was not raised as a problem that the
policy-specifications didn't cover all required cases.

Q: What are the problems with a 'bool' return type for the policies?
It could be said that the relational operators could benefit from returning
a non-boolean type.
But, why would it be neccesary that they return a non-boolean type?
Returning a non-boolean type would be useful in order to define the mapping
between the interval-interval inner comparisons and a boolean value.
But, isn't it the purpose of a user-defined interval-interval function
returning a 'bool' to supply this mapping?

So, if I have a comparison policy which allows me to define a mapping
between interval-interval comparisons and bool, why would I need the
additional possibility of defining this mapping not as a functionality of
the policy itsef but as the functionality of a proxy-class as tribool? That
is, what *additional* purpose could have a non-boolean return type? (which
is not covered by the original policy specification).
AFAICT, tribool would be used to 'define' the mapping which I can do already
via the policies.

IMO,
(1) comparison policies as were originally designed -with a fixed bool
return type-; and
(2) any class type with an implicit conversion to bool (such as tribool)

serve the same purpose: to map interval-interval comparisons to bool.

Therefore, I believe that the library should choose either one or the other.
This is what I meant to strongly recommend, not that it chooses tribool or
any other fancy tool.

I see two overlapping alternatives:

A) Use comparison policies with only bool return types
(and possibly with extended function sets to resolve the
relational-identities problem)

B) Use a high-level proxy class which is returned by relational operations
and which defines the mapping-to-bool either as:

  B.1) an implicit conversion to bool.
  B.2) explicit functions taking the proxy as argument and returning bool.

tribool is really just an example of (B.1).

Notice that such a proxy could encode all the information it wants.
With the proxy approach, it might be possible to evaluate all of the
possible relations with all possible semantics (for instance, as shown by
Joel), by using a syntax of the form:

map(x .op. y)

where
"map" is a discriminator function returning bool and used to select the
semantic of the relation.
".op." is any of the relational operators
"x .op. y" is not a boolean expression but an instance of the proxy feed to
the discriminator.

Now...

You have properly explained that a specific proxy such as tri-bool won't
cover all the required cases while comparison policies do.
I knew this when I post my comments; so I agreed that tribool couldn't be
fixed in the interface.

But then I stated that, since it can't be fixed, tribool shouldn't coexist
with the policy-approach because of the reasons I now gave above.

Still, I wanted to explore general proxies, and I intended this to be the
core of my post. Perhaps I shouldn't have even mentioned tribool.

So, here I go again:

It is always possible to define a proxy which handles properly all
interval-interval comparisons; and that therefore the true problem is how to
define the mapping between this unique universal proxy returned by all
relational operators and bool.

IMHO, a consistent and complete solution to this proxy-2-bool problem is to
simply disallow implicit bool conversions and *require* explicit functions.

But requiring the use of explicit functions to map relational expressions
(non-boolean) is unlikely to be accepted by end users.
If we think *only* in this last inconvinience, the proxy should have some
implicit bool conversion for end users to like it (**but notice that I would
have it without implicit conversions, as I said so before**).
But then this implicit conversion needs to be selected by the user, which
means that the proxy itself is required to be a policy class.
I concluded that a proxy with implicit bool conversions will suffer
*exactly* from the *only* problem I see with comparison policies:
non-locality.

OTOH, a proxy *without* implicit conversions will have strong local
semantics (context-free meaning), so it would totally solve all the problems
raised so far AFAICT.
It appears that this is still the case, so the only drawback I see in this
scheme is its involved syntaxis.

A last note: I think I've just made clear that I've never advocated implicit
conversions.
(But I admit that I might have failed to say so clearly before)
Just for the records, I definitely never thought of overloading && and ||
for the proxy classes.

Best Regards

BTW: I will give a full review of the library beyond this general issue.

Fernando Cacciola
Sierra s.r.l.
fcacciola_at_[hidden]
www.gosierra.com


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