Boost logo

Boost :

From: Fernando Cacciola (fcacciola_at_[hidden])
Date: 2001-05-11 12:20:43


Bill Seymour wrote:

> >
> > OPINION: All the non-assignment operations should be functions,
> > NOT members. NEVER use members for functional operations.
> >
>
> I note that Fernando Cacciola agrees. What's the reason?
>
It's actually a matter of personal philosophy. I'll try to explain it:

Consider the relation between a class and the operations (or methods) it
supports.
IMO, there are operations that make sense only in the context of the
*particular* class and there are methods that make sense in the context of
the *class's general category*.
Although the meaning of 'class general category' is not well defined, you'll
get what I mean with the following examples:

vector, list, set, my_fancy_container are *containers*.
int,double,rational<>,decimal<> are *numbers*
point,segment,spline,polyhedra are *geometric entities*

Certainly, those categorizations are rather diffuse, but they exist and are
conceptually used when any system is designed.

Now consider the following operations:

) For containers: sort, copy
) For numbers: lexically compare (<,==,>), arithmetically operate (+-*/)
) For geometric objects: transform, draw

It is clear to me that the above operations are conceptually independent of
the particular type; that is, chances are that I write

sort(v.begin(),v.end())
if ( a < b) ...
c = div(a,b)
transform(obj), draw(obj)

thinking not about the particular classes chosen to represent the objects
but the *categories* of those objects.

Now, I know that the classification of a given operation as class-specific
or category-specific can be very ambiguous, except for the trivial cases,
but I think we should try to apply this to decimal<> because of a practical
reason I'll explain below.

I claim that every non-class-specific operation must be implemented as a
non-member (possibly friend) function. The reason should be fairly obvious:
since the operation is not class specific you can change the type of a given
variable without breaking code.

That is,

just as I can write: double a =1 , b= 2, c = a * b ; and then just change
'double' for 'float';
or vector<int> v ; ... ; sort(v.begin(),v.end()) ; and then just change
vector<int> with list<int>;
users of a user defined number class should be able to write code using
number-related-operations such as:

  b=abs(a),
  q =div(a,b).quot

and then just change money<2> with some_other_type<2>.

Notice that even if some_other_type doesn't come with a proper 'abs' or
'div' function I can always add one without changing some_other_type. I
couldn't do this if I wrote:

b = a.abs()
q = a.div(b).quot ;

OK. I know that the proposed interface supplies non-member forms of the
above, but I would actually take the member-forms away.
I would do the same with 'to_double'.

Conclusion:

I am a numerical algorithms developer, and I designed and used lots of user
defined number types over the years. I changed designs too many times.
But I learn that as a user of a custom number type, I find from time to time
a better class and I like to use it.

Whenever I write:

   a.to_double(), a.abs(), a.div(b)

   instead of

  to_double(a), abs(a), div(a,b)

I am limiting the ability to change the type as desired.

I would like the decimal<> interface to propone the non-member form for
non-class-specific operations.

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