The interaction of encapsulation and properties in D

"Luís "Luís
Wed Jul 10 19:55:09 PDT 2013


Maybe this has already been discussed (if so sorry), but I would 
like to ask your opinion about the following.

The condensed version: because we have properties, is it wise to 
use public member variables in D, in some circumstances?

The long version, starting with the context: AFAIK, standard 
encapsulation wisdom says you should never expose member 
variables directly, like this:

     class X
     {
         public int phone;
     }

     void main()
     {
         X x = new X();
         x.phone = 555123;
     }

The usual admonitions apply, such that you might want to change 
the internal representation of the 'phone'. So, as with every 
problem in life, you decide to add one more level of indirection, 
and you implement some form of getters and setters:

     // in Java or in D without using properties...
     class X
     {
         public int _phone;

         void setPhone(int v)
         {
             _phone = v;
         }

         int getPhone()
         {
             return _phone;
         }
     }

     void main()
     {
         X x = new X();
         x.setPhone(555123);
     }

With such encapsulation, once you realise the silliness of having 
a phone number stored in an int, this is easy to change without 
breaking the client code:

     // in D without using properties
     class X
     {
         public string _phone;

         void setPhone(int v)
         {
             _phone = to!string(v);
         }

         void setPhone(string v)
         {
             _phone = to!string(v);
         }

         int getPhone()
         {
             return to!int(_phone);
         }
     }

     void main()
     {
         X x = new X();
         x.setPhone(555123); // did not break the old client code
         x.setPhone("555 123"); // the new stringified API also 
works
     }

Of course, in D we would do this with properties instead:

     class X
     {
         public string _phone;

         @property void phone(int v)
         {
             _phone = to!string(v);
         }

         @property int phone()
         {
             return to!int(_phone);
         }

         @property void phone(string v)
         {
             _phone = v;
         }

         @property string phoneString()
         {
             return _phone;
         }
     }

     void main()
     {
         X x = new X();
         x.phone = 555123;
         x.phone = "555 123";
     }

But when we use the property syntax to implement the 
encapsulation the client code does not have to change; there is 
source code compatibility at the client side: the same client 
code can be used for both the the direct member variable 
implementation and the property accessors implementation, as long 
as we are willing to recompile. The client code is already 
shielded from such implementation issue; in a certain sense the 
'phone' "field" was already encapsulated.

Why, then, should one use (traditional, property based) 
encapsulation *proactively*? After all, if we later decide that 
we want to sanitize the setter inputs, or add logging, or trigger 
an action, or something like that, we can always refactor the 
public member variable into the respective property accessors.

So why not, instead, just use a simple public member variable, 
when that is cleaner (less boilerplate code), more 
straightforward, and not obvious that we will really need the 
extra indirection?

A case where such reasoning would not apply is when source code 
compatibility is not enough, such as when you have a D library. 
But this could be solved by something like...

     class X
     {
         @property public int phone;
     }

...which would under the covers generate getter and setter 
properties, so that if you later wanted to encapsulate it without 
breaking binary compatibility you could do so.

So, summing it up: even assuming that performance is not an 
issue, does the advice to always encapsulate your member 
variables (as one would do, for instance, in idiomatic Java) 
actually make sense for D, or would you recommend using public 
member variables when that is more straightforward, and the 
indirection is not yet needed?


More information about the Digitalmars-d mailing list