You Might As Well Make All Your Class Members Public

So recently some of us were discussing the fact that F# 3.0 is going to add a feature to make it more amenable to OO programmers.  F# 3.0 will add automatic “getters” and “setters” for members of a class. A small digression; I prefer the terms “inspector” and “mutator” because they seem more precise.

If it were up to me, though, most OO code would not use inspectors and mutators.  Why? Because the use of inspectors and mutators can defeat information hiding which is one of the principle benefits of object orientation. I’ll explain.  Let’s pretend we have a class C which contains a data member _m1.  This data member is an integer.  Something like this:

public class C
{
    private integer _m1;
    public integer m1 {
        get
        {
            return _m1;
        }
        set
        {
            _m1 = value;
        }
}

Now let’s say you need to reference m1 from other places in your code.  Everywhere you need to reference m1, you need to specify that m1 is an integer.  Every place in code that you need to set m1, you have to set an integer.  Now later on we may find that m1 needs to be a floating point.  Because I’ve got a public getter and setter, I now need to know about code which is referencing my class and I may need to modify that code.  This is violating the whole notion of encapsulation that we adopted OO to get.  And what if I’m sharing my code to other teams?  I might break their code and never even know about it.  At this point I might as well dispense with the private _m1 member because it’s not helping anything and in fact it’s just more work to maintain. I might as well not bother using private members.

Now some might say—well, what are you suggesting?  No inspectors or mutators?  I’d suggest we don’t need them as much as I’ve seen some OO programmers abuse this facility.  I’d also suggest another way to get back the encapsulation is to hide the actual type of the member behind something that indicates the significance of the value.   Like this example:

using EmployeeCount=System.Int32;

public class C
{
    private EmployeeCount _m1;
    public EmployeeCount m1 {
        get
        {
            return _m1;
        }
        set
        {
            _m1 = value;
        }
}

If I hide the actual type of _m1 behind EmployeeCount if I ever need to change the type of _m1 I only need to change it in one place and I don’t have to worry about code which accesses my class.  I’ve regained the encapsulation that I lost via opening part of the class’ internal details.

5 responses

  1. It’d surprising how little you need them in F#, generally you only expose read only ones so that you don’t have internal mutation:

    type MyClass(property1 : int) =
    member val Property1 = property1
    member val Property2 = “” with get, set

    Property1 is an example of that, with property2 being mutable.

  2. It’s true that when changing a member with automatic accessors, you might break some code that uses your class. But how is this different from, say, changing the type of a method whose argument’s type doesn’t match the type of a private member anymore?

    If you need to change the way your class works internally, you may need to replace the automatic accessors with a private member and a public pair of accessors. I don’t see this as a problem; automatic accessors are just a convenience facility for when the inner workings happen to match the provided interface.

  3. Well if you change public facing code you might/will break code … where is the surprise? That’s why you have to be carefull in designing and changing the public parts …

    Using type-aliases is indeed a great thing but I like it most because you can use it to make the method-type tell what the parameters are without using names for those parameters – a thing every FP languague likes to have.

  4. You’re sort of missing my point Carsten. I don’t expect there to be no side-effects to changing public facing code. I’m saying that too many developers make every inspector/mutator _public_ as a default and I’m saying that breaks encapsulation.

  5. Love the part about the type alias that gives the value meaning. Then you never accidentally initialize the EmployeeCount to a number of vacation days.

    I’m in favor of automatic accessors. This is one feature that Scala has over F# currently; it makes the type declarations shorter.

    Then again, in F#, if you want your fields public you can use a record.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: