One my former coworkers recently posed the question, does it really matter if you use a field or a property? He immediately clarified he understood the importance of encapsulation, but what if you just need to store a simple piece of data?
I’m writing within the context of C# and Java. There are other languages out there, but they’re what I’m most familiar with. I’m going to discuss public fields first, and nonpublic fields afterwards.
It is impossible to separate the access level of reading and writing a field. When you use a public field, you are allowing any code that might use your class to alter the field value at any time. This means that you should not perform conditional logic based on the value of the field because you cannot control value changes.
As a practical example, it would be a very bad idea to have a C# class that looked like this:
public class BankAccount
{
public decimal _currentBalance;
public bool Purchase(decimal transactionAmount)
{
if (transactionAmount <= 0.0m)
return false;
if (_currentBalance - transactionAmount < 0.0m)
return false;
return PerformPurchase();
}
}
The Purchase method is rendered totally useless helpless against purchases that exceed a current balance because other classes can directly manipulate the field:
class HackMyAccount
{
static void Main(string[] args)
{
BankAccount myAccount = AccountDatabase.Get("1701D-1337");
myAccount._currentBalance += 1000000000m; // Mysteriously acquire a billion...
myAccount.Purchase(52367892.27m); // Buy a yacht!
}
}
If you perform logic or validation on the value, you cannot use a public field.
When you declare a public field, you are declaring the class performs no conditional logic on the field, and the class has no interest in what the value of the field is. In my experience this is only appropriate for data transfer objects or specification objects.
What about nonpublic fields? Here we move from the very obvious situation of “that’s a bad idea“ to “it depends”. Let’s look at the benefits and cost of each.
The advantages of a property are:
Some examples of behavior while reading values include providing some formatting:
public string Name
{
get { return _first + _last; }
}
And on demand instantiation:
protected ISessionFactory SessionFactory
{
get
{
if (_sessionFactory == null)
{
lock (_sessionFactoryLock)
{
if (_sessionFactory == null)
{
var configuration = new Configuration();
configuration.Configure();
configuration.AddAssembly(typeof(User).Assembly);
_sessionFactory = configuration.BuildSessionFactory();
}
}
}
return _sessionFactory;
}
}
Behavior when writing values usually involve validation of the value being set:
int _age;
public int Age
{
get { return _age; }
set
{
if (value < 0)
throw new ArgumentOutOfRangeException("Age cannot be negative");
_age = value;
}
}
The advantages of a field are:
The cost of implementing and understanding a field is very minimal:
protected int _numberOfCallsMade;
The cost of a property that isn’t a straight pass through is obviously going to be higher because there is some behavior associated with the field being wrapped (see any of the above examples on adding behavior to a field). You have to decide if the behavior you want to add the field is worthwhile.
What about the cost of a property that is a straight pass through? In early versions of C#, the cost looks like this:
string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
In Java, you actually have to write a no argument method that returns the value for getting, and a void method with a parameter to receive the new value.
Newer versions of C# introduced default properties:
string Name { get; set; }
That’s it. It takes three extra seconds to type, and guarantees that I can easily add behavior around reading and writing a name if I need to later, and do so without refactoring from _name to Name.
An alternative to this "properties are cheap, the potential benefit is worth it" viewpoint is “YAGNI – use a nonpublic field
YAGNI is intended to keep designs simple and understandable by preventing needless complexity. I don’t believe there are very many developers who are going to have a mental burden differentiating between fields and pass through properties, and I think the extra complexity is worth the potential benefit (even if behavior is never added later). It’s not like we’re introducing a database to an application that prints “Hello world” or creating a graphics library abstraction for an application that will only run on one operating system.
The second reason is desire for consistency. Rather than deal with fields sometimes and properties sometimes, I'd rather just have everything be a property whenever possible.
The last reason is more of an intangible, aesthetic issue, but I feel it’s a valid point. There’s something subtle that’s implied by using a property instead of field – that the class explicitly owns that data, and is retaining the responsibility for controlling it. Fields imply records of data that can be freely modified from anywhere, and don’t encourage thinking about what classes or methods are responsible for controlling that data.
In other words, to me this:
protected int Counter { get; set; }
says “there are no object state concerns or data validation concerns involved with Counter”.
And this:
protected int _counter;
says “I didn’t think about this at all”. I realize this isn't always going to be the case, but it's the impression I get left with.
Public fields that are used by conditional logic or validation is a defect (or security exploit) waiting to happen. Avoid this situation or risk peril.
Fields without conditional logic or validation are more of a personal thing. There's nothing technically wrong with a class full of nothing but public fields being used to pass data between architectural layers in the application or passing messages between processes.
The only time I use fields is when I need a readonly or constant object. Given how easy it is to implement and understand pass through properties, the benefit of being able to add behavior later without refactoring all the references, and the mental check for “how do I need to control this data?” that occurs when defining a property, my current preference is to use properties for everything else.
Comments
Interfaces
I got the following comment from @nedames on Twitter about another advantage to properties I missed:
@nolanegly Interesting blog post. Consider adding: No fields in interfaces; and public fields can't implement interface members.