Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

One thing I'd like to do in C++ is to call non-member functions with the same syntax you call member functions:

class A { };
void f( A & this ) { /* ... */ }
// ...
A a;
a.f(); // this is the same as f(a);

Of course this could only work as long as

  • f is not virtual (since it cannot appear in A's virtual table.

  • f doesn't need to access A's non-public members.

  • f doesn't conflict with a function declared in A (A::f).

I'd like such a syntax because in my opinion it would be quite comfortable and would push good habits:

  1. calling str.strip() on a std::string (where strip is a function defined by the user) would sound a lot better than calling strip( str );.

  2. most of the times (always?) classes provide some member functions which don't require to be member (ie: are not virtual and don't use non-public members). This breaks encapsulation, but is the most practical thing to do (due to point 1).

My question here is: what do you think of such feature? Do you think it would be something nice, or something that would introduce more issues than the ones it aims to solve? Could it make sense to propose such a feature to the next standard (the one after C++0x)?


Of course this is just a brief description of this idea; it is not complete; we'd probably need to explicitly mark a function with a special keyword to let it work like this and many other stuff.

share|improve this question

migrated from stackoverflow.com Jan 17 '11 at 15:57

This question came from our site for professional and enthusiast programmers.

    
Why? You propose a syntactical change, which is severly limited and doesn't help much (at most saves one character). Don't you think C++ is complex enough already? –  delnan Jan 17 '11 at 17:11
    
Four people with the same generic icon. Ahhh them confusion yo have just caused my poor little brain. –  Loki Astari Jan 18 '11 at 1:17

6 Answers 6

up vote 16 down vote accepted

re your #2: Actually, making functions non-members often increases encapsulation, as Scott Meyers observed more than a decade ago.

Anyway, what you describe sounds much like C#'s extension methods to me. They are good to soothe the minds of those that are frightened when they see totally free functions. :) Once you've braved the STL (which, BTW, is not the standard library, but only that part of it which comes from the original STL) where almost all functions are so free that they aren't even real functions, but function templates, you will no longer need those.

In short: Don't try to bend a language to adapt to your mindset. Instead enhance your mindset to embrace the language's philosophy. You will emerge a bit taller from doing so.

share|improve this answer
1  
Yeah, that's exactly my point. Using non-member functions increases encapsulation, but most of the times, classes provide some member functions that don't need to be members, and this common practice breaks encapsulation. –  peoro Jan 17 '11 at 14:37
    
@peoro: If using non-members increases encapsulation why do you want to call them as if they were members? –  sbi Jan 17 '11 at 14:39
2  
@peoro: No, as I wrote, it's only more comfortable to those coming from so-called "pure" OO languages like Java and C#, which boggle at free function. Most will overcome this, if they persevere. When I learned C++ almost 20 years ago, developers came to C++ from C and boggled at member functions. It's a good thing they didn't adapt the syntax back then to make them more comfortable, don't you think? (Although it would be interesting to think whether languages like Java etc. would ever have been born - and what they'd look like - had C++ managed to get OO without the member function syntax.) –  sbi Jan 17 '11 at 14:45
2  
+1 for the Scott Meyers article link –  JaredC Jan 17 '11 at 14:49
4  
@peoro, @sbi: The funny thing is that those pure-OO languages end up with weird interfaces that come from the need to encapsulate everything in a class. Take a look at java.util.Collections that is a wrapper around static functions because the language (or its followers) won't even think on having free functions... Well, those are free functions in a cumbersome namespace called class Collections. –  David Rodríguez - dribeas Jan 17 '11 at 14:52

Trying to answer your points:

  1. This is just a matter of style. To you it sounds better, to someone else it sounds worse. Some languages (of Lisp heritage) define all calls as (<func name> <arguments>), is it inherently better or worse than <func name>(<arguments>)? Maybe and maybe not. Matter of style. I'm sure no one is going to consider changing the C++ standard on such considerations.
  2. This is what static members are for in C++ - are you familiar with this construct? Besides, as the C++ standard library (the STL portions thereof) demonstrates, it's possible to combine objects with non-member functions that act on them in an elegant way.
share|improve this answer
    
I'm not getting your second point. static members don't work on an instance of the class, what has it got to do with this feature? –  peoro Jan 17 '11 at 14:35
    
Static members are similar to non-member functions in that they don't get an instance (this) passed. You can invoke them on instance of the class if you want - they act like "class-specific global functions". Factories are a good example. –  Eli Bendersky Jan 17 '11 at 14:45
    
Well, a static function taking an instance of the class as their parameter is kind of the opposite of what I'm thinking about: a static function is a way to declare a somehow non-member function that can access non-public members (similar to a free friend function?). This idea is to do the opposite: allowing to declare member functions that cannot use member variables. –  peoro Jan 17 '11 at 15:00
    
@peoro: you said "to call non-member functions with the same syntax you call member functions". Now you say something else. I'm confused –  Eli Bendersky Jan 17 '11 at 15:02
    
Yes, sorry, I don't know how to call the functions I was proposing. My point is: when a function needs to do something with an object, it is usually implemented as a member function by the developer of the class. This thing breaks encapsulation (see sbi's answer), but is done anyway because it's more comfortable to call it with the syntax obj.f(); this is why I think it's done. This makes me think: a way to define a non-member function (improving encapsulation!) which can be used as obj.f() could be a solution. A static function breaks encapsulation as much as any other member function. –  peoro Jan 17 '11 at 15:09

If you want to add methods to a class, just inherit from that call and add the members to your derived class.

If you're asking how I like your syntax, I don't. Why make it look like a method is part of a class when it isn't. Especially when it's pretty straight forward to make it part of a class.

share|improve this answer
    
Member functions break encapsulation. Declaring some functions as member just to be able to do x.function() is a bad thing, and this idea is to give a way to avoid it. (Besides your first phrase introduces other issues: it might be a problem if the base class doesn't have a virtual destructor etc). –  peoro Jan 17 '11 at 14:39
1  
This is not the right approach. You should only inherit from those classes that were designed to be derived. This type of reasoning is what leads to people deriving from standard containers, and then people seeking ways to disable inheritance and what not. –  David Rodríguez - dribeas Jan 17 '11 at 14:53
1  
And on extending classes with free functions, this is a good article to read: GOTW 84 - Monoliths "Unstrung" –  David Rodríguez - dribeas Jan 17 '11 at 14:54

I believe that as part of Concepts (which were dropped from C++0x), there was something like this, but going in the opposite direction, so that nonmember syntax could be used to call member functions. In other words, given a std::vector<int> vec, this

begin(vec)

would be equivalent to calling the member function explicitly:

vec.begin();

I think that is a better approach, in that it is biased so that it prefers nonmember functions, which are the most "public" part of the interface. To some extent, member functions are an implementation detail which is likely to change more often than the typically higher-level nonmember functions that use the class.

So something like this would allow us to use the general non-member syntax for everything, and while it would implicitly fall back to calling a member function if no matching non-member function is found, it would always prefer the most public, the most encapsulated function available, which is the non-member one.

Of course, both ways can silently break code, but allowing nonmember syntax for calling member functions will at least maintain encapsulation: by adding a new function, I can convert a member function call, which has access to the private members of the class, into a non-member which does not have access to private members.

But if it was done the other way around, allowing member syntax for calling non-member functions, then I could, by adding a new function to the class, silently convert an unknown number of non-member function calls into member function calls. In other words, a lot of code which previously called a function that had no access to private members, are silently changed into calls to a function that does access private members. I think that's the more dangerous way to go.

share|improve this answer

To me it is a value to clearly be able to see whether I am making a call to a member or nonmember function.

But even if I preferred your style, what if after writing such a call a.f(...) into my code, a function f() with a compatible signature is introduced into class A? Should my code silently break upon the next recompile, calling into a totally different function than I originally intended? Should the design committee attempt to extend the (already very complex) name lookup rules to accommodate such special cases?... And what if I will have already left the company in the meantime, and it is up to my poor successor to try and decide what my original intent could be?

share|improve this answer
    
There are other problems like the one you mentioned: what if two namespaces provide a non-member function f to be called with the syntax object.f on objects of the same type? If I decide this idea could be worth something I'll try to find out solutions. The simplest idea for your case is just to give an error at compile time: it's exactly like a symbol conflict; namespaces will help us. –  peoro Jan 17 '11 at 14:45

I think it's an excellent idea because of ADL and the operator overloading mess- make operators pseudo-members, ditch ADL. Extension methods like this wouldn't change encapsulation because they're still an exterior function, they just have the syntax of an interior function.

There are some functions that do well to be free, and some functions that do well to be members- even if they're free from an encapsulation point of view.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.