Alex Rivera | Logout

Choosing between immutable objects and structs for value objects

Asked 2009-02-22T22:35:50.920
26

How do you choose between implementing a value object (the canonical example being an address) as an immutable object or a struct?

Are there performance, semantic or any other benefits of choosing one over the other?

Edit
Report

3 Answers

14

I like to use a thought experiment:

Does this object make sense when only an empty constructor is called?

Edit at Richard E's request

A good use of struct is to wrap primitives and scope them to valid ranges.

For example, probability has a valid range of 0-1. Using a decimal to represent this everywhere is prone to error and requires validation at every point of usage.

Instead, you can wrap a primitive with validation and other useful operations. This passes the thought experiment because most primitives have a natural 0 state.

Here is an example usage of struct to represent probability:

public struct Probability : IEquatable<Probability>, IComparable<Probability>
{
    public static bool operator ==(Probability x, Probability y)
    {
        return x.Equals(y);
    }

    public static bool operator !=(Probability x, Probability y)
    {
        return !(x == y);
    }

    public static bool operator >(Probability x, Probability y)
    {
        return x.CompareTo(y) > 0;
    }

    public static bool operator <(Probability x, Probability y)
    {
        return x.CompareTo(y) < 0;
    }

    public static Probability operator +(Probability x, Probability y)
    {
        return new Probability(x._value + y._value);
    }

    public static Probability operator -(Probability x, Probability y)
    {
        return new Probability(x._value - y._value);
    }

    private decimal _value;

    public Probability(decimal value) : this()
    {
        if(value < 0 || value > 1)
        {
            throw new ArgumentOutOfRangeException("value");
        }

        _value = value;
    }

    public override bool Equals(object obj)
    {
        return obj is Probability && Equals((Probability) obj);
    }

    public override int GetHashCode()
    {
        retur
answered 2009-02-22T22:40:58.567
2

In today's world (I'm thinking C# 3.5) I do not see a need for structs (EDIT: Apart from in some niche scenarios).

The pro-struct arguments appear to be mostly based around perceived performance benefits. I would like to see some benchmarks (that replicate a real-world scenario) that illustrate this.

The notion of using a struct for "lightweight" data structures seems way too subjective for my liking. When does data cease to be lightweight? Also, when adding functionality to code that uses a struct, when would you decide to change that type to a class?

Personally, I cannot recall the last time I used a struct in C#.

Edit

I suggest that the use of a struct in C# for performance reasons is a clear case of Premature Optimization*

* unless the application has been performance profiled and the use of a class has been identified as a performance bottleneck

Edit 2

MSDN States:

The struct type is suitable for representing lightweight objects such as Point, Rectangle, and Color. Although it is possible to represent a point as a class, a struct is more efficient in some scenarios. For example, if you declare an array of 1000 Point objects, you will allocate additional memory for referencing each object. In this case, the struct is less expensive.

Unless you need reference type semantics, a class that is smaller than 16 bytes may be more efficiently handled by the system as a struct.

answered 2009-02-22T22:59:29.973
0

As a rule of thumb a struct size should not exceed 16 bytes, otherwise passing it between methods may become more expensive that passing object references, which are just 4 bytes (on a 32-bit machine) long.

Another concern is a default constructor. A struct always has a default (parameterless and public) constructor, otherwise the statements like

T[] array = new T[10]; // array with 10 values

would not work.

Additionally it's courteous for structs to overwrite the == and the != operators and to implement the IEquatable<T> interface.

answered 2009-02-22T22:55:37.533

Your Answer