
From: "David Bergman" <davidb@home.se>
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@sig.com Software Engineer http://www.sig.com Susquehanna International Group, LLP using std::disclaimer;