52

I don't know why I started thinking about this, but now I can't seem to stop.

In C# - and probably a lot of other languages, I remember that Delphi used to let you do this too - it's legal to write this syntax:

class WeirdClass
{
    private void Hello(string name)
    {
        Console.WriteLine("Hello, {0}!", name);
    }

    public string Name
    {
        set { Hello(name); }
    }
}

In other words, the property has a setter but no getter, it's write-only.

I guess I can't think of any reason why this should be illegal, but I've never actually seen it in the wild, and I've seen some pretty brilliant/horrifying code in the wild. It seems like a code smell; it seems like the compiler should be giving me a warning:

CS83417: Property 'Name' appears to be completely useless and stupid. Bad programmer! Consider replacing with a method.

But maybe I just haven't been doing this long enough, or have been working in too narrow a field to see any examples of the effective use of such a construct.

Are there real-life examples of write-only properties that either cannot be replaced by straight method calls or would become less intuitive?

Aaronaught
  • 120,909
  • 25
  • 266
  • 342
  • Does it make sense to call methods and the values of properties change? Does it make sense for an inherited setter to cause an overridden method? – Armentage Feb 06 '10 at 17:19
  • Note to editors: Not C# specific. I called out the fact that many OO languages support this. The example is in C# but it could have been in Delphi, VB.NET, PHP, etc. – Aaronaught Feb 06 '10 at 17:53
  • 18
    You should consider developing a Visual Studio/msbuild plugin to translate errors into a form as entertaining as your example. – 3Dave Aug 20 '12 at 20:56
  • 1
    I agree, David. It would've really been nice about six or seven years ago when VS would give you like 60 errors for one screwed up line of code in C++. – Panzercrisis Dec 14 '12 at 14:31
  • Almost there: http://stackoverflow.com/questions/322941/writeonly-property-or-method – nawfal Apr 19 '13 at 19:01

14 Answers14

17

My first reaction to this question was: "What about the java.util.Random#setSeed method?"

I think that write-only properties are useful in several scenarios. For example, when you don't want to expose the internal representation (encapsulation), while allowing to change the state of the object. java.util.Random is a very good example of such design.

Pang
  • 9,564
  • 146
  • 81
  • 122
dfa
  • 114,442
  • 31
  • 189
  • 228
17

Code Analysis (aka FxCop) does give you a diagnostic:

CA1044 : Microsoft.Design : Because property 'WeirdClass.Name' is write-only, either add a property getter with an accessibility that is greater than or equal to its setter or convert this property into a method.

Ðаn
  • 10,934
  • 11
  • 59
  • 95
15

Write-only properties are actually quite useful, and I use them frequently. It's all about encapsulation -- restricting access to an object's components. You often need to provide one or more components to a class that it needs to use internally, but there's no reason to make them accessible to other classes. Doing so just makes your class more confusing ("do I use this getter or this method?"), and more likely that your class can be tampered with or have its real purpose bypassed.

See "Why getter and setter methods are evil" for an interesting discussion of this. I'm not quite as hardcore about it as the writer of the article, but I think it's a good thing to think about. I typically do use setters but rarely use getters.

Kaleb Brasee
  • 51,193
  • 8
  • 108
  • 113
  • 6
    Are you maybe referring to property injection as a means of DI? And if so, what's the advantage over constructor injection? – Aaronaught Feb 06 '10 at 17:17
  • 1
    Yeah, I usually use property injection with setters instead of constructor injection. I actually prefer the idea of constructor injection, but I use the Spring framework, and using setters instead of constructors makes the XML file clearer. – Kaleb Brasee Feb 06 '10 at 17:21
  • Ah, okay. I haven't used Spring much - looking at how it works, that does make a lot of sense. +1 for that! – Aaronaught Feb 06 '10 at 17:24
  • 12
    But why is a write-only property better than a Set method? (E.g. SetName(string name) .) I would say that it's not better. One usually expects properties to be readable. Making one write-only would violate the Principle of Least Surprise. A Set method doesn't have this problem. – dan-gph Mar 10 '10 at 06:39
  • 2
    Get/set vs properties comes down to syntactic sugar. The only objective reason I've come up with in their favor is code brevity and the flexibility to modify implementation while maintaining a "this looks like a field" interface/signature. Then again, its easy to fall into the trap of building an every-which-way extensible framework instead of just getting the thing done, so... – 3Dave Aug 20 '12 at 21:01
  • I don't buy it. If you actually need the object, it should be passed as part of the constructor. – Jonathan Allen Feb 22 '17 at 17:45
  • Your link is broken. I managed to find it in the WayBack machine: https://web.archive.org/web/20200204194309/https://www.javaworld.com/article/2073723/why-getter-and-setter-methods-are-evil.html – BrainStorm.exe Jan 06 '23 at 18:51
13

I have code similar to the following in an XNA project. As you can see, Scale is write-only, it is useful and (reasonably) intuitive and a read property (get) would not make sense for it. Sure it could be replaced with a method, but I like the syntax.

public class MyGraphicalObject
{
    public double ScaleX { get; set; }
    public double ScaleY { get; set; }
    public double ScaleZ { get; set; }

    public double Scale { set { ScaleX = ScaleY = ScaleZ = value; } }

    // more...
}
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
RAL
  • 917
  • 8
  • 19
4

One use for a write-only property is to support setter dependency injection, which is typically used for optional parameters.

Let's say I had a class:

public class WhizbangService {
    public WhizbangProvider Provider { set; private get; }
}

The WhizbangProvider is not intended to be accessed by the outside world. I'd never want to interact with service.Provider, it's too complex. I need a class like WhizbangService to act as a facade. Yet with the setter, I can do something like this:

service.Provider = new FireworksShow();
service.Start();

And the service starts a fireworks display. Or maybe you'd rather see a water and light show:

service.Stop();
service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds);
service.Start();

And so on....

This becomes especially useful if the property is defined in a base class. If you chose construction injection for this property, you'd need to write a constructor overload in any derived class.

public abstract class DisplayService {
    public WhizbangProvider Provider { set; private get; }
}

public class WhizbangService : DisplayService  { }

Here, the alternative with constructor injection is:

public abstract class DisplayService {
    public WhizbangProvider Provider;

    protected DisplayService(WhizbangProvider provider) {
       Provider = provider ?? new DefaultProvider();
    }
}

public class WhizbangService : DisplayService  { 
    public WhizbangService(WhizbangProvider provider) 
      : base(provider) 
    { }
}

This approach is messier in my opinion, because you need to some of the internal workings of the class, specifically, that if you pass null to the constructor, you'll get a reasonable default.

neontapir
  • 4,698
  • 3
  • 37
  • 52
3

In MVP pattern it is common to write a property with a setter on the view (no need for a getter) - whenever the presenter sets it content the property will use that value to update some UI element.

See here for a small demonstration:

public partial class ShowMeTheTime : Page, ICurrentTimeView
{
    protected void Page_Load(object sender, EventArgs e) 
    {
        CurrentTimePresenter presenter = new CurrentTimePresenter(this);
        presenter.InitView();
    }

    public DateTime CurrentTime 
    {
        set { lblCurrentTime.Text = value.ToString(); }
    }
}

The presenter InitView method simply sets the property's value:

public void InitView() 
{
    view.CurrentTime = DateTime.Now;
}
AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
BornToCode
  • 9,495
  • 9
  • 66
  • 83
2

Making something write-only is usefulwhenever you're not supposed to read what you write.

For example, when drawing things onto the screen (this is precisely what the Desktop Window Manager does in Windows):
You can certainly draw to a screen, but you should never need to read back the data (let alone expect to get the same design as before).

Now, whether write-only properties are useful (as opposed to methods), I'm not sure how often they're used. I suppose you could imagine a situation with a "BackgroundColor" property, where writing to it sets the background color of the screen, but reading makes no sense (necessarily).
So I'm not sure about that part, but in general I just wanted to point out that there are use cases for situations in which you only write data, and never read it.

user541686
  • 205,094
  • 128
  • 528
  • 886
2

Although the .NET design guidelines recommend using a method ("SetMyWriteOnlyParameter") instead of a write-only property, I find write-only properties useful when creating linked objects from a serialised representation (from a database).

Our application represents oil-field production systems. We have the system as a whole (the "Model" object) and various Reservoir, Well, Node, Group etc objects.

The Model is created and read from database first - the other objects need to know which Model they belong to. However, the Model needs to know which lower object represents the Sales total. It makes sense for this information to be stored a Model property. If we do not want to have to do two reads of Model information, we need to be able to read the name of Sales object before its creation. Then, subsequently, we set the "SalesObject" variable to point to the actual object (so that, e.g., any change by the user of the name of this object does not cause problems)

We prefer to use a write-only property - 'SalesObjectName = "TopNode"' - rather than a method - 'SetSalesObjectName("TopNode") - because it seems to us that the latter suggests that the SalesObject exists.

This is a minor point, but enough to make us want to use a Write-Only property.

1

As far as I'm concerned, they don't. Every time I've used a write-only property as a quick hack I have later come to regret it. Usually I end up with a constructor or a full property.

Of course I'm trying to prove a negative, so maybe there is something I'm missing.

Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
1

I can't stop thinking about this, either. I have a use case for a "write-only" property. I can't see good way out of it.

I want to construct a C# attribute that derives from AuthorizeAttribute for an ASP.NET MVC app. I have a service (say, IStore) that returns information that helps decide if the current user should be authorized. Constructor Injection won't work, becuase

public AllowedAttribute: AuthorizeAttribute
{
    public AllowedAttribute(IStore store) {...}
    private IStore Store { get; set; }
    ...
}

makes store a positional attribute parameter, but IStore is not a valid attribute parameter type, and the compiler won't build code that is annotated with it. I am forced to fall back on Property Setter Injection.

public AllowedAttribute: AuthorizeAttribute
{
    [Inject] public IStore Store { private get; set; }
    ...
}

Along with all the other bad things about Property Setter instead of Constructor Injection, the service is a write-only property. Bad enough that I have to expose the setter to clients that shouldn't need to know about the implementation detail. It wouldn't do anybody any favors to let clients see the getter, too.

I think that the benefit of Dependency Injection trumps the guidelines against write-only properties for this scenario, unless I am missing something.

Skip Saillors
  • 744
  • 13
  • 27
  • [Conditional Filters in ASP.NET MVC](http://haacked.com/archive/2011/04/25/conditional-filters.aspx/) is the accepted solution. Some frameworks, like Ninject, even [have their own shortcuts for it](https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations). Attributes should be used for decoration, as a signal to downstream processes - not to house important business logic. – Aaronaught Mar 14 '14 at 01:18
  • I don't understand. I don't want to manage when the attribute applies. I want to replace what happens. I want to change the behavior of the [Authorize]. If I read it right, a conditional filter will affect when the attribute is applied, not what happens when it is applied. – Skip Saillors Dec 11 '15 at 01:26
1

I just came across that situation when writing a program that reads data from a JSON database (Firebase). It uses Newtonsoft's Json.NET to populate the objects. The data are read-only, i.e., once loaded they won't change. Also, the objects are only deserialized and won't be serialized again. There may be better ways, but this solution just looks reasonable for me.

using Newtonsoft.Json;
// ...

public class SomeDatabaseClass
{
    // JSON object contains a date-time field as string
    [JsonProperty("expiration")]
    public string ExpirationString
    {
        set
        {
            // Needs a custom parser to handle special date-time formats
            Expiration = Resources.CustomParseDateTime(value);
        }
    }
    
    // But this is what the program will effectively use.
    // DateTime.MaxValue is just a default value
    [JsonIgnore]
    public DateTime Expiration { get; private set; } = DateTime.MaxValue;
    
    // ...
}
  • Just came here to post the same scenario, set-only properties are very useful when deserializing json datetime strings into typed values. See https://stackoverflow.com/a/72105340/892770 for another example – UnionP May 03 '22 at 20:56
0

No, I can' imagine any case where they can't be replaced, though there might people who consider them to be more readable.

Hypothetical case:

CommunicationDevice.Response = "Hello, World" 

instead of

CommunicationDevice.SendResponse("Hello, World")

The major job would be to perform IO side-effects or validation.

Interestingly, VB .NET even got it's own keyword for this weird kind of property ;)

Public WriteOnly Property Foo() As Integer
   Set(value As Integer)
     ' ... '
   End Set
End Property

even though many "write-only" properties from outside actually have a private getter.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Dario
  • 48,658
  • 8
  • 97
  • 130
  • 2
    Any property can be replaced with methods. In fact, properties in many languages are nothing more than a pair of methods (getter and setter). .NET adds a little bit of metadata saying "these two methods go together" to make reflection call it a "property", but other than reflection properties are just syntactic sugar. – Ben Voigt Feb 06 '10 at 17:43
0

I recently worked on an application that handled passwords. (Note that I'm not claiming that the following is a good idea; I'm just describing what I did.)

I had a class, HashingPassword, which contained a password. The constructor took a password as an argument and stored it in a private attribute. Given one of these objects, you could either acquire a salted hash for the password, or check the password against a given salted hash. There was, of course, no way to retrieve the password from a HashingPassword object.

So then I had some other object, I don't remember what it was; let's pretend it was a password-protected banana. The Banana class had a set-only property called Password, which created a HashingPassword from the given value and stored it in a private attribute of Banana. Since the password attribute of HashingPassword was private, there was no way to write a getter for this property.

So why did I have a set-only property called Password instead of a method called SetPassword? Because it made sense. The effect was, in fact, to set the password of the Banana, and if I wanted to set the password of a Banana object, I would expect to do that by setting a property, not by calling a method.

Using a method called SetPassword wouldn't have had any major disadvantages. But I don't see any significant advantages, either.

Tanner Swett
  • 3,241
  • 1
  • 26
  • 32
  • 1
    The significant advantage to a method called `SetPassword` is that it's not confusing. A property called `Password` implies that it is retrievable, and many consumers of that API wouldn't realize that it isn't until they try to actually retrieve it. It's also confusing for other reasons; can `Password` be assigned multiple times? I would assume that there should also be a way to `ClearPassword` or `ChangePassword` using the original password as input; otherwise, if the password can't be changed or cleared, it should be provided in the constructor. – Aaronaught Mar 08 '15 at 19:53
  • You make some good points. The only thing I have to add is that `Password` here does satisfy all the *other* expectations of the user: it can be assigned multiple times, assigning it has no side effects, and so forth. – Tanner Swett Mar 10 '15 at 16:18
0

I know this has been here for a long time, but I came across it and have a valid (imho) use-case:

When you post parameters to a webapi call from ajax, you can simply try to fill out the parameters class' properties and include validation or whatsoever.

public int MyFancyWepapiMethod([FromBody]CallParams p) {
    return p.MyIntPropertyForAjax.HasValue ? p.MyIntPropertyForAjax.Value : 42;
}

public class CallParams
{
    public int? MyIntPropertyForAjax;

    public object TryMyIntPropertyForAjax
    {
        set
        {
            try { MyIntPropertyForAjax = Convert.ToInt32(value); }
            catch { MyIntPropertyForAjax = null; }
        }
    }
}

On JavaScript side you can simply fill out the parameters including validation:

var callparameter = {
    TryMyIntPropertyForAjax = 23
}

which is safe in this example, but if you handle userinput it might be not sure that you have a valid intvalue or something similar.

z00l
  • 895
  • 11
  • 21