I don't think there's a language-agnostic answer to this since what constitutes a “property” is a language-specific question, and what a caller of a “property” expects is a language-specific question as well. I do think the most fruitful way to think about this is to think about what it looks like from the point of view of the caller.
In C#, properties are distinctive in that they are (conventionally) capitalized (like methods) but lack parentheses (like public instance variables). If you see the following code, absent documentation, what do you expect?
var reciprocalHeading = myHeading.Reciprocal;
As a relative C# novice, but one who’s read Microsoft’s Property Usage Guidelines, I would expect
Reciprocal to, among other things:
- be a logical data member of the
- be inexpensive to call, such that there’s no need for me to cache the value
- lack observable side effects
- produce the same result if called twice in succession
- (maybe) offer a
Of these assumptions, (3) and (4) are probably correct (assuming
Heading is an immutable value type, as in Ewan's answer), (1) is debatable, (2) is unknown but also debatable, and (5) is unlikely to make semantic sense (though whatever has a heading should perhaps have a
HeadingChanged event). This suggests to me that in a C# API, “get or calculate the reciprocal” should not be implemented as a property, but especially if the calculation’s cheap and
Heading is immutable, it’s a borderline case.
(Note, though, that none of these concerns have anything to do with whether calling the property creates a new instance, not even (2). Creating objects in the CLR, in and of itself, is pretty cheap.)
In Java, properties are a method naming convention. If I see
Heading reciprocalHeading = myHeading.getReciprocal();
my expectations are similar to those above (if less explicitly set out): I expect the call to be cheap, idempotent, and lacking in side effects. However,
outside the JavaBeans framework the concept of a “property” is not all that meaningful in Java, and particularly when considering an immutable property with no corresponding
getXXX() convention is now somewhat old-fashioned. From Effective Java, second edition (already more than eight years old now):
Methods that return a non-
boolean function or attribute of the object on which they’re invoked are usually named with a noun, noun phrase, or a verb phrase beginning with the verb
get …. There is a vocal contingent that claims that only the third form (beginning with
get) is acceptable, but there is little basis for this claim. The first two forms usually lead to more readable code… (p. 239)
In a contemporary, more fluent API, then, I would expect to see
Heading reciprocalHeading = myHeading.reciprocal();
-- which would again suggest that the call is cheap, idempotent, and lacks side effects, but would say nothing about whether a new calculation is performed or a new object is created. This is fine; in a good API, I shouldn’t care.
In Ruby, there's no such thing as a property. There are “attributes”, but if I see
reciprocalHeading = my_heading.reciprocal
I have no immediate way of knowing whether I’m accessing an instance variable
@reciprocal via an
attr_reader or a simple accessor method, or whether I’m calling a method that performs an expensive calculation. The fact that the method name is a simple noun, though, rather than say
calcReciprocal, suggests, again, that the call is at least cheap and probably doesn’t have side effects.
In Scala, the naming convention is that methods with side effects take parentheses and methods without them don’t, but
val reciprocal = heading.reciprocal
could be any of:
// immutable public value initialized at creation time
val reciprocal: Heading = …
// immutable public value initialized on first use
lazy val reciprocal: Heading = …
// public method, probably recalculating on each invocation
def reciprocal: Heading = …
// as above, with parentheses that, by convention, the caller
// should only omit if they know the method has no side effects
def reciprocal(): Heading = …
(Note that Scala allows various things that are nonetheless discouraged by the style guide. This is one of my major annoyances with Scala.)
The lack of parentheses tells me the call doesn’t have side effects; the name, again, suggests that the call should be relatively cheap. Beyond that, I don’t care how it gets me the value.
In short: Know the language you’re using, and know what expectations other programmers will bring to your API. Everything else is an implementation detail.