-
Notifications
You must be signed in to change notification settings - Fork 4.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deconstruction of formal parameters #15111
Comments
I want to say that I've seen comments regarding having patterns supported directly in method parameters. That may have been to permit overloading by pattern matching, although with infallible patterns that would seen to be about identical with this proposal. /cc @alrz Even if this were to be supported I'd think that you'd still be required to set formal parameter names as that is what ends up embedded in the CLR metadata and formal contract for the method. |
It's been discussed in #6067 and rejected per this comment,
However, it'd be always safe to use "complete patterns" in all those places, namely, |
It would seem that if that reasoning can be applied to dismiss deconstruction of tuples in the parameter syntax that it would likely apply to custom deconstruction as well. Of course those comments are over a year old, and a lot has changed in a year. |
@alrz I do not propose to allow all patterns in parameters, only those that cannot fail ( |
Trivial record types definitely provide additional type safety over bare numbers or strings. I use these types in ALL formal parameters in my business domains and have very good experience with that approach. I would like to encourage all developers to start experimenting using 'record types' as a wrapper for bare types. Of course, instead of not yet existing records, I use something very similar to translated code as shown in documentation (records.md). As a deconstrucion I use emailAddress.Value, velocity.Value, ... which is sometimes long and annoying, but not too much. Yes. It would be nice to have shorter and easier deconstruction. I'm not sure is this proposal right direction, but in my opinion the topic is very important. |
👍 This is one of those things I continuously kick myself for forgetting, it is well worth the cost.
I don't think that is the issue.
I think @gafter's point is very important. The desire to easily consume parameters via deconstruction or via or patterns will make for an inferior API in many cases that does not clearly express the abstraction that the caller must provide but rather its parts as they relate to their consumption within function body. Consider an example from another language: // This is JavaScript for comparative purposes!
// In ES5.1 style (no destructuring)
function submitOrder(order) {
if (blacklistedNames.includes(order.customer.name) || order.product.id) {
return Promise.reject(Error('blacklisted customer' + order.customer.name));
}
if (!order.items.some(item => availableProducts.map(product => product.id).includes(item.id))) {
return Promise.reject(Error('one or more items is currently unavailable'));
}
return httpClient.post(`api/${apiVersionCreatedWith}/orders/${id}`, order);
} In the above code, the consumer knows that // In ES2015
function submitOrder({ id,
apiVersionCreatedWith,
customer: { name: custName },
product: { id: pid },
items
}) {
if (blacklistedNames.includes(custName)) {
return Promise.reject(Error('blacklisted customer' + custName));
}
if (!items.every(({ id: id }) => availableProducts.map(({ id }) => id).includes(id))) {
return Promise.reject(Error('one or more items is currently unavailable'));
}
return httpClient.post(`api/${apiVersionCreatedWith}/orders/${id}`, {
id, customer: { name: custName }, items, product: { id: pid }
});
} In the above, I would argue, the simplicity for the caller is completely gone. There is no cohesion in the API, no notion of how the arguments must match up, just a subset of the objects fields associated and renamed as is convenient for the callee to consume. And this is not even by position. I guess my point here is that convenience of consumption should be secondary to providing a solid API. There are ways to do both but deconstruction directly into an argument list declaration is problematic. Note the JavaScript in the example can be rewritten with a destructuring binding inside the body to get the best of both worlds, or one can use TypeScript to mask the implementation signature with a proper API surface, but it is easy to get things wrong with this feature. |
Discussed in dotnet/csharplang#153 |
Trivial record types are a common pattern in functional languages, providing additional type safety over bare numbers or strings or tuple:
However, using them in C# requires additional deconstructing or constant member access:
I propose to allow positional deconstruction in method declarations.
Deconstructed parameters can lack their own names if they have only one parameter:
Deconstruction of types parameterized by deconstructible types, like
cc
inSendMail
above, is an open question:Perhaps it can be done rather straightforwardly for all monadic (LINQ-able) types.
The text was updated successfully, but these errors were encountered: