digitalmars.D - Free functions versus member functions
- Walter Bright (18/30) Oct 10 2007 fact
- Bill Baxter (13/49) Oct 10 2007 From the fine article:
- Walter Bright (4/16) Oct 10 2007 I think Herb was talking about ADL. D doesn't have ADL, but the next
- Kris (3/6) Oct 10 2007 Does D + ADL == ADD ?
- Walter Bright (2/10) Oct 10 2007 Nope. O.D.D.
- janderson (8/44) Oct 10 2007 I'm sure you Walter have read these but for anyone else:
- Kris (24/56) Oct 10 2007 Yes, that perspective resonates, though I tend to use the term 'client
- Regan Heath (4/15) Oct 11 2007 What about D's modules or packages, aren't they the equivalent of a
- Chad J (49/54) Oct 11 2007 I'm not sure about namespaces, but one thing that putting stuff in
- Jarrett Billingsley (13/25) Oct 11 2007 You might already know about this, but D already has a way to force the ...
- Bill Baxter (24/39) Oct 11 2007 Two big differences with D's modules and C++ namespaces
- Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= (6/19) Oct 11 2007 I haven't been using C++ lately, but isn't 'using namespace' similar to ...
- BCS (4/18) Oct 11 2007 As I understand it the difference is that in D you can't access somthing...
- Jari-Matti =?ISO-8859-1?Q?M=E4kel=E4?= (5/24) Oct 11 2007 Well, yes. But in C++ you still need #include the definition some way fi...
- Bill Baxter (6/29) Oct 11 2007 Maybe, assuming the imports could be repeats of already imported
- Kevin Bealer (6/40) Oct 10 2007 I like Meyer's point here. My view is that classes provide the followin...
- janderson (21/40) Oct 11 2007 make such decisions, and backs it up with reasoning that I find compelli...
- Bruno Medeiros (27/45) Oct 13 2007 I don't think I fully agree with some points of that article. He states
- =?ISO-8859-1?Q?R=e9my_Mou=ebza._?= (19/67) Oct 13 2007 API building can sometimes lead to classes that have methods quite unrel...
- Kevin Bealer (9/58) Oct 14 2007 There is an advantage to it, in that non-member function list needs to c...
- Daniel Keep (17/23) Oct 14 2007 Yes, Walter calls it "uniform function call syntax" or somesuch. Basica...
- Janice Caron (5/10) Oct 14 2007 Almost equivalent? Correct me if I'm wrong, but the former is capable
- Daniel Keep (9/25) Oct 15 2007 Equivalent from the point of view of the person using it. They're
Continuing the discussion from the thread "questions on PhanTango 'merger'": Lars Ivar Igesund wrote:It is not as if such functions are non-existant in Tango, so which exact functionality do you think is better expressed through free standing functions rather than objects? The answers of others shows that this usually is wanted for objects where you often need only one operation on the given object, even if others are available. This don't remove thefactthat an object (class) equally often is a useful abstraction, andwhen thatis established, free standing functions usually should be implemented as wrappers around each method on the object, rather than the object being implemented via free standing functions. This is why Tango looks asit doestoday; we have avoided wrappers of our own code if possible, because they degrade orthogonality of the API, and add more code to maintain.Whether wehave been to strict in enforcing that stance, is an open question.I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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>
Oct 10 2007
Walter Bright wrote:Continuing the discussion from the thread "questions on PhanTango 'merger'": Lars Ivar Igesund wrote: > It is not as if such functions are non-existant in Tango, so which exact > functionality do you think is better expressed through free standing > functions rather than objects? The answers of others shows that this > usually is wanted for objects where you often need only one operation on > the given object, even if others are available. This don't remove the fact > that an object (class) equally often is a useful abstraction, and when that > is established, free standing functions usually should be implemented as > wrappers around each method on the object, rather than the object being > implemented via free standing functions. This is why Tango looks as it does > today; we have avoided wrappers of our own code if possible, because they > degrade orthogonality of the API, and add more code to maintain. Whether we > have been to strict in enforcing that stance, is an open question. I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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>From the fine article: """ Herb Sutter has explained that the "interface" to a class (roughly speaking, the functionality provided by the class) includes the non-member functions related to the class, and he's shown that the name lookup rules of C++ support this meaning of "interface" [7,8]. """ Do D's name lookup rules similarly support that meaning of "interface"? (I'm not sure what the Herb was talking about but I'm guessing he meant things like preferring the most-derived type for overloads and argument dependent lookup.) --bb
Oct 10 2007
Bill Baxter wrote:From the fine article: """ Herb Sutter has explained that the "interface" to a class (roughly speaking, the functionality provided by the class) includes the non-member functions related to the class, and he's shown that the name lookup rules of C++ support this meaning of "interface" [7,8]. """ Do D's name lookup rules similarly support that meaning of "interface"? (I'm not sure what the Herb was talking about but I'm guessing he meant things like preferring the most-derived type for overloads and argument dependent lookup.)I think Herb was talking about ADL. D doesn't have ADL, but the next update will include "overload sets" which, although very different, accomplish the same thing.
Oct 10 2007
"Walter Bright" <newshound1 digitalmars.com>I think Herb was talking about ADL. D doesn't have ADL, but the next update will include "overload sets" which, although very different, accomplish the same thing.Does D + ADL == ADD ? :p
Oct 10 2007
Kris wrote:"Walter Bright" <newshound1 digitalmars.com>Nope. O.D.D.I think Herb was talking about ADL. D doesn't have ADL, but the next update will include "overload sets" which, although very different, accomplish the same thing.Does D + ADL == ADD ? :p
Oct 10 2007
Walter Bright wrote:Continuing the discussion from the thread "questions on PhanTango 'merger'": Lars Ivar Igesund wrote: > It is not as if such functions are non-existant in Tango, so which exact > functionality do you think is better expressed through free standing > functions rather than objects? The answers of others shows that this > usually is wanted for objects where you often need only one operation on > the given object, even if others are available. This don't remove the fact > that an object (class) equally often is a useful abstraction, and when that > is established, free standing functions usually should be implemented as > wrappers around each method on the object, rather than the object being > implemented via free standing functions. This is why Tango looks as it does > today; we have avoided wrappers of our own code if possible, because they > degrade orthogonality of the API, and add more code to maintain. Whether we > have been to strict in enforcing that stance, is an open question. I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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'm sure you Walter have read these but for anyone else: I like this interview with Bjarne Stroustrup. I think it explains it reasonably well. http://www.artima.com/intv/goldilocks3.html Also Hurb Sutters book "C++ Coding Standards" as a good explanation: http://www.gotw.ca/publications/c++cs.htm Its actually the official "coding style guide" where I work. -Joel
Oct 10 2007
Yes, that perspective resonates, though I tend to use the term 'client functions' to describe what Scott is calling non-member functions. There's some specific interest here with regard to D: 1) the Widget factory example is less clear in D, due to that lack of an equivalent 'namespace' mechanism. This is why such methods tend to reside inside the respective class/struct in D. Yes, one could perhaps use "import as" instead, but that would tend to muddy usage further. I think this indicates a minor annoyance with the D namespace mechanism. One that's bothered me from time to time <g> 2) the section on "syntax issues" is something that D, on the other hand, is fairly adept at: the support for "flip that outside left-hand reference into the first argument instead", which people got excited about regarding arrays, does help to maintain syntactic symmetry. That's assuming you can avoid namespace collisions in the process. As I understand it, some of the changes in D v2 are intended to address that latter concern? The interesting thing overall is this: what Scott describes has minimal bearing on the concerns within Tango, since we've mostly been attuned to the client/member issue from the beginning. Where we do currently deviate, it is Having said that, and assuming I correctly understand some of the comments made about Tango (over the last year), perhaps Tango just doesn't have sufficient 'client' functions? "Walter Bright" <newshound1 digitalmars.com> wrote in message news:feju2r$1nsn$1 digitalmars.com...Continuing the discussion from the thread "questions on PhanTango 'merger'": Lars Ivar Igesund wrote:It is not as if such functions are non-existant in Tango, so which exact functionality do you think is better expressed through free standing functions rather than objects? The answers of others shows that this usually is wanted for objects where you often need only one operation on the given object, even if others are available. This don't remove thefactthat an object (class) equally often is a useful abstraction, andwhen thatis established, free standing functions usually should be implemented as wrappers around each method on the object, rather than the object being implemented via free standing functions. This is why Tango looks asit doestoday; we have avoided wrappers of our own code if possible, because they degrade orthogonality of the API, and add more code to maintain.Whether wehave been to strict in enforcing that stance, is an open question.I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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>
Oct 10 2007
Kris wrote:Yes, that perspective resonates, though I tend to use the term 'client functions' to describe what Scott is calling non-member functions. There's some specific interest here with regard to D: 1) the Widget factory example is less clear in D, due to that lack of an equivalent 'namespace' mechanism. This is why such methods tend to reside inside the respective class/struct in D. Yes, one could perhaps use "import as" instead, but that would tend to muddy usage further. I think this indicates a minor annoyance with the D namespace mechanism. One that's bothered me from time to time <g>What about D's modules or packages, aren't they the equivalent of a namespace? If not, what do they lack? Regan
Oct 11 2007
Regan Heath wrote:What about D's modules or packages, aren't they the equivalent of a namespace? If not, what do they lack? ReganI'm not sure about namespaces, but one thing that putting stuff in structs/classes does is it forces users to state where the functions/data they are using comes from. It's forced FQN (Fully Qualified Name) syntax in a sense. It is nicer than just using module-based FQN because Stdout.formatln() is shorter than tango.io.Stdout.formatln() and still gets the point across. It would be nice to be able to write stdio.writefln(), which wouldn't lose much since it is very unlikely that there will be a series of imports like so: std.stdio; somelib.stdio; somelib.subpackage.stdio; In above such cases, well, too bad. Someone trying to figure out where stdio.writefln came from will just have to look it up. I may have just conflated two things unfortunately: compulsory FQN vs. voluntary FQN is one, and the other is the notion of a partially qualified name (PQN?). Currently D modules are voluntary FQN, while structs/classes act as compulsory PQN. Another thing that makes me tend to throw things into structs and classes is that private-is-visible. Consider this: //main.d import std.stdio; import primary; import secondary; void main() { writefln( generate() ); } // primary.d public char[] generate() { return "Hello from primary!"; } // secondary.d private char[] generate() { return "Hell from secondary!"; } Compiling the above code results in the following error: main.d(7): Error: primary.generate at primary.d(2) conflicts with secondary.generate at secondary.d(2) When I declare something private, I generally don't want it to affect anything in other modules, at all. Other modules do get affected in D, in the form of compiler errors, but a similar effect can be gained by just throwing things into structs or classes. This has been discussed before. I remember Walter liking it this way. It was to allow people to "poison" certain function overloads. It's a small thing, but annoying.
Oct 11 2007
"Chad J" <gamerChad _spamIsBad_gmail.com> wrote in message news:fel0ol$tnn$1 digitalmars.com...It would be nice to be able to write stdio.writefln(), which wouldn't lose much since it is very unlikely that there will be a series of imports like so: std.stdio; somelib.stdio; somelib.subpackage.stdio; In above such cases, well, too bad. Someone trying to figure out where stdio.writefln came from will just have to look it up. I may have just conflated two things unfortunately: compulsory FQN vs. voluntary FQN is one, and the other is the notion of a partially qualified name (PQN?). Currently D modules are voluntary FQN, while structs/classes act as compulsory PQN.You might already know about this, but D already has a way to force the use of module-level FQNs and a way to rename modules when importing them: static import foo; // all members have to be accessed as foo.* import stdio1 = somelib.stdio; import stdio2 = somelib.subpackage.stdio; // Now you can access stdio1.* and stdio2.* The only somewhat annoyting part about this is that you have to do something _at import time_, something whith can't be enforced by the library that's being imported. I think it might be nicer if you could, at the very least, declare a module itself as static (static module foo; for the above example), and when you import it, it's automatically a static import.
Oct 11 2007
Regan Heath wrote:Kris wrote:Two big differences with D's modules and C++ namespaces 1) A single C source file can have any number of (possibly nested) namespaces 2) A single namespace can be split across parts of lots of files The result is that C++ namespaces are usually used to represent bigger collections of functionality. Like "IO" or "Net". Not IO.Conduit.BufferedNosePicker They're used more for package-level scoping than module-level. I don't think I have ever seen C++ code that uses a 1-file per 1-namespace mapping. You certainly could do that with C++, but there is just no reason to. Another difference is that in C++ you have to *explicitly* say you want to bring members of a namespace into your current namespace with a "using" directive. In contrast, D's imports throw all the symbols into the local namespace by default. You have to do something extra to prevent it ("static import" instead of import). "Using" is also a nice tool for manipulating visibility of namespaces. D doesn't have anything quite like it. You can say at the function level for instance "using SomeNamespace" and then you can use things from that namespace unqualified, but just to the end of that function. There's also a renamed using -- something like "using SNS = SomeNamespace;" I think. --bbYes, that perspective resonates, though I tend to use the term 'client functions' to describe what Scott is calling non-member functions. There's some specific interest here with regard to D: 1) the Widget factory example is less clear in D, due to that lack of an equivalent 'namespace' mechanism. This is why such methods tend to reside inside the respective class/struct in D. Yes, one could perhaps use "import as" instead, but that would tend to muddy usage further. I think this indicates a minor annoyance with the D namespace mechanism. One that's bothered me from time to time <g>What about D's modules or packages, aren't they the equivalent of a namespace? If not, what do they lack?
Oct 11 2007
Bill Baxter wrote:Another difference is that in C++ you have to *explicitly* say you want to bring members of a namespace into your current namespace with a "using" directive. In contrast, D's imports throw all the symbols into the local namespace by default. You have to do something extra to prevent it ("static import" instead of import).I haven't been using C++ lately, but isn't 'using namespace' similar to D import - it imports all symbols from the namespace. Explicit syntax is nameSpace::symbol IIRC."Using" is also a nice tool for manipulating visibility of namespaces. D doesn't have anything quite like it. You can say at the function level for instance "using SomeNamespace" and then you can use things from that namespace unqualified, but just to the end of that function. There's also a renamed using -- something like "using SNS = SomeNamespace;" I think.Well isn't this what has been proposed for D already, i.e. imports inside non-module level scopes.
Oct 11 2007
Reply to Jari-Matti Mäkelä,Bill Baxter wrote:As I understand it the difference is that in D you can't access somthing without an import. In C++ you can access it, but you need the FQN if you don't use using.Another difference is that in C++ you have to *explicitly* say you want to bring members of a namespace into your current namespace with a "using" directive. In contrast, D's imports throw all the symbols into the local namespace by default. You have to do something extra to prevent it ("static import" instead of import).I haven't been using C++ lately, but isn't 'using namespace' similar to D import - it imports all symbols from the namespace. Explicit syntax is nameSpace::symbol IIRC.
Oct 11 2007
BCS wrote:Reply to Jari-Matti Mäkelä,Well, yes. But in C++ you still need #include the definition some way first. The only difference is C++ and D have different kinds of mappings between namespaces and files. I guess you could get similar behavior by also extending import to import subscopes inside a module.Bill Baxter wrote:As I understand it the difference is that in D you can't access somthing without an import. In C++ you can access it, but you need the FQN if you don't use using.Another difference is that in C++ you have to *explicitly* say you want to bring members of a namespace into your current namespace with a "using" directive. In contrast, D's imports throw all the symbols into the local namespace by default. You have to do something extra to prevent it ("static import" instead of import).I haven't been using C++ lately, but isn't 'using namespace' similar to D import - it imports all symbols from the namespace. Explicit syntax is nameSpace::symbol IIRC.
Oct 11 2007
Jari-Matti Mäkelä wrote:Bill Baxter wrote:Maybe, assuming the imports could be repeats of already imported modules. But anyway, proposed and implemented are very different things. People have also proposed that D compilers should be able compile C++ code directly. --bbAnother difference is that in C++ you have to *explicitly* say you want to bring members of a namespace into your current namespace with a "using" directive. In contrast, D's imports throw all the symbols into the local namespace by default. You have to do something extra to prevent it ("static import" instead of import).I haven't been using C++ lately, but isn't 'using namespace' similar to D import - it imports all symbols from the namespace. Explicit syntax is nameSpace::symbol IIRC."Using" is also a nice tool for manipulating visibility of namespaces. D doesn't have anything quite like it. You can say at the function level for instance "using SomeNamespace" and then you can use things from that namespace unqualified, but just to the end of that function. There's also a renamed using -- something like "using SNS = SomeNamespace;" I think.Well isn't this what has been proposed for D already, i.e. imports inside non-module level scopes.
Oct 11 2007
Walter Bright Wrote:Continuing the discussion from the thread "questions on PhanTango 'merger'": Lars Ivar Igesund wrote: > It is not as if such functions are non-existant in Tango, so which exact > functionality do you think is better expressed through free standing > functions rather than objects? The answers of others shows that this > usually is wanted for objects where you often need only one operation on > the given object, even if others are available. This don't remove the fact > that an object (class) equally often is a useful abstraction, and when that > is established, free standing functions usually should be implemented as > wrappers around each method on the object, rather than the object being > implemented via free standing functions. This is why Tango looks as it does > today; we have avoided wrappers of our own code if possible, because they > degrade orthogonality of the API, and add more code to maintain. Whether we > have been to strict in enforcing that stance, is an open question. I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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. 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. 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
Oct 10 2007
Kevin Bealer wrote:Walter Bright Wrote:http://www.ddj.com/cpp/184401197I eventually ran across this article by Scott Meyersmake such decisions, and backs it up with reasoning that I find compelling.which made a lot of sense. It gives some good guidelines to use tofunctions in C, to all member functions in C++, and now back to free functions? <g>Isn't it funny how we've completed the circle? We went from all freeI 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.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.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?)KevinPerhaps 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
Oct 11 2007
Walter Bright wrote:Continuing the discussion from the thread "questions on PhanTango 'merger'": I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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 don't think I fully agree with some points of that article. He states that a function that can be implemented as a "non-friend non-member" function instead of a member function, should be implemented that way, since it would reduce encapsulation. Well, sorta. Just because a function is written as a member function doesn't mean we have to access the classes fields directly in that function, one can use the class's external API just as if the function was non-member, and thus have no decrease in encapsulation. Second, I think that many times it is useful to have as part of the class API certain utility functions (that are not part of the minimal set and as such could be implemented as free functions), simply because they would be commonly useful. He mentions this aspect in the end of the article, but he gives the impression that he thinks including such functions is only worthwhile in rare occasions, and that classes should always have the minimal set of members, or close to it. I on the other hand think that most functions that could be expected to be used often should be part of the API. For instance, consider the IPath class of Eclipse: http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IPath.html It's a class that represents a path name: a collections of path segments plus a device id. I think that class API/interface is ideally defined in terms of number of member functions, but according to Meyers, the class should have a lot less member functions. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Oct 13 2007
API building can sometimes lead to classes that have methods quite unrelated to what the objects are intended for, just because we need some utility functions to be used with them. Traits (as in http://www.iam.unibe.ch/~scg/Research/Traits/) have been suggested to address this problem. From what I understood we could use mixin template class to add utility behaviour to a class ,in D. This would allow us to keep a minimalistic set of members in a class and create new ones with reusable units of utility behaviour. This also leads to simpler inheritance hierarchies. Here is what it could look like: interface SomeConstraints { // define some methods/properties requires for the trait to work } class Behaviour ( T : SomeConstraints ): T { // a traits is a stateless set of reusable methods and should only have methods. void extendedOperation (); } class Basic : SomeConstraints { // methods ; } void main () { Basic polymorphicBasic = new Behaviour !( Basic )( args, ... ); polymorphicBasic.extendedOperation (); } Currently constructors are not inherited (unless I am not up to date) and adding behaviours using this kind of code would not be easy without default constructors. Bruno Medeiros Wrote:Walter Bright wrote:Continuing the discussion from the thread "questions on PhanTango 'merger'": I've been stumped by this design issue before. Should functionality be done as a set of free functions, or as member functions? I remember going over this with Matthew Wilson, and he resolved it by implementing two parallel sets of interfaces: one free, the other member. I thought that doing both was a copout, but couldn't figure out which one was right. 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 don't think I fully agree with some points of that article. He states that a function that can be implemented as a "non-friend non-member" function instead of a member function, should be implemented that way, since it would reduce encapsulation. Well, sorta. Just because a function is written as a member function doesn't mean we have to access the classes fields directly in that function, one can use the class's external API just as if the function was non-member, and thus have no decrease in encapsulation. Second, I think that many times it is useful to have as part of the class API certain utility functions (that are not part of the minimal set and as such could be implemented as free functions), simply because they would be commonly useful. He mentions this aspect in the end of the article, but he gives the impression that he thinks including such functions is only worthwhile in rare occasions, and that classes should always have the minimal set of members, or close to it. I on the other hand think that most functions that could be expected to be used often should be part of the API. For instance, consider the IPath class of Eclipse: http://help.eclipse.org/help32/index.jsp?topic=/org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/runtime/IPath.html It's a class that represents a path name: a collections of path segments plus a device id. I think that class API/interface is ideally defined in terms of number of member functions, but according to Meyers, the class should have a lot less member functions. -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Oct 13 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. -JoelI 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
Oct 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?) KevinYes, 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
Oct 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.
Oct 14 2007
Janice Caron wrote:On 10/15/07, Daniel Keep <daniel.keep.lists gmail.com> wrote: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. :) -- DanielBasically: 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.
Oct 15 2007