Feature Request: Deep immutability #4015
Replies: 5 comments 6 replies
-
You could do this by writing an analyzer that checks to ensure things are mutated based on hte specific patterns/practices you would/wouldn't allow. |
Beta Was this translation helpful? Give feedback.
-
I'm facing the same problem in many occasions. Because there is currently no other way, I created interfaces, e.g. interface IReadOnlyPoint
{
double X { get; }
double Y { get; }
}
interface IPoint : IReadOnlyPoint
{
new double X { get; set; }
new double Y { get; set; }
}
struct Point : IPoint
{
public double X { get; set; }
public double Y { get; set; }
} and I really hate it, because it's too much work and too way too much maintenance, also the problem is that people in our company try to cast a IReadOnlyPoint to an IPoint because they need it. The same is here with the suggestion of using an analyzer. It doesn't hinder people to use it even if they are not allowed. I see this often happening in our own codebase which causes a lot of trouble, because sometimes the cast is possible and sometimes not depending on the selected processing graph. Another problem is that the (in case of speed you don't want to access the property getter). Here I really prefer prohibition instead of prevention or cure. So the final solution would be struct Point : IPoint
{
public double X;
public double Y;
double IReadOnlyPoint.X { get => X; set => X=x; }
double IReadOnlyPoint.Y { get => Y; set => Y=y; }
double IPoint.X { get => X; set => X=x; }
double IPoint.Y { get => Y; set => Y=y; }
public Point(double x, double y) {X=x; Y=y;}
} Some solutions say to create a readonly wrapper, like ReadOnlyList but also here only the list cannot be modified, but still the objects the list contains. So the solution here would be to create a ReadOnlyList with wrapper items that are readonly. Here: List<IPoint> points;
ReadOnlyList<IReadOnlyPoint> ro_points; which means allocating new objects. Also here in your example using geometric primitives so I assume you are somehow in a situation like we are, thousands of geometric primitives need to be recreated as readonly objects, right? In our situation cloning an object would mean cloning 50MB. So it's easier (not in architectural but performance wise) to return the readonly interface. At least for such primitive structures, like Point, Line, structs, etc. we have made all of them readonly structs and modifications are only allowed by creating a new instance. Currently this is not so nicely done (because you need write out the full constructor), but with C#9 and withers this can be done easier: readonly struct Point
{
public readonly double X;
public readonly double Y;
public Point(double x, double y) {X=x; Y=y;}
} One more problem is with the upcoming of As far as I can remember in C++, but currently I'm really not sure and it might be that this also doesn't apply to this example regarding properties, you could write class Line
{
public const Point P1;
public const Point P2;
public Line(Point P1, Point P2)
{
this.P1 = P1;
this.P2 = P2;
}
} with my example above your class would look like class Line
{
public readonly IReadOnlyPoint P1;
public readonly IReadOnlyPoint P2;
public Line(IReadOnlyPoint P1, IReadOnlyPoint P2)
{
this.P1 = P1;
this.P2 = P2;
}
} But we also have structures or classes (doesn't matter) with around 100 properties and more. So here implementing e.g. IReadOnlySpectrum with readonly getters and then ISpectrum with getters and setters is way to much work. As |
Beta Was this translation helpful? Give feedback.
-
Cc @jaredpar |
Beta Was this translation helpful? Give feedback.
-
The main problem I see we with declaring mutability on the consumption side is side effects. Sure, we can block calls to setter methods, but what about all the other methods on the class that cause mutation to occur? Even getters can cause mutation, so without a way to express that a method is allowed to be called on an immutable instance, this would be nothing but a false sense of security. |
Beta Was this translation helpful? Give feedback.
-
I'm sorry if I'm being a bit slow on this, but if a third-party creates a
class that has mutability, I can't see how you could declare it to be
immutable.
Even if you were somehow able to apply a modifier to its declaration to
somehow force it to be immutable, what happens when it attempts to mutate
internally? Exception?
…On Fri, 16 Oct 2020 at 16:53, Alireza Habibi ***@***.***> wrote:
I already mentioned #421
<#421>. It gets
complicated when you want to make guarantees while permitting transitions
between the two contexts (mutability should not leak when you're aliasing
to an immutable storage, for example).
The ecosystem already doubled the types for mutable/immutable collections
to make up for that and at this point I'm not sure if it wouldn't be too
late to consider this as a language feature.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#4015 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADIEDQMXCA24OQNDCNB5YSLSLBT77ANCNFSM4SSQLWDA>
.
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Assume we have a third party library with a single class
Point
. We cannot alter it.The following code is ours. I need a feature to prevent the properties of
P1
from being modified.Beta Was this translation helpful? Give feedback.
All reactions