Proposal: Allow getters and setters to have different signature in interfaces #1982
Replies: 37 comments
-
I'd suggest the problem is having When I read your sample, By contrast, In a code review I would flag code where |
Beta Was this translation helpful? Give feedback.
-
@theunrepentantgeek Edit: Oh, and |
Beta Was this translation helpful? Give feedback.
-
But properties (which are what indexers compile to) are not. Currently, this interface IReadOnlyMap
{
double this[string key] { get; }
}
interface IMap : IReadOnlyMap
{
double this[string key] { set; }
} means
and what you are proposing would make it
which I believe is impossible without clr changes. |
Beta Was this translation helpful? Give feedback.
-
So is this adding a Also, I think this violates LSP because you can pass |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Post retracted as the code doesn't work as @svick points out below. |
Beta Was this translation helpful? Give feedback.
-
It's a bad precedent. Therefore it's a precedent that we should actively ignore. |
Beta Was this translation helpful? Give feedback.
-
Care to explain why? Making everything immutable is not practical and having read-only view over potentially mutable data is very useful, especially if you want to separate the concerns in your code. |
Beta Was this translation helpful? Give feedback.
-
Good point. The code compiles just fine but is then unusable in many situations due to the compiler not being able to resolve whether the getter or setter is referred to in eg |
Beta Was this translation helpful? Give feedback.
-
It's all to do with the "pit of success" and thus making "readonly" the default state and the fact that many folk (incorrectly, but frequently) treat read-only as immutable. So a better design would have been |
Beta Was this translation helpful? Give feedback.
-
I highly agree. Pretty sure it's a logical fallacy to assume that because someone else, or a lot of people, or a lot of smart people do it, then it's the best thing to do. Everyone is subject to mistakes, even the writers of .NET |
Beta Was this translation helpful? Give feedback.
-
Whether or not you use the name |
Beta Was this translation helpful? Give feedback.
-
That would be my preference too but is that all this is about? Are we seriously just arguing about the naming here? |
Beta Was this translation helpful? Give feedback.
-
This is kind of my fault. 😞 I was trying to make the point that the interface inheritance used in the original example didn't make any sense because the two interfaces had very different semantics that shouldn't be conflated together into an inheritance structure. But, I didn't explain that well, everyone has gotten distracted by ReadOnly vs Immutable, and my original point seems to have been lost. |
Beta Was this translation helpful? Give feedback.
-
@theunrepentantgeek well I think it's a very good discussion, since I never realized that there's this distinction, and it's a very important distinction. |
Beta Was this translation helpful? Give feedback.
-
As stated before, Imagine writing a function that takes a list and only needs to read some data from it, once. Should it take a Under your proposal, if the caller has a mutable list interface, let's say |
Beta Was this translation helpful? Give feedback.
-
Sorry, but I've absolutely no idea what you are trying to argue. It is irrelevant whether we have: interface IReadOnlyList {}
interface IList : IReadOnlyList {}
class List : IList {} or interface IReadOnlyList {}
interface IList {}
class List : IList, IReadOnlyList {} in both cases, I can supply Could you try to explain your argument differently, please? I might get then. |
Beta Was this translation helpful? Give feedback.
-
@DavidArno |
Beta Was this translation helpful? Give feedback.
-
I was assuming that r/w extending r/o is possible. (e.g. r/o is created no later than r/w, such change is acceptable, etc.)
I don't think it is too much for something requiring read-write to require readable. On the other hand, something read-write not requiring readable is weird.
Not extending the interface does not solve the problem either. Users still can implement getters differently. And it actually creates more problems: I can now implement the r/w interface and not implement the r/o one.
Actually there is. (except that
Maybe the writer of this just want to be specific about what interfaces are implemented? But it looks like some random interfaces that |
Beta Was this translation helpful? Give feedback.
-
@DavidArno In the first case, I can pass an IList to a function that takes an IReadOnlyList. In the second case, I cannot. |
Beta Was this translation helpful? Give feedback.
-
@Neme12 you can pass |
Beta Was this translation helpful? Give feedback.
-
I said
(notice the This is important if you're dealing with interfaces, either that you got from someone else or you just prefer to always work with interfaces, like it's conventional to do in Java. |
Beta Was this translation helpful? Give feedback.
-
I was going to ask for a use-case where you'd do that. But of course, |
Beta Was this translation helpful? Give feedback.
-
I'm sure I could dream up some (likely daft) example. But I don't really get the point. It's useful to have a list implement both a readable view and a mutable view of itself. Just don't use interface inheritance to do so as it's not necessary and can cause all sorts of problems as per the OP's example. |
Beta Was this translation helpful? Give feedback.
-
On the other hand @DavidArno, a lot of read only lists implement IList anyway. The reason being that a lot of functions that could accept an IReadOnlyList only accept an IList. The reason for that is that it would be a breaking change to accept an IReadOnlyList in place of an IList, since IList doesn't implement IReadOnlyList, despite the fact that (as you yourself admit) pretty much every class that implements IList ought to implement IReadOnlyList. |
Beta Was this translation helpful? Give feedback.
-
Similarly, if you have a function that accepts an IList, you can't call a function that accepts an IReadOnlyList without some sort of hack. This is despite the fact that 99% of all IList implementations do (or at least should) implement IReadOnlyList. |
Beta Was this translation helpful? Give feedback.
-
I know, and I find that really sad. I understand why eg I would have preferred that the authors of those immutable types had stuck to their principles and had said "if you want to use this type, you'll have to fix your code". But so much of the .NET ecosystem is about pandering to those that don't want to change things, so they'd have limited their market if they had done.
If/when we get shapes, this may be addressed. Rather than using inheritance, I can then create a shape composed of multiple interfaces. Then my method can require an |
Beta Was this translation helpful? Give feedback.
-
Even if every developer use the required minimum interfaces, logical mismatch between "[readable and writable list] is [readable list]" is always correct logically, but code can never understand that even if you claim in the document. |
Beta Was this translation helpful? Give feedback.
-
@glassgrass The point is I think code should understand that. And we could make it understand if we make |
Beta Was this translation helpful? Give feedback.
-
With C# 8.0 you can do this: interface IReadOnlyMap
{
double this[string key] { get; }
}
interface IMap : IReadOnlyMap
{
double IReadOnlyMap.this[string key] => this[key];
new double this[string key] { get; set; }
} This has two advantages:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
The lack of this distinction has caused so much pain and confusion, see: here, here and here.
I wanted to be able to specify IReadOnlyMap and IMap, and naturally expected this to work:
I thought this would work because getter and setter are distinct methods with distinct names, but instead I was surprised to find out that there is name hiding.
People typically suggest to use new, i.e.
This is semantically broken, as noted by one SO user:
It's fundamentally wrong to use new here for both aesthetic and practical (since it allow separate explicit implementation of the getter) reasons. Bad, wrong, period.
I spent 1 hour searching and failed to find a semantically correct approach within current language design, hence the proposal here.
Beta Was this translation helpful? Give feedback.
All reactions