Boost logo

Boost :

From: Rob Stewart (stewart_at_[hidden])
Date: 2004-04-05 08:44:52


From: Robert Bell <belvis_at_[hidden]>
> Gennadiy Rozental wrote:
>
> > Here is how I see it. Trait is something type specific, IOW specific
> > to type, IOW uniquely defined by type. If you could provide trait
> > along with the type as a template parameter, that mean you could
> > change it independently from the type, IOW you could define different
> > value for trait still using the same type. For example if you have
> > component C defined like:
> >
> > template<typename T, typename Trait>
> > struct C { ... };
> >
> > You could instantiate it like C<MyT,TraitValue1> or
> > C<MyT,TraitValue2>. So as you could see trait value is not uniquely
> > defined by the type.
>
> So what? The only thing I'm getting from this as to why traits should be
> "uniquely defined by the type" is because you've defined traits that
> way. But I don't see why traits have to be defined that way. I don't see
> what bad thing happens if C is defined as above.

If trait is synonymous with policy, then why have both? When
policies hit the scene, they were like "traits on steroids," as
Andrei put it. They pushed the envelope in terms of what a
traits class could be used to do. The result, however, didn't
look like the traits class stuff that had been used prior to that
point, save for std::char_traits in the likes of
std::basic_string.

As a result, I think we wound up with something new, not just a
slight variation on the status quo. Thus, a traits class is one
that can be specialized for various types, but is always known by
one name in all uses. By contrast, a policy class is one passed
as a template argument for use specifically to alter behavior
according to predefined points of customization.

> > Proper design would be to have trait stand alone class, like this:
> >
> > template<typename T>
> > struct Trait { value = ... };
> >
> > template<typename T>
> > struct C { here we are using Trait<T>::value, where we used to use
> > Trait. };
> >
> > Now if the user needs to define trait value (or change from using
> > default value provided by most traits designs), she just need to
> > define explicit/partial specialization for this type or types family.
>
> Unless, as someone else pointed out, there already exists such a
> specialization.
>
> > On the other hand policy is something that is orthogonal to the
> > primary type (actually in policy based design there may not be any
> > primary type, but just an orthogonal policies), IOW you could use
> > different policies in conjunction with the same type. And natural
> > place for the policy is along with type in component definition among
> > the template parameters.
>
> You seem to be arguing that
>
> template<typename T, typename U = traits<T> >
> class Foo { };
>
> is wrong because it blurs the distinction between traits and policies. I

I think Gennadiy would agree that this is fine because U is a
policy template parameter defined to use at least a subset of
traits' interface. If U isn't well-defined and traits becomes
the definition of U, even though Foo doesn't use all of traits'
interface, then the design of Foo is poor. That would seem to be
the case with std::basic_string and std::char_traits. I haven't
looked at the implementation with this in mind, but I'm guessing
that std::basic_string doesn't use all of std::char_traits
interface, and yet the "traits" parameter of std::basic_string
isn't defined separately.

> say "so what?" If the problem is best solved by blurring these ideas,
> blur away. No one seems to have yet been able to define "traits" and
> "policies" very well anyway, so what are we blurring?

*If* there is value, as I of course think there is, in
maintaining a distinction for accuracy in discourse, then we're
needlessly combining separate notions. If few think the
distinction is important, then we should simply choose one or the
other term to avoid confusion.

> On 1/3/2004, you wrote
>
> > I've expressed my opinion in the matter before: Traits - as name
> > suggest could not be policy. IOW should not be template parameters.
> > Traits are type specific and an ability to supply them independently
> > to the primary type in most cases leads to invalid/too complicated
> > design.
>
> The way I read this, your use of "most cases" means you agree there are
> some cases where the above use of traits passed into a template is
> justified and acceptable. This seems to contradict the idea above that
> traits can never be used this way. Can you clarify please?

If an existing traits class provides (at least) the interface
needed for a template's policy class, then using the traits class
as that policy should be fine. The fact that the template
parameter is a policy means that the template is allowing for
other implementations of that interface. That doesn't make the
traits class any less the one definition of those traits. Put
another way, any other classes implemented to be used as the
template's policy argument won't be used as traits; they'll only
be used as the template's arguments.

The distinction provides some clarity when using the phrases
"traits class" or "policy class." When someone says "policy
class," you immediately know that they mean something passed as a
template argument or the template parameter used within the
template to effect behavioral changes. When someone says "traits
class," you immediately know that they mean something
customizable for each distinct type, but not for each template
wishing to use it. Those are quite different things and
disambiguiating them via different names is sensible.

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