Proposal: Fine-grained visibility #225
Replies: 23 comments
-
I agree that fine-grained visibility can help to maintain large project and to improve self-documentation. So you need to find very strong motivation for this feature to win over other proposal. Also find good reasons that holds you from splitting your large project into multiple project (even more than hundreds it's fairly ok). InternalsVisibleTo can be a good trade-off. |
Beta Was this translation helpful? Give feedback.
-
Caring about safety on design-time, can save you a lot of time along the maintainability road. The purpose of "syntax sugar" is to help readability, not to compromise correctness. So relax, and think about what you write :) |
Beta Was this translation helpful? Give feedback.
-
Note that with attributes and analyzers, C# already provides all the necessary features to implement this proposal. |
Beta Was this translation helpful? Give feedback.
-
The attributes + analyzers approach is a 2nd-best, but it has the following disadvantages:
A built-in approach simply offers a better safety mechanism. |
Beta Was this translation helpful? Give feedback.
-
This sounds like it needs a lot more justification. |
Beta Was this translation helpful? Give feedback.
-
@yaakov-h I think this is trivial, but in any case, I changed the wording slightly to account for your input. |
Beta Was this translation helpful? Give feedback.
-
While I recognize that this proposal isn't likely to be a priority, I've been thinking along the same lines for a long time. |
Beta Was this translation helpful? Give feedback.
-
I like the idea but not thrilled with the syntax. :) p.s. This seems like it would impact the whole .NET stack and not just the language, CLR, Reflection APIs, etc... unless it's just a compiler check. |
Beta Was this translation helpful? Give feedback.
-
It doesn't have to. The main point is to provide extra safety when working at the source level. At the CLR level, it could be represented using the existing visibility modifiers, possibly with some added attributes, to be used by IDEs. Regarding syntax, you're welcome to suggest a version you'd like :) |
Beta Was this translation helpful? Give feedback.
-
While I like the general idea of having finer control over visibility, this doesn't feel like it achieves that to me. When I choose a visibility modifier, I'm specifying where I want this member to be accessible from, and I'm specifying this at the declaration site. If any class can use |
Beta Was this translation helpful? Give feedback.
-
@TheOtherSamP
By the same reasoning one could argue that |
Beta Was this translation helpful? Give feedback.
-
There is a big difference. With My suggestion would be, if you are encountering such boundaries, it might be better to restructure code. Perhaps the way you have your assemblies split up isn't the best design given the restrictions you need to place. |
Beta Was this translation helpful? Give feedback.
-
@dman2306 Notice that this proposal refers to inter-project boundaries; intra-project boundaries cases are already covered by existing modifiers, The goal is to enable a visibility that is less restrictive than
Code restructuring is possible only to a limited extent. Sometimes you end up with complicated hierarchies which could be replaced with much simpler structures using this feature. |
Beta Was this translation helpful? Give feedback.
-
If you want finer grained control over these things, I would suggest perhaps reversing this idea. I still feel that class Foo
{
private int Value { get; set; } visibleto FooWrapper
}
class FooWrapper
{
public int Value => this.foo.Value;
private readonly Foo foo;
FooWrapper(Foo foo)
{
this.foo = foo;
}
} |
Beta Was this translation helpful? Give feedback.
-
I considered a similar approach when phrasing the proposal, but found a few issues with it:
I think we have a different point of view on this. I see the hidden, contextual members as part of the external implementation, injected to providers by the consumer. I.e. the In your approach, the provider knows specifically about its consumers, having to authorize them explicitly. The issue I see with your model is what we have a mixed responsibility. On the one hand, the only reason the member exists is for usage by the consumer (as it's hidden to the rest of the code). But suddenly the provider gets to decide who uses it? This is confusing. In my approach, the consumer declares the context, injects appropriate logic to necessary areas, and decides to see that logic where it needs to. All in all, I agree that |
Beta Was this translation helpful? Give feedback.
-
Note that in my version I did not include the If you really wanted to specify the visibility in the same syntactic position it is currently, you could perhaps define some form of scope FooValueAccessors
{
FooWrapper,
OtherFooWrapper
}
class Foo
{
// I guess this should also implicitly include private access
FooValueAccessors int Value { get; private set; }
} Regarding your point about analysis, I don't really see where you're coming from. My VS (it might be R#) already lets me easily view all uses of a member within the project. To me, your version is just |
Beta Was this translation helpful? Give feedback.
-
@TheOtherSamP Can't see how your suggested You've reached the same syntax at the "provider" side. The only difference left now, is how to see members. |
Beta Was this translation helpful? Give feedback.
-
It's different because it adds value. Permission to access a member should be given out by that member, otherwise it's not permission. Let's say we're working on a team. Person A is responsible for developing a Node class that maintains some state. The node class has a couple of public methods that mutate its state in a controlled manner while ensuring that state remains valid. Person B is developing a NodeManager class, and they find that they need to be able to load an arbitrary state into a Node. As that Node's manager, they know a little more about what's going on with it, so they can safely make sensible changes to its state. Under the Under the You mentioned before that you could use the IDE to find references to a visibility and check that nobody has used Perhaps I am not understanding your aims here. What do you see the advantages of your approach being vs just making those members internal? |
Beta Was this translation helpful? Give feedback.
-
Under the We now only differ at the way we specify consumers. I propose to annotate individual consumers using We should consider what's more intuitive. IMO, once you lose the I'd say the "consumer list" approach will be more readable if phrased like this:
I prefer individual I don't see the custom visibility modifier strictly as a permission. |
Beta Was this translation helpful? Give feedback.
-
Not at all. A I still really don't understand why you wouldn't just use |
Beta Was this translation helpful? Give feedback.
-
I have no personal experience with PostSharp, but I understand that product introduces a mechanism for restricting visibility to specific classes or by namespace: http://doc.postsharp.net/control-visibility. That may provide some inspiration. |
Beta Was this translation helpful? Give feedback.
-
Actual syntax would be nice, but at the end of the day, all I want is to be able to do this: public sealed class SortedList<T> : IList<T>, IReadOnlyList<T>
{
[VisibleTo(typeof(SortedListExtensions))]
private readonly List<T> storage;
// ...
}
public static class SortedListExtensions
{
public static int GetInsertionIndex<T, TComparable>(
this SortedList<T> sortedList,
TComparable comparableValue) where T : IComparable<TComparable>
{
// Access sortedList.list directly to do a binary search
}
} @gafter @CyrusNajmabadi is this primarily a language ask or a corefx ask? |
Beta Was this translation helpful? Give feedback.
-
After reading the comment to my proposal #732, that referenced this issue, it seems that what you are asking for is similar to what I asked. Please take a look at #732 to see more use cases for this functionality. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Motivation
Often it's desired to have a finer level of control over visibility of type members within a project's boundaries, such as allowing constructors/members to be invoked only from certain contexts.
The existing
internal
modifier only affects inter-project visibility, but doesn't aid with safety within project boundaries.Overview
We propose a new top-level declaration,
visibility
, which defines visibility "contexts". Member/type declarations are then annotated, both at the provider/consumer side to control visibility.Syntax
In the following example, we want to control the initialization of
Node
instances.sees
clause appended to its declaration:sees
clause either before or after thewhere
clause:Further notes
Standard editor facilities can allow analyzing references to the visibility context (both at the provider/consumer side), allowing the code-base maintainer to ensure that the intended visibility scheme is preserved.
Beta Was this translation helpful? Give feedback.
All reactions