Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I call this C# class "immutable"?

I need to make my mutable class immutable, now it looks like as following. However, still I'm not sure that I have a fully "immutable* class, and if it is, what kind of immutability this is called ?

public class B<C, M>
        where C : IComparable<C>
        where M : IMetaData
{

    internal B(char tau, M metadata, B<C, M> nextBlock)
    {
        if (tau == 'R') omega = 1;
        _lambda = new List<Lambda<C, M>>();
        _lambda.Add(new Lambda<C, M>(tau: tau, atI: metadata));
        foreach (var item in nextBlock.lambda)
            if (item.tau != 'L')
                _lambda.Add(new Lambda<C, M>(tau: 'M', atI: item.atI));
    }

    internal int omega { private set; get; }
    private List<Lambda<C, M>> _lambda { set; get; }
    internal ReadOnlyCollection<Lambda<C, M>> lambda { get { return _lambda.AsReadOnly(); } }



    internal B<C, M> Update(int Omega, char tau, M metadata)
    {
        B<C, M> newBlock = new B<C, M>();
        newBlock.omega = Omega;
        newBlock._lambda = new List<Lambda<C, M>>(this._lambda);
        newBlock._lambda.Add(new Lambda<C, M>(tau: tau, atI: metadata));
        return newBlock;
    }

    internal B<C, M> Update(Dictionary<uint, Lambda<C, M>> lambdas)
    {
        B<C, M> newBlock = new B<C, M>();
        newBlock.omega = this.omega;
        newBlock._lambda = new List<Lambda<C, M>>();
        foreach (var l in lambdas)
            newBlock._lambda.Add(new Lambda<C, M>(tau: l.Value.tau, atI: l.Value.atI));

        return newBlock;
    }
}

public class Lambda<C, M>
        where C : IComparable<C>
        where M : IMetaData
{
    internal Lambda(char tau, M atI)
    {
        this.tau = tau;
        this.atI = atI;
    }

    internal char tau { private set; get; }
    internal M atI { private set; get; }
}

Based on my application B needs to be changed from time to time; hence to keep the property of immutability, every update needs to be done throught Update function that returns a totally new B.

Update

To shed a light on IMetaData that was cleverly spotted by Jon Skeet please consider following definitions:

public interface IMetaData
    {
        UInt32 hashKey { set; get; }
    }

and following class is passed as M to B<C, M>

public class MetaData : IMetaData
    {
        public UInt32 hashKey { set; get; }
    }
like image 664
Hamed Avatar asked Oct 31 '14 15:10

Hamed


People also ask

What does call () do in C?

The call by reference method of passing arguments to a function copies the address of an argument into the formal parameter. Inside the function, the address is used to access the actual argument used in the call. It means the changes made to the parameter affect the passed argument.

What is Call by in C?

The call by value method of passing arguments to a function copies the actual value of an argument into the formal parameter of the function. In this case, changes made to the parameter inside the function have no effect on the argument. By default, C programming uses call by value to pass arguments.

How do you call C in C++?

Just declare the C++ function extern "C" (in your C++ code) and call it (from your C or C++ code). For example: // C++ code: extern "C" void f(int);


2 Answers

No external code can ever observe any mutations of this type, which is enough for it to be considered "immutable" in common speach. The only times it is ever mutated is during it's own constructor; it is never mutated once created, so no external entity could ever actually observe a mutation of the type. This tends to be true of almost all types that are considered "immutable".

While the type does have the technical ability to mutate itself outside of its constructor in that it has both fields that are not readonly as well as a mutable List, it never actually performs any such mutations or exposes any means of mutating the data.

like image 54
Servy Avatar answered Sep 18 '22 07:09

Servy


The vast majority of immutable class types achieve their immutability by encapsulating data in an object of mutable class type but ensuring that no reference to that object will ever be exposed to code that might mutate it. Given that .NET does not have any immutable array types other than String, such an approach is often the only practical way for a variable-sized collection to offer efficient random access. Types which do not need to offer efficient random access could use more "deeply immutable" means of storing data such as linked lists or trees that store everything in readonly fields, but in practice if there is no possible execution sequence via which a particular object instance could be mutated, then that particular instance may be legitimately described as "immutable" even if its class would allow the instance to be mutated by anyone with a reference to it.

With regard to whether an interface-type reference may be regarded as identifying an immutable object, that would depend upon whether there is a contract in either the interface itself, or in the means by which the reference was supplied, which would specify either that all legitimate implementations of that interface will be immutable, that the particular instance identified by the reference will be immutable, or (if the code holding the reference never exposes it to outside code) that the instance will never be exposed to code that might mutate it. If the interface promises immutability, then code receiving a reference from outside code could use it directly; otherwise, it would have to receive the reference from code that promises that there won't be any "unsheltered" references to it. One possible pattern would be to have an interface offer an AsReadableSnaphot method which would guarantee to return an object encapsulating the state of the object upon this it is invoked, and would promise that no outside reference existed which would mutate the object in question; an immutable class might implement such a method to simply return itself, while a mutable one might implement it to return a clone of itself). If instances of the class might be big, it might be desirable to have AsReadableSnapshot create an immutable class instance (so that calling AsReadableSnapshot wouldn't have to make yet another copy of the data therein) but if they will always be small, having the returned object be of a mutable type shouldn't be a problem.

like image 45
supercat Avatar answered Sep 18 '22 07:09

supercat