Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2004-04-02 17:38:47


From: "David Bergman" <davidb_at_[hidden]>
> Rob wrote:
>
> > So you're saying that a traits class cannot have behavior?
>
> Yes, that is what I am saying, weird as it might sound... Not "have"
> behavior, but certainly map to... yes, the distinction is partly
> philosophical, I admit that.

You've lost me. I don't understand the distinction you're trying
to make.

> > You're saying that, for example,
> > std::char_traits<T>::length() means that std::char_traits is
> > not a traits class?
>
> No, in my twisted world view 'std::char_traits' is a trait (template) class
> manifesting some features of the Character concept. One of the features is a
> behavior, 'length.'

I'm further confused.

For the record, std::char_traits is a traits class in my world.

> > While I agree that there should be
> > little behavior in traits classes as a rule, if that behavior
> > is peculiar to the traits class (specialization of class
> > template, typically), then it is reasonable.
>
> It might be reasonable to let the trait (template) class map to certain
> behavioral features of the concept, yes.

Try again. I don't understand what you're trying to say. If
there's a static mf in the traits class, then it has behavior.

> Again, the crucial part is that trait classes realize relationships and
> features found in the concept model, where you get the *actual*
> correspondents (types, values, and, yes, behavior) of the model provided as
> type parameter.

OK, I think I understand what you're trying to say here, but
given my confusion with your previous statements, I must not.

> > I say that
> > because you can count on the consistency of that behavior and
> > the specific behavior is based upon the combination of the
> > traits class and the type for which you want the traits.
>
> Ok, makes sense. If that kind of behavior is expected for all models of a
> concept, it might make sense to realize it via a trait, such as
> "std::char_traits<C>::eq(const C& c1, const C& c2)."

Yep, std::char_traits has a static mf eq(), so it has behavior.
Any specialization of std::char_traits is expected to provide
that same mf unless some other aspect of that specialization
precludes equality comparison so that clients know better than to
try to use eq() in that case.

[snip]
> No, I am not excluding behavior. Some of the features in the Feature Model
> might be behavior, but when using GP in C++, one should use syntax as
> triggering the behavior, without going through traits, in my very humble

Isn't that beside the point? We're trying to figure out what
traits and policies are, not whether we should use traits for a
particular purpose.

> opinion. That is, in C++ we define a number of pseduo-syntactical
> constructs, such as "The concept Comparable has an operator '<'" and use
> that '<', without going through a trait. Had C++ been a true GP-embedding
> language, like Haskell, we could have coded that constraint directly.
>
> So, we use
>
> template<typename T>
> T min(const T& t1, const T& t2) {
> return t1 < t2 ? t1 : t2;
> }
>
> instead of
>
> template<typename T>
> T min(const T& t1, const T& t2) {
> return rob::comp_trait<T>::less(t1, t2) ? t1 : t2;
> }

If we can rely on the "normal" semantics of operator <() for T,
then that works great. If the "normal" semantics are not
appropriate, then we must identify the alternative semantics
("rob::comp_trait<T>::less() in your example).

> [snip]
> >> We use the trait as a meta function to access
> >> a policy. Simple.
> >
> > I see what you mean, but it doesn't fit prior art, at least
> > not to me.
>
> I agree, sadly.
>
> > For me, a type that unequivocally associates
> > information and yes, even behavior, with another type is a
> > traits class.
>
> For me, the trait concept is more tighly associated with a GP feature model
> and conceptual network, but I could swallow that view point, being more
> succinct and more down-to-earth C++-ish ;-), and change my semantics
> accordingly. Clean enough, in other words. The important, perhaps
> philosophical, issue is your use of "associated ... behavior," which is
> totally aligned with my view, i.e., *not*

It seems like we agree, and then you say things like this. I
don't understand the distinctions you're trying to make.

> > A type that can be injected via template
> > parameter to control the behavior of a template is a policy.
>
> Yes [but in my world of development there are also runtime policies,
> implemented via objects.]

Sure, but I'm focused on defining traits classes and policy
classes.

> > The distinction is whether all code has equal access to the
> > information (traits) or whether only a specific template has
> > the information (policy).
>
> Hmm, but what happened to the nice injective property of policies of which
> you (and I) talked?

It's still there, just implied: the specific template knows about
the policy because it's a template argument.

> > Traits are characteristics associated with another type.
>
> Ok.
>
> > Policies are imposed by any client of the template using the policy.
>
> So, you do share David A.'s view, that the usage is important?
>
> Is it fair to say that a policy is defined by its use and a trait by its
> describing characteristics of types? If so, it is fairly close to my
> original DESCRIBE/ACT dichotomy... ;)

No, I don't think you get the point I'm (feebly?) attempting to
make. A policy class may be so because it was created expressly
to be used as one among many policies for a template. A traits
class may be a policy class in the context of its use as a
template argument. However, such a class is still inherently a
traits class because it was conceived to be used "globally" by
its one name.

I'll use std::char_traits and std::basic_string to make some more
concrete points, but I'm not sure std::char_traits is a good
example of anything for my purposes!

std::char_traits is a traits class provided it is reasonable to
use it by that name throughout your code. Gennadiy, or course,
thinks that's how std::basic_string should have been implemented
in the first place. (Many would agree.) I'm not sure that many
(any?) people write code using std::char_traits by itself. If
that is true, then std::char_traits is not a traits class.

std::basic_string was implemented with a template parameter
called "traits" which is, within std::basic_string a policy
class. It just so happens that std::basic_string's "traits"
policy has the same interface, for good or ill, as
std::char_traits. Thus, std::char_traits can be used as
std::basic_string's "traits" template argument, becoming a policy
class within std::basic_string.

Phew! I don't know if I helped or hurt my cause. It is partly a
matter of intent, I guess. If the class is supposed to augment a
type with additional (meta)information, then its a traits class.
If its supposed to be used to parameterize a template in order to
affect the behavior of the template, then its a policy class. If
it serves both purposes, I'd call it a traits class. A more
important distinction, perhaps, is whether the name is well
known. A traits class is to be used by the same name in all
contexts. A policy class may be aliased by being a template
parameter and isn't supposed to be known by name for any other
purpose.

Did that help or hurt?

-- 
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