10

Lately I've been realizing the benefit of (some would argue overuse of) immutable objects to cut down dramatically on read-write dependency issues in my object model and their resulting conditions and side-effects, to ultimately make the code simpler to manage (kind of functional-programming-esque).

This practice has led me to create read-only objects that are provided values at creation/construction time and then to make available only public getters for external callers to access the properties with. Protected, internal and private setters allow internal control to be maintained over writing to the object model.

When creating interfaces while making an API over my object model, I've started considering the same issues about immutability. For example, by providing only public getters on my interfaces, and leaving it up to implementors to decide upon setters and how to handle that aspect.

An example of a "read-only" interface for implementation that I'm talking about is this Valuable Item (just for demonstration):

public interface IValuableItem {
    decimal Amount {get;}
    string Currency {get;}
}

However I got to wondering how I should provide a companion interface that allows for writing (and if I should), and not combine those operations within the same interface as to not "taint" its immutability.

The following ideas have come to mind, just off the top of my head. Without providing what I think are pros and cons to each, what do you think the best approach is? Is there a coding methodology common in the industry for managing this concept?

// companion writer
public interface IValuableModifier {
    decimal Amount {set;}
    string Currency {set;}
}

or

// explicit methods to enforce importance of or deviance in the programming
public interface IValuableModifier {
    void SetAmount(decimal val);
    void SetCurrency(string cur);
}

or

// companion writer that inherits the original interface
public interface IValuableModifier : IValuableItem { //...

or

// Let a concrete class choose one and/or the other.
class Concrete  : IValuableModifer, IValuableItem { //...

or

etc...
What else can help me imbue writing on my otherwise immutable programming model and keep it moderately flexible or at least to separate the concerns for better control over it?

John K
  • 28,441
  • 31
  • 139
  • 229
  • A class that has a `public` or `protected` property that provides only a `set` accessor will raise Code Analysis warning [CA1044: Properties should not be write only](https://msdn.microsoft.com/en-us/library/ms182165.aspx). – DavidRR Aug 11 '16 at 13:35

5 Answers5

10

I think I might use a variant of your ideas, something like this:

public interface IValuableItem
{
    decimal Amount { get; }
    string Currency { get; }
}

public interface IMutableValuable : IValuableItem
{
    new decimal Amount { set; get; }
    new string Currency { set; get; }
}

class Item : IMutableValuable
{
    public decimal Amount { get; set; }
    public string Currency { get; set; }
}

This way your mutable interface has full getters and setters (I don't think it makes sense to have an interface that has setters but no getters), but any object that implements it will also have an immutable version of the interface that you can use for any pure-functional code.

Gabe
  • 84,912
  • 12
  • 139
  • 238
  • +1: *I don't think it makes sense to have an interface that has setters but no getters* - unless have a valid justification for the same. – KMån Nov 30 '10 at 07:08
  • @KMån - I agree. I've tried a few times to have only setter interfaces, but almost always you need a bit of "get-ability" somewhere, so it's not worth it. You could create `IMutableValuable` above by inheriting mutable and immutable interfaces, but it's YAGNI. – Kit Oct 05 '11 at 13:12
  • @KMån: that may be justified when you want to enforce a functional semantic, avoiding side effect during evaluation, like ensuring the complex evaluation of an object does not depends on the states of the object during its own evaluation. In such a case, it may be justified to provide a write only interface, with no read access. Not easy to properly design though, especially if you want to properly specify the methods, which typically requires reference to read access methods. – Hibou57 Nov 07 '12 at 22:09
4

You should have separate interfaces for ReadableFoo, ImmutableFoo, and MutableFoo. The latter two should inherit from the first. ReadableFoo should contain an "AsImmutable" method which will return a Foo that is guaranteed to be immutable (a immutable instance should return itself; a mutable instances should return a new immutable instance which contains its data), and probably an "AsNewMutable" member (which will create a new mutable instance containing the same data, whether the original was mutable or not).

No class should implement both ImmutableFoo and MutableFoo.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • I find this answer interesting as well. You are saying 'should' - is this based on a general practice or spec that I can read more about? – John K Dec 03 '10 at 05:40
  • @John K: If an object claims to be immutable, it promises anyone who uses it that it will never change. If an object claims to be mutable, it promises that anyone who uses it will be allowed to change it, and (unless changed back) the change will be reflected the next time the object is read. I suppose one could have a "ModelTFordColor" class which was both immutable and mutable (you can set it whenever you want, to whatever color you want, so long as it's black, and its color will be what you set) but I can't think of any useful scenarios for a class being both mutable and immutable. – supercat Dec 03 '10 at 15:39
  • 1
    @John K: I won't say that no class "can" implement both ImmutableFoo and MutableFoo (since nothing prevents a class from doing that) but except in trivial cases where a mutator couldn't have any real effect, any class which implements both interfaces will violate the contract of at least one of them. – supercat Dec 03 '10 at 15:55
3

If your objects are to be immutable (and you design your application around the concept of immutable data) then objects really MUST remain immutable.

The canonical method for modifying data in immutable scenarios is to create new objects, so I would suggest something like this:

public interface IValuableItem<T>
{
    decimal Amount { get; }
    string Currency { get; }
    T CreateCopy(decimal amount, string currency);
}

public class SomeImmutableObject : IValuableItem<SomeImmutableObject>
{
    public decimal Amount { get; private set; }
    public string Currency { get; private set; }

    public SomeImmutableObject(decimal amount, string currency)
    {
        Amount = amount;
        Currency = currency;
    }

    public SomeImmutableObject CreateCopy(decimal amount, string currency)
    {
        return new SomeImmutableObject(amount, currency);
    }
}

SomeImmutableObject obj = new SomeImmutableObject(123.33m, "GBP");
SomeImmutableObject newObj = obj.CreateCopy(120m, obj.Currency);
Dean Chalk
  • 20,076
  • 6
  • 59
  • 90
2

Consider using a builder pattern: Builder objects construct immutable instances of the core object. .NET Strings are like this - the string object is immutable, and there is a StringBuilder class for efficient construction of string objects. (string + string + string is much less efficient than using a StringBuilder to do the same)

Note also that builder objects exist solely for building the target object - builders are not instances of the target object / do not implement the target interface themselves.

It's worth the effort to make your system run on immutable objects, as immutability washes away a lot of headaches in threading / concurrency / parallel execution scenarios, as well as data caching / data versioning scenarios.

dthorpe
  • 35,318
  • 5
  • 75
  • 119
1

I believe combining your 3rd and 4th choice is a better way to implement mutable & immutable types.

Public interface ImmutableItem {
    decimal Amount {get;}
    string Currency {get;}
}

Public interface MutableItem: ImmutableItem {
    decimal Amount {set;}
    string Currency {set;}
}

class Concrete : ImmutableItem  {
    //Only getters
}


class Concrete : MutableItem  {
   //Both getters & setters
}

This is clean and it let the concrete classes to decide which kind of mutability is wanted to expose to outer world.

RameshVel
  • 64,778
  • 30
  • 169
  • 213
  • 2
    If an item calls itself an immutable item, consumers should be able to safely assume that it won't change. Since a MutableItem, as defined, can be cast to an ImmutableItem, that assumption doesn't hold. Better to have a ReadonlyItem, which is inherited by both ImmutableItem and MutableItem. – supercat Dec 02 '10 at 20:38