-
Notifications
You must be signed in to change notification settings - Fork 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
Proposal: Non-Positional Parameters #1478
Comments
This can be achieved with a custom analyzer. I don't see a reason for this to be added as a new syntax restriction. |
I agree with @Logerfo , the behavior from the compiler can already be enforced through an analyzer, especially given that your proposal pretty much builds on existing syntax (except where you get into generic attributes, but you can always use a I also think that tooling support in the IDE, either built-in or through an extension, could give this behavior to you for free without requiring any changes to the language/compiler, as mentioned here: #1462 (comment) |
Right, that is not part of this proposal. I just think it looks nicer. 🙂 |
@Logerfo I can't enforce consumers of my API to add my analyzer. Your suggestion would limit applicability. (At least I don't think I can. Correct me if I'm wrong.) |
@HaloFour I do like the IDE suggestion. |
Similarly you couldn't force customers to use a specific version of the C# compiler, and older compilers would be unaware of this attribute and how it should restrict compilation. Or compilers for other languages. Ultimately I think it should be up to the consumer of any given API to decide if embedding the parameter names at the call site is valuable to them, not the author of said API. I wouldn't use an API that attempted to force my hand in such a manner. |
Fluent APIs tend to enforce descriptive usage. I use them regularly. This proposal is a small step toward adding a fluent API but without all the hassle. |
Why should the method writer care about how some unknown consumer of the method is going to write the method call? If the method writer really cares, they'd do better by not creating that many parameters in the first place. Also, the method writer might think his method won't be legible if the arguments aren't explicitly named at the call site... but that isn't necessarily the case. A good choice of variable names can still result in a reasonably understandable call. (For example, no point in forcing the consumer to spell out an argument |
@stakx I agree, this does look nicer: AddStudent("Amanda Jones", lockerAssigned, outOfStateTransfer, throwOnError, overwrite, gradeLevel, retryCount, timeout); Except that I accidentally switched two arguments. And you probably had to look at the top of this page to see which ones. |
@bondsbw - Yes, given that many Since I mentioned API design, here's some possible alternatives that might reduce or even obliterate the need for enforcing named arguments:
There's probably many more options. What I'm saying is that a not-to-well-designed method (IMHO) like |
P.S.: In case this feature request gains traction, I'd be happy if at least the compiler deemed e.g. |
The crappiness quotient of a method can be expressed as (number of parameters)^(number of boolean parameters+1), with 1 being "not at all crappy" and this example, of 8^5, or 4096, is pretty damned crappy. I'm with @stakx here: don't fix this with compiler bodges; fix it by reducing the number of parameters. |
Of course. That's the point of this proposal, reducing hidden intent. The problem goes beyond Booleans and includes most types of constants. We can't tell what those integers mean any more than we can tell what the Booleans mean. |
That's the other goal of this proposal, KISS. Alternatives inevitably require more stuff. Maybe you need an enum for your flags. Or a class to hold all the parameters. Or more methods (and possibly more types) to create a fluent API. Those all work great, but they aren't as user-friendly. |
That only works if all the parameters are optional. |
I'm going to note that I'm not particularly arguing against the idea of requiring the parameter names at the call site. I think it's a good debate to have when designing v1 of a language. But we're leading into v8, positional parameters are the standard and there's nothing that you can do as an API author to force any consumer of your API to actually use a version of the compiler that can enforce such a behavior. That reason, above all others, is why I don't feel that this proposal is not a good fit for C#. |
This is somewhat minor (IMHO). Existing behavior is a reasonable fallback. |
Which then breaks if the user updates the compiler, even if they are entirely unaware of whether various APIs they consume might try to enforce this behavior. |
The best solution to make method parameters a less mess is a
I often use structs for public APIs parameters instead of long parameter lists. |
@Opiumtm As stated above, it's more work for the implementer and still not a solution for required parameters. |
@bondsbw Required parameters could be at non-default struct's constructor, of course. |
@Opiumtm It misses the point of this proposal. There is no way to require the caller to specify those argument names. |
It's more work for the implementer once. A struct with readonly values for required parameters, initialized from a constructor, handles required parameters quite well, I believe. Note also that there's no requirement for everything to be contained in the one struct. Take your original example:
One possible restructuring of this would be:
In this scenario, it's likely that |
@theunrepententgeek How does your example force the caller to supply parameter names for required parameters? That's the purpose of this proposal, so failing to address that specific need is pointless. |
Because the NewStudentInformation and ServiceOption bool/int settings are not part of their respective constructors, and so must be explicitly set. var newStudent = new NewStudentInformation("James Smith")
{
LockerAssigned = true,
GradeLevel = 9
}; etc, etc. |
@bondsbw I think you're missing my point, so let me be more explicit. I think this proposal provides an approach for papering over problems in badly designed method signatures.
I'd suggest that enhancements to C# should primarily fall into one of two categories: features that make the language more powerful and expressive (async/await, shapes, records, etc) or that encourage good development practices (e.g. expression bodied members encouraging short implementations). I don't think proposal falls into either category. |
@DarthVella Those named parameters are not required. You left some out, demonstrating my point. @theunrepentantgeek This proposal is intended to fix the bad part. I don't feel this is a problem in Objective-C for example, where parameter names are required. I feel this squarely meets your second criteria by encouraging readable method calls, and without extra structs which require more typing just to "fix" this problem for the subset of cases where the parameters are optional. |
This was a part of the initial design of Objective-C, not added in a much later version. It's interesting that in Swift they make it possible to define functions that don't require the argument labels. |
Some who come from an Obj-C background feel that aspect of Swift was a mistake. That said, I concede that there is little support for this in C#. |
@bondsbw The example I gave relied on the default for OutOfStateTransfer being false, but I'll concede the point. |
Coincidentally, I just found out via a mailing list that Python added this concept in version 3.0. |
Indeed, if we really were trying to copy the concept from Python 3 then this proposal might extend #1458 in this way: public void AddStudent(string name, params, bool lockerAssigned, bool outOfStateTransfer,
bool overwrite, bool throwOnError, int gradeLevel, int retryCount, int timeout)
{
...
} |
Positional arguments can be easy to write but difficult to read:
To fully understand this call, you need to cross-reference the
AddStudent
method signature.The caller can optionally choose to name the arguments:
But this is unenforceable.
Proposal
Allow the method writer to require arguments to be named.
NonPositionalAttribute
, applied to a parameter, will require the argument to be named.In this case, only
name
is allowed to be called without a name, while all the others must be named.Considerations
NonPositionalAttribute
could be applied at the method level to require all arguments to be named. This could be applied even more broadly, such as the class or assembly levels.The text was updated successfully, but these errors were encountered: