digitalmars.D - Partial class implementation
- Robert Fraser <fraserofhtenight gmail.com> Jul 16 2007
- Tristam MacDonald <swiftcoder gmail.com> Jul 16 2007
- janderson <askme me.com> Jul 16 2007
- Robert Fraser <fraserofthenight gmail.com> Jul 16 2007
- janderson <askme me.com> Jul 16 2007
- janderson <askme me.com> Jul 16 2007
- Bill Baxter <dnewsgroup billbaxter.com> Jul 16 2007
- Reiner Pope <some address.com> Jul 17 2007
- Bill Baxter <dnewsgroup billbaxter.com> Jul 17 2007
- BCS <ao pathlink.com> Jul 17 2007
- Robert Fraser <fraserofthenight gmail.com> Jul 17 2007
Random, C#-inspired thought: It would be nice if it were possible to implement parts of classes in different modules than other parts. This would allow logical grouping of methods for a set of related classes. This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
Jul 16 2007
This might be an interesting perspective on the kind of harm such an option might cause: http://www.ddj.com/dept/cpp/184401197 Robert Fraser Wrote:Random, C#-inspired thought: It would be nice if it were possible to implement parts of classes in different modules than other parts. This would allow logical grouping of methods for a set of related classes. This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
Jul 16 2007
Tristam MacDonald wrote:This might be an interesting perspective on the kind of harm such an option might cause: http://www.ddj.com/dept/cpp/184401197 Robert Fraser Wrote:Random, C#-inspired thought: It would be nice if it were possible to implement parts of classes in different modules than other parts. This would allow logical grouping of methods for a set of related classes. This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
I thought it was possible to do something like: void foo(A a) { } ... a.foo(); I tried it out and it didn't work. Sigh, it would be awesome for many reasons if D did support this. -Joel
Jul 16 2007
That article is indeed well-reasoned, however it fails to take into account other features. In particular (this may come off as Java-fanboy nitpicking): 1. It encourages a large public interface: if functions that depend soley on the "public interface" are non-members, to achieve the same level of accessibility, the initial public interface of a class may need to be expanded. In particular the getter/setter/property pattern is encouraged by such a design, and overuse of this pattern can degrade a class to a simple aggregation of data, defeating the purpose of encapsulation entirely. 2. The architecture is less nimble for client code. If a function that at one time needed only access to the public interface later needs member access, the non-member function will become a simple proxy for the member function, or, worse, the public interface could be expanded. 3. Sending messages directly to a class is (IMO) clearer, prettier, and better for auto-complete tools & lookup (manual or go-to-definition) than a free function. But to each his own, I guess. That article certainly had some good points. That said, I was thinking about partial class implementation mainly with regards to related virtual functions (i.e. Implementing the same abstract/interface/override function across multiple subclasses all in the same file, while other parts of those clases are defined elsewhere. This will help logically group large clas hirearchies, IMO. Tristam MacDonald Wrote:This might be an interesting perspective on the kind of harm such an option might cause: http://www.ddj.com/dept/cpp/184401197 Robert Fraser Wrote:Random, C#-inspired thought: It would be nice if it were possible to implement parts of classes in different modules than other parts. This would allow logical grouping of methods for a set of related classes. This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
Jul 16 2007
Robert Fraser wrote:That article is indeed well-reasoned, however it fails to take into
nitpicking):1. It encourages a large public interface: if functions that depend
level of accessibility, the initial public interface of a class may need to be expanded.
Classes should be small and as minimal as possible. I think this is part of Meyers argument. Anything that can be placed outside the class should be. If it can't because that gives assess to something that could potentially be misused by the world outside the class, thats a case to make it a member. Therefore you get this highly easy to use class that is less bug prone. It knows what is job is, its small so its easy to maintain.In particular the getter/setter/property pattern is encouraged by such a design, and overuse of this pattern can degrade a class to a simple aggregation of data, defeating the purpose of encapsulation entirely.
This is true. I don't think the example of a point was the best example. Herb Sutter and Bjarne Stroustrup's often argue that if the class variables have not constraints (invariants) then the class should really be a C struct (where everything is public).2. The architecture is less nimble for client code. If a function that at one time needed only access to the public interface later needs member access, the non-member function will become a simple proxy for the member function, or, worse, the public interface could be expanded.
But this is a good thing. It means you either have to go back to the drawing board with the class interface or add the non-member into the interface. Its pretty easy to remove a non-member function. Its much harder to remove a function once it becomes part of a class. Note that if you want to extend a class there are other ways to do it (namely using a component). Also if you find your creating proxies, then there was probably something wrong with the design in the first place.3. Sending messages directly to a class is (IMO) clearer, prettier, and better for auto-complete tools & lookup (manual or go-to-definition) than a free function.
There is no real point in arguing this. My main argument is based on code refactorbility and design. I find free functions are much more reuseable then member functions, look at algorithms in std (find, sort ect...).But to each his own, I guess. That article certainly had some good points. That said, I was thinking about partial class implementation mainly with regards to related virtual functions (i.e. Implementing the same abstract/interface/override function across multiple subclasses all in the same file, while other parts of those clases are defined elsewhere. This will help logically group large clas hirearchies, IMO.
While I'm not against the idea. I think, its a much better idea to have lots of small cohesive component classes rather then a large class. I've seen so many large classes and I've always been able to break them down into small chunks. I must admit though it can sometimes be quicker in the short run to simply throw everything into the same class. Here's some more information: http://www.artima.com/intv/goldilocks.htmlTristam MacDonald Wrote:This might be an interesting perspective on the kind of harm such an option might cause: http://www.ddj.com/dept/cpp/184401197 Robert Fraser Wrote:Random, C#-inspired thought: It would be nice if it were possible to implement parts of classes in different modules than other parts. This would allow logical grouping of methods for a set of related classes. This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
Jul 16 2007
I want to extend what I was saying about components.
If you have a class and you want to break it up into several files based
on methods, why not use components instead. You end up with a much more
flexible design.
ie Say I have:
class Boat
{
public:
string GetName();
string GetOwner();
//ect...
point GetLocation();
point Facing();
float GetSpeed();
//ect...
};
If you went for component design you would probably do something like:
class Info
{
public:
string GetName();
string GetOwner();
//ect...
};
class PhysicsObj
{
public:
point GetLocation();
point Facing();
float GetSpeed();
//ect...
};
struct Boat
{
Info info = new Info();
PhysicsObj physicsObj = new PhysicsObj();
};
Immediately more reusable and maintainable.
Now like you said, you could use mixins. This is a nicety of D however
components offer a few advantages as well like a nice way to break up
the namespaces, are easier to refactor and allow for more cohesive code.
-Joel
Jul 16 2007
janderson wrote:Robert Fraser wrote:
There is no real point in arguing this. My main argument is based on code refactorbility and design. I find free functions are much more reuseable then member functions, look at algorithms in std (find, sort ect...).
Does that really hold true for D though? Without Koenig lookup, free functions don't have the same flexibility they do in C++. You can write generic template functions like find, sort, etc, where there is a single implementation and callers have to implement the concept it requires. But something like 'toString' as a non-member is pretty much impossible in D. --bb
Jul 16 2007
Bill Baxter wrote:janderson wrote:Robert Fraser wrote:
There is no real point in arguing this. My main argument is based on code refactorbility and design. I find free functions are much more reuseable then member functions, look at algorithms in std (find, sort ect...).
Does that really hold true for D though? Without Koenig lookup, free functions don't have the same flexibility they do in C++. You can write generic template functions like find, sort, etc, where there is a single implementation and callers have to implement the concept it requires. But something like 'toString' as a non-member is pretty much impossible in D. --bb
I didn't realise there was an issue here, before; can you tell me if this is what you are talking about? --- module a.b.c; struct A {...} string toString(A) {...} --- module a.b; import a.b.c; class B { A getInstanceOfA() {...} } --- module b; import a.b; void main() { B b = new B(); auto a = b.getInstanceOfA(); string s = toString(a); // doesn't work } --- In this case, I can see it might be a surprise that it doesn't work, but is there anything worse than that? What's wrong with just importing a.b.c and carrying on? If you did any serious manipulations of 'a', then you would have to declare the type 'A' *sometime*; so you'd end up importing a.b.c anyway... I'm just taking a guess at what you mean, though; if I'm completely off, can you please explain? -- Reiner
Jul 17 2007
Reiner Pope wrote:Bill Baxter wrote:janderson wrote:Robert Fraser wrote:
There is no real point in arguing this. My main argument is based on code refactorbility and design. I find free functions are much more reuseable then member functions, look at algorithms in std (find, sort ect...).
Does that really hold true for D though? Without Koenig lookup, free functions don't have the same flexibility they do in C++. You can write generic template functions like find, sort, etc, where there is a single implementation and callers have to implement the concept it requires. But something like 'toString' as a non-member is pretty much impossible in D. --bb
I didn't realise there was an issue here, before; can you tell me if this is what you are talking about? --- module a.b.c; struct A {...} string toString(A) {...} --- module a.b; import a.b.c; class B { A getInstanceOfA() {...} } --- module b; import a.b; void main() { B b = new B(); auto a = b.getInstanceOfA(); string s = toString(a); // doesn't work } --- In this case, I can see it might be a surprise that it doesn't work, but is there anything worse than that? What's wrong with just importing a.b.c and carrying on? If you did any serious manipulations of 'a', then you would have to declare the type 'A' *sometime*; so you'd end up importing a.b.c anyway... I'm just taking a guess at what you mean, though; if I'm completely off, can you please explain?
I think that's ok, insofar as what you've written. What you can't do is import more than one version of toString, even if they are unabmiguous w.r.t. the usual overloading rules: ---- module a; struct A { ... } string toString(A) { ... } ---- module b; struct B { ... } string toString(B) { ... } ---- import a; import b; void main() { } ---- That fails just importing the two modules, so I didn't bother actually trying to call the toString methods. The above would work fine if you had the two flavors of 'toString' all consolidated in one module. It would also work fine with 'static import' and explicit use of a.toString and b.toString. But what doesn't work is resolving an overload to different modules based on the argument type. Apparently it's a big hairy deal to implement and the bane of compiler-writers' existence. But C++ allows it. Walter believes it's not necessary, though. And so far he seems right. But it does mean you need to put some things inside classes (like toString) that could be free functions if protection levels were the only concern. --bb
Jul 17 2007
Reply to Robert,This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
IIRC this works. Or did I misread you? template Foo() { int get(){ return foo; } void set foo(int i){foo = i;} } class Bar { int foo; mixin foo!(); }
Jul 17 2007
BCS Wrote:Reply to Robert,This is already possible via template mixins (sort of, but alias template params are required to access fields), but explicit partials might be quite helpful.
IIRC this works. Or did I misread you? template Foo() { int get(){ return foo; } void set foo(int i){foo = i;} } class Bar { int foo; mixin foo!(); }
Yup; that's what I'm doing now.
Jul 17 2007









janderson <askme me.com> 