Proposal: Shorter syntax for exposing sub-object methods #3809
Replies: 4 comments
-
Rather than changing the language, this seems like a good application of source generators. |
Beta Was this translation helpful? Give feedback.
-
i think that a concise syntax for forwarding would aid tooling. I think that it would also aid development as forwarding is quite a common operation, however i believe method group expansion (1 member compiles into many members) is the realm of source generators, due to potential opaque binary breaking changes. i doubt the language team would be happy with a feature that allowed upgrading a third party library (the source of the forwarded type) to be a binary breaking change - which any automated method group expansion feature would be. |
Beta Was this translation helpful? Give feedback.
-
How would this introduce opaque binary breaking changes though? I would argue this syntax is not more risky than writing Sure, if I update the thirdparty library A and it adds a method which now makes any reference in my library B unclear, this will hit me at compile time. And if the issue is not in my code but in somebody else's code C who uses my library B, then they will have a compile time error when they try to recompile against my new library B. But the old binaries of C or B are not containing method groups anywhere, just calls to existing methods in B and A. So unless that method gets removed in A, B and C will work - and if A removes a method, code will break, no matter if I wrote all forwarding methods by hand or used a shorthand syntax. |
Beta Was this translation helpful? Give feedback.
-
It does though if you use the In your example, it would look like:
I will say that the introduction of expression-bodied members has greatly reduced the amount of boilerplate noise we have to write. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Many composed classes and wrappers have the sole purpose of selectively exposing single members though forwarding. Currently, this can be quite a lot of code to write, especially if the class in question has a lot of overloads. A shorthand syntax for exposing sub-object methods would be very useful in many cases:
Current code:
Disadvantages:
<inheritdoc>
doesn't work since this is not inheritance).Proposal
Method referencing
This will automatically create forwarding members with the same signature and documentation as the referenced member. By changing
public
to e. g.protected
you can modify the accessibility of the generated forwarding member.Variants
There could be even shorter and more versatile/powerful syntax, but their usage bears risks:
Method group referencing
Length
andFoo
look the same, but since "Foo" references a method group, create forwarding methods for all members of the method group.Risk: if the wrapped class adds new overloads, this will also add new overloads to the wrapper. However, this would arguably be a desired behavior for many (most, even?) wrappers, and inheritance does the same (but not even limited to new overloads of existing functions) and it's not a problem.
Return type inference
Create methods for all members of the method group and pass back their results.
Risk: while being useful in general for even shorter syntax, there are cases where changes to the wrapped object's API do not only change the API of the wrapper, but may vitiate the whole purpose of that wrapper. Imagine a "ReadOnlyWrapper" selectively forwards some void methods of a mutable instance using the
public ref
syntax. Now the wrapped mutable gets changed to a fluent interface. Suddenly, theReadOnlyWrapper
will expose the mutable object.It is supposedly a very weird and rare scenario that can be easily avoided by using
public void ref
instead ofpublic ref
, but it's a risk worth noting nevertheless. Probably, using the syntaxpublic dynamic ref
instead of justpublic ref
makes this more obvious.= Choice of syntax =
I propose using the
ref
keyword. My reasoning was as follows: I definitely did not want to introduce a new keyword. Looking at existing keywords, these keywords seemed suitable to be generally relatable to the concept of call forwarding:abstract
,as
,base
,delegate
,implicit
,interface
,ref
,using
, andvirtual
. I ruled outabstract
,delegate
,implicit
,interface
, andvirtual
, since they are already used as keywords within classes.as
would make sense for an alias, but writing a readable syntax without repeating 90% of the signature was impossible.base
implies inheritance too much, when the concept at hand is actually composition, not inheritance. The only two remaining keywords wereref
andusing
. Sinceusing
already has multiple meanings, andref
somewhat conveys the principle of defining a mechanism where you pass something in and get something out again, I choseref
. As mentioned earlier,ref
is not a valid keyword on class level yet, so conflicts are impossible.Beta Was this translation helpful? Give feedback.
All reactions