Partial class implementation

janderson askme at me.com
Wed Jul 18 22:39:17 PDT 2007


Robert Fraser wrote:
> janderson Wrote:
> 
>> 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.
>>
> 
> I agree so far...
> 
>>> 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).

> 
> I disagree here, because you are making the assumption that there
> will
never be a need to refactor (with D's property syntax, this is somewhat
mitigated since a public field can be turned into a method without
breaking client code, however if something that was a stack-allocated
class later needs to be given dynamic dispatch, this is not as much as
possibility).

Your right that this is a difference from C++ and D.  However its still 
possible to make the struct a component of a class.  That way you still 
keep the functionality of the struct.  Actually this is the recommend 
way of solving that problem in C++.


> 
> Further, however, this mindset encourages thinking of classes/structs
> 
> as aggregations of data. For a better example than a point, think about
> an AST node in a compiler (what I was thinking about when I wrote the
> OP, though now we're pretty off-topic). A generalized AST node will have
> a set of children and a parent, and a subclass implementing a
> conditional expression may have a condition, a then expresson and an
> else expression. It's possible that all this should be properties with
> getters and setters. However, if you think more deeply about it (I'd
> suggest staring at a picture of a bonsai tree...), the parent,
> condition, then expression and else expression will only be set once,
> and, depending on how you generate the tree, this may be at construction
> time. So, having setters for these properties is unnecessary and
> potentially dangerous if other coders will be using your class.

Yes this is a reasonable example.  The use of getters/setters is useful 
for restricting use of the data to prevent bugs.  Its also useful for 
changing the integrals of the object but keeping the same interface. 
For instance if you decide that you wish to change your internal matrix 
representation to a quaternion and a vector.

A great thing about D (and C#) is that you can add them properties later.

> 
> In fact, very few classes I write have explicit
> getters/setters/properties. Classes, IMO, are aggregations of methods,
> not data, and the data serves to hold state relating to invocations of
> those methods.
> 
> Which, I guess, is the main philosophical difference between the ways
> we approach defined types. I (coming from a Java/C# background), quite
> simply don't use free functions except in very rare situations where
> they don't fit within a class. There's room for two different kinds of
> programmers in this world.

Although you can simulate free functions in these languages they don't 
make it easy.  In my option its not wrong to use a highly OO techniques 
can get you where u want to go.  However if you have a multi-paradigm 
language like D or C++ you can take advantage of both sides.

> 
>>> 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).
> 
> Why is it easier to remove a non-member function than a member
> function? Client code relying on the function will break either way.

1) free-functions are not tied to their data types.  You can easily 
change the parameters to meet the goals of the function.  For instance 
if you decide you don't need that class anymore, you may still beable to 
change the function to something without that class.

2) Consider a function that takes 2 or more classes, which object does 
it belong to?

3) Templates are a great example of the reusabilty of free functions. 
It should be possible to replace any free-function with a template or 
overload (one nasty thing about D is you have to either create different 
names for overloads or alias them in).

4) When you inherit from a class if you have a lot of publics that 
should be free functions then your going to have to maintain them in the 
child class as well. (I also recommend not using inheritance for reuse, 
but for polymorphic type operations.)

5) Putting a method inside a class gives you access to all of its 
private data.  Now if you choose to go completely though the public data 
  and are rigorous about that then the class will be less error prone 
because your sub-set of methods you call should be really solid. However 
how do you tell which is your subset if they are all in the same class? 
  How do ensure that a method doesn't suddenly .  Free functions 
automatically have this constraint.  When you've got a solid subset that 
you don't have to worry about that abstraction any more.

6) Adding member functions that really should be free functions will 
increase the size of the class.  Its harder to unit test large classes.

7) You can't take the class and use it in another project so easily 
because the member-functions (which should be free) may be coupling it 
to other things.

There's a couple of more points I think I've missed.  If you want an in 
depth look into this I'd recommend Exceptional C++ by Herb Sutter.


--
Now I should point out like I said before, if you don't have access to 
the internals of a class because they are being protected for integrity 
reasons (this is a good thing) then it should be private.

> 
>> Also if you find your creating proxies, then there was probably 
>> something wrong with the design in the first place.
> 
> Initially, yes. But if you're refactoring your code and something
> that  was a free function needs to become a method (needs access to private
> members), what other choice do you have (if client code is already using
> the function)?

Normally this would only occur of the interface of the class changes. 
If the interface of the class does change you'll be told about possible 
issues like this from the compiler.  If it was inside the class, its 
possible the code code may become invade without your knowledge (since 
it seems like a reasonable large change to the interface of the class).

You can as you suggested always write a wrapper if necessary.  However a 
free-function will normally be doing more then a simple operation. 
Normally you'll find you'll need to provide a way to modify or read this 
internal value one way or another from the outside (note I'm not saying 
directly).

I could make the argument the other way what if the class changed you 
want to do the operations on.  Do you remove the method from the other 
class and create a new one in the new class?

> 
>>> But to each his own, I guess. That article certainly had some good
>>> points.
>>>

This walking-the-OO-line a well known C++ verse Java debate.  I can't 
say I side with the Java side because most of the opponents haven't used 
C++ at least in this way (the same can't be said about C++ programmers).

I used to be very OO but personally I've come to see this sort of coding 
works a lot better for me.  Its a big learning step, which requires an 
adjustment in thinking.  Its also a common interview question.

So I'm no saying your wrong, I'm just saying this is why I code this 
way.  Either way its always good to have a overall plan when you code. 
And its great that your thinking about this sort of high level stuff.

This is the sort of thing I think "style-guides" should be about rather 
then how many spaces you put in front of your methods ;)

I hope that helps.



More information about the Digitalmars-d mailing list