They're quite a smell that you have no encapsulation, plus mutable state.
I find myself either
- Writing object oriented code with higher level operations that operate on data internally without exposing it via getters and setters.
or
- Value types that take values in constructor and provide naming and additional behaviour on that data (proper Value Types support will really help with this.)
or
- Data pipelines dealing with n-tuples. For which you might be tempted to reach for getters/setters but I'd tend to either use off the shelf tuple types. i.e. tuple(A,B,C) or classes with public fields, or interfaces with static factory to create instances. I'd love better support for tuples with named attributes (Like new c# has)
Loads of getters/setters is something that the frameworks of the last decade encouraged people to do but aren't really a thing any more.
I used to be an advocate property syntax, but after seeing them used in C# and now in Swift I have completely changed my mind. It's an inconsistent mess that Java has avoided at the small price of some more lines of code (that are mostly auto generated and need no documentation)
In C# you do have to think about it all the time. Most types have both properties and methods and in many cases it's not obvious whether the author of that type had the same idea about whether or not something should be a property or a method as you do. Where you only have to remember a name in Java, you have to remember both a name and its syntactic category in C#. One more thing to keep in mind equals greater mental load.
In fact, the guidelines for choosing between one and the other include considerations that should be of no concern to the user of a public interface (https://msdn.microsoft.com/en-us/library/ms229054(v=vs.100)....). If any of these implementation details change, the logical conclusion would be to change the public interface from property syntax to method syntax or vice versa. That's what I call inconsistent.
If you're saying that the choice between getX() and x() in Java is also somewhat inconsistent then you are absolutely right. It's just not a problem on the same scale as in C#.
And if the implementation of a C# property changes in any of the ways that would make it a method, that probably deserves to be surfaced as a breaking change in the API. That's a feature, not a bug. eg, I would certainly want to know if the implementation of a property was changed from a field access to a network call.
And if you look at the guidelines I linked to, you'll see that the criteria that are supposed to tell us whether or not to use a property are much more subtle than making a network call vs accessing a field. Can you really justify a breaking change to a public interface because a type conversion is introduced in the implementation of property?
I think disguising a function call as a direct variable access is much more problematic than calling a function that may or may not do more than return the value of a variable.
That said, I do realize that reasonable people can absolutely disagree on this issue.
>>Can you really justify a breaking change to a public interface because a type conversion is introduced in the implementation of property?
I just quickly re-read that page, but I don't see what you're referring to here.
"The operation is a conversion, such as the Object.ToString method."
But this only pertains to the conversion of the object on which the property is defined. In other words, you should have methods like ToString or AsEnumerable, rather than properties like String or Enumerable, even though other rules would indicate property to be valid (idempotent, fast, no arguments). This rule is just an indication that properties represent conceptual attributes of an object; and the result of a conversion of an object to something else is not an attribute.
Semantically, the difference between properties and methods is the same as the difference between data and behavior. Are you saying that it's not a useful distinction to have?
Compare with Kotlin:
class MyFoo(val foo: Foo)
Done.Now you're left with something that could be fit on three lines (the "final" for the parameter is also useless and can be removed):
public Foo getFoo() { return foo; }
public void setFoo(Foo foo) { this.foo = foo; }
Even if you don't write the actual source like that, a good editor like IntelliJ can automatically display them like that (code folding).The C# version is about the same length:
public Foo Foo {
get { return foo; }
set { foo = value; }
}
Also, you don't have to write the get/set methods yourself. You hit a few keys and your editor generates them. public Foo Foo { get; set; }
and get the backing field for free.Bring in properties already.
public Foo Foo { get; }
or for a computed property: public int Foo => Bar + 1;
The real savings from property come when you use them, though - the extra pair of () doesn't feel like much, but when you start chaining properties, I find that not having () there significantly improves readability. Then, of course, Java also insists on `get` prefix by convention. So you have Java: foo.getBar().getBaz().blah()
vs C#: foo.Bar.Baz.Blah()
More importantly, the latter visually emphasizes the difference between accessing data and operating on it. You can see that "Bar" and "Baz" are data members, conceptually similar to "foo", whereas "blah()" is an operation.
The savings in screen space and visual cortex neurons doesn't come from the one or two properties that need logic, it comes from the dozen avoided