Virtual properties anyone?

As part of the WinFX review team, I regularly review APIs for usability issues. One thing that we as a team have been highlighting as a potential issue is the use of virtual properties. Consider the following code snippet:

public class Class1
    private string theString;

    public virtual string MyString
        get{return theString;}
        set{theString = value;}

public class Class2 : Class1
public override string MyString
get{return “Ha ha!”;}
set{base.MyString = value;}

Code that accesses the MyString property of an instance of Class1 might either return the actual string or “Ha ha!” depending on the actual runtime type.

The design guidelines suggest that properties should not be used if they perform some expensive operation (see Brad’s post on a similar issue). Calling a virtual property or method is more expensive than calling non-virtual methods or properties so that is one reason for not creating virtual properties. Another reason is that we believe the code to access a property doesn’t really suggest that the value of MyString depends on the runtime type of the object. Consider the following:

public void DoSomething(Class1 c1){Console.WriteLine(c1.MyString);}

In this case, a developer might be surprised if calling DoSomething resulted in “Ha ha!“ being output to the console. We believe that to provide a consistent user experience, properties should mimic simple field access as much as possible. Thus virtual properties run the risk of breaking this consistency since in some cases, some properties work just like accessing a field while in other cases they work more like a virtual method call.

We’re not suggesting that there is never a good reason for declaring virtual properties. We’re just discouraging the use of virtual properties and encouraging the use of virtual methods instead.

However, I’d be interested in your feedback on this issue. Are we being too cautious?

Comments (9)

  1. Ouch. That would certainly drive me nuts.

    You say "We believe that to provide a consistent user experience, properties should mimic simple field access as much as possible. "

    Why? They’re not fields, they’re properties. The whole purpose of a property is to, in fact, encapsulate that access away and to allow the actual object to decide how to respond. You’re taking away the latter when it is one of the main purposes of a property.

    Your example is pretty ridiculous too. When you access a property you should never make an assumption about what it is doing. If I access MyString on a class I know that it can do basically anything it wants and I should treat it that way.

    IMO, it’s decisions like this that always end up giving me classes that are unusable, unexstencible and force me to rewrite them all the time.

    Why would you pruposely restrict developers from being able to extend and utilize this code? All you end up doing is hurting those who want that power.

  2. There is a place for virtual properties in API design, but in majority of cases that we ran into during WinFx reviews, it was actually a design mistake. For example, we have seen lots of APIs where a property was virtual but it sill was just accessing the filed and there was no concrete scenarios for this property to do anything else. Sure, you can always come up with a corner case scenario, but at what cost:

    1. Virtual members are not being inlined. That means virtual property access is way more expensive than a filed access. This is not really acceptable for many system APIs.

    2. Virtual property (like any other virtual member) has a higher cost of design, has a negative impact on ability to version the API, and finally there are potential security implications.

  3. "We believe that to provide a consistent user experience, properties should mimic simple field access as much as possible."

    What about lazy load scenarios? Those aren’t simple member access scenarios.

    What about abstract properties? If I want to create an abstract class that requires the deriving class to implement a property, why am I being punished for it?

    I also agree wholeheartedly with Cyrus’s comment.

    What you’re doing here is ‘limiting’ the freedom of design for developers, based on purely physical reasons. What you should be doing is go and open a can of whoop ass the ineffeciency of virtual members, namely properties.

  4. David Levine says:

    I also have to vote in favor of Cyrus’s argument. A property is syntatic sugar around a method pair (possibly a single method), and the intent is to shield the details of providing a value from all callers – the implementor is free to change the logic behind it whenever it is necessary.

    Well, why wouldn’t a derived class find it necessary to change the behavior? Perhaps it wants to add a smart caching scheme on top of the base class. Perhaps it wants to do a remote lookup on top of a static local loopup.

    I also find the performance argument non-persuasive. Sure, if you sit there in a tight loop calling it 10000/second it begins to add up, but I think code that does that is more of a corner case then your example. Most code will call it once in a while where the extra performance hit of making a virtual method call is unnoticable. Optimization is good, but it should not get in the way of functionality, especially since this is totally under the control of the base class designer, who can choose to make the property virtual or not.

  5. Steven Clarke says:

    These are great comments, thanks for sharing them. Clearly some of you feel pretty strongly about this 🙂

    We’ll absolutely take your feedback into consideration during our reviews. Just to be a little clearer than I was in my original post though, our intention is not to completely prevent API designers from using virtual properties. We just want to make sure that they have very good reasons for using them. As I said, and as you have all reiterated, there are some very good reasons for using virtual properties. We do not intend to stop API designers from using virtual properties in those cases.

    One follow up question I have is – "How do you determine whether or not to make a property virtual?"

  6. Nicholas Allen says:

    Steven- Perhaps I’m misunderstanding the intent of your question, but why is determining whether a property should be extensible any different than for a method, class, or anything else?

    I’d guess that you’d want to have some meaningful extensibility scenario. There’d have to be no issues for correctness, compatibility, or security. You’d need some amount of resources for programming / test / documentation.

    But don’t you have all of that anyways for virtual methods? I guess I don’t see why properties are being treated differently than methods. If you have a situtation where get/set makes sense, use a property. Otherwise, use a method. Whether it should be virtual or not doesn’t seem to depend on the particular syntax you use to express it.

  7. I cannot understand the logic against virtual properties. They are functions like any other, and need to be overrideable, like any other function, on occassion. Virtual does not cause any performance decrease of the magnitude that would cause a problem for a property in a debugger.

    The "suprise" in the example code would be just as suprising whether the code used a method or a property. Everyone knows a property is a type of function — so what is the big deal? We need the flexibility, and I don’t see how you are going to place restrictions, beyond "long execution time", which is a separate issue.

    You know what this would engcourage? GetXX() and SetXX() functions. And people will think this is somehow "better" because they are conforming to a guideline. Don’t put out a superfluous guideline!

    People should have very good reasons for making anything virtual, function or property. Neither is more complex than the other.

  8. Steven,

    Here’s a good considiration:

    I am given a base class with a property. I can’t trust that property to not raise any events, call any methods, etc. just after I set its value from my own class (how could I otherwise set the value?).

    This is why I would like to override it and do some of my own logic prior to the logic of the base class, or even alter the behaviour all together.

  9. Steven Clarke says:

    Thanks again everybody. It seems obvious now, but thanks for making it clear to me. There is no reason for treating virtual properties any different to virtual methods. If there is a good reason for defining a virtual method, define it. If there isn’t, don’t.