Thread overview
Re: Free functions versus member functions
Oct 14, 2007
Kevin Bealer
Oct 14, 2007
Daniel Keep
Oct 14, 2007
Janice Caron
Oct 15, 2007
Daniel Keep
October 14, 2007
janderson Wrote:

> Kevin Bealer wrote:
>  > Walter Bright Wrote:
>  >>
>  >> I eventually ran across this article by Scott Meyers
> http://www.ddj.com/cpp/184401197
>  >> which made a lot of sense. It gives some good guidelines to use to
> make such decisions, and backs it up with reasoning that I find compelling.
>  >>
>  >> Isn't it funny how we've completed the circle? We went from all free
> functions in C, to all member functions in C++, and now back to free
> functions? <g>
>  >
>  > I like Meyer's point here.  My view is that classes provide the
>  > following added value: they let you define a bunch of operations
>  > without defining how they specifically will work.
>  >
>  > The example I think of is what I believe are two mistakes in the C++
>  > STL, the first is 'sort'.  I think it "should" be a member function,
>  > as vector::sort and list::sort have to be done differently for
>  > efficiency reasons.
> 
> I've found sort as a non-member function quite useful when I needed to change the code from a std::vector to a standard C array.  A nice thing about non-member functions is they can work with privative types too.

Me too; now that I think about it there is also the nice aspect that you can sort part of an array/list/vector with it.

>  > They give us the efficiency by making list::sort a member and vector
>  > can be sorted with sort(v.begin(), v.end()).  But I think that's a
>  > mistake, since you can't write a good template that calls x.sort()
>  > and expect it to do the best thing.
> 
> 
> I'm not sure what you what you are getting at here.  I don't think a member function list::sort was a good idea.

There is an advantage to it, in that non-member function list needs to copy values but member function list can just switch pointers.  This is important for a list of strings if you don't want the strings to be moved, or if you want to keep an iterator to a particular value from before to after the move.

I've never tested the difference in speed so I don't know how important this is, but I think sort() can sometimes take advantage of internal features of a class.  That said, having both member and non-member seems okay to me (for this case).

But speed depends on the type T (as in vector<T>) as well.  For some types, list<T>::sort might be faster and for others, vector<T>::sort.  I seem to recall testing set<T> versus vector<T>::sort to see which worked faster and finding that one worked faster if T was int, and the other if T was string.

(Just one implementation of course.)

>  > The other mistake (I think) is in the other direction, which is the
> 'extra' members that classes like string and vector have that give them
> personalities. For example, methods like "push_back()" and "rfind()"
> could be implemented externally for both string and vector, and it would
> result in less complexity AND more capability. (Maybe they wanted
> something like Boyer-Moore for string's find() related code?)
>  >
>  > Kevin
>  >
> 
> Perhaps these could be external however it would probably restrict optimizations and verifications that can be applied to these (without exposing more of the class then you need too).  However it does seem odd to have find functions in 2 different places and my pet peeve with STL is that it has low discover-ability.
> 
> -Joel

I guess what I'm thinking is that find(a.begin(), a.end(), value) could be written, and string::find(...) could also be written.  If the most efficient find() is the external one, then string::find() could just use that.  If not, it can use an different internal version.

My thinking is that users wanting speed can say s.find(...) and users wanting flexibility could say find(x.begin(), x.end(), ...) where x is any type.  Maybe there's a nicer way to do this (I guess people use template specializations?)

Kevin

October 14, 2007

Kevin Bealer wrote:
> I guess what I'm thinking is that find(a.begin(), a.end(), value) could be written, and string::find(...) could also be written.  If the most efficient find() is the external one, then string::find() could just use that.  If not, it can use an different internal version.
> 
> My thinking is that users wanting speed can say s.find(...) and users wanting flexibility could say find(x.begin(), x.end(), ...) where x is any type.  Maybe there's a nicer way to do this (I guess people use template specializations?)
> 
> Kevin
> 

Yes, Walter calls it "uniform function call syntax" or somesuch.  Basically:

  s.find(...)

and

  find(s, ...)

become equivalent.  This means that you can have a global find functions like thus:

  size_t find(T,U)(T collection, T thing_to_find) { ... }
  size_t find(T)(ICollection collection, T thing_to_find) { ... }

And optimised member functions for particular implementations

  struct CrazyCollection(T)
  {
    size_t find(T thing_to_find) { ... }
  }

And they all get invoked the same way.  The user no longer has to care where the function was written, just that it exists.

	-- Daniel
October 14, 2007
On 10/15/07, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
> Basically:
>
>   s.find(...)
>
> and
>
>   find(s, ...)
>
> become equivalent.

Almost equivalent? Correct me if I'm wrong, but the former is capable of polymorphism while the latter isn't?

I think this uniform call syntax idea is /brilliant/, by the way. I'm all in favor it. Just being clear here.
October 15, 2007

Janice Caron wrote:
> On 10/15/07, Daniel Keep <daniel.keep.lists@gmail.com> wrote:
>> Basically:
>>
>>   s.find(...)
>>
>> and
>>
>>   find(s, ...)
>>
>> become equivalent.
> 
> Almost equivalent? Correct me if I'm wrong, but the former is capable of polymorphism while the latter isn't?
> 
> I think this uniform call syntax idea is /brilliant/, by the way. I'm all in favor it. Just being clear here.

Equivalent from the point of view of the person using it.  They're *obviously* not equivalent in how they're implemented, where they're kept, or how they're mangled.

I just didn't want to do a Raymond Chen and write the long, boring disclaimer where I precisely qualify every thing I said that could potentially be misinterpreted.

I really don't have the patience for that.  :)

	-- Daniel