-
Notifications
You must be signed in to change notification settings - Fork 323
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
Confusing handling of named arguments #7359
Comments
I'm not sure what would be the proper solution for this.
|
This behaviour is consistent with point (2) of the Named Arguments section in the function arguments design: https://enso.org/docs/developer/enso/syntax/function-arguments.html#named-arguments This probably rules out (1) - as I suspected - it is unlikely possible to reconcile reordering named arguments with currying. However still, I think we need to look into (2) - currently the user experience of using named arguments can become a rabbit hole. Maybe actually we could somehow 'group' arguments to user-facing components that do not resort on currying and still have (1)? I'm not a fan of doing this as that would make the language less uniform. However from the UX perspective - we definitely want to have clear error messages and intuitive handling of arguments - and the current state is quite far from that - as shown here or in #5219 - i.e. when you misspell an argument name. This may not be as high priority though, as the IDE should generally manage arguments of nodes and so it should be much harder to trigger these errors in the IDE. I imagine the only scenario is when the library version has changed between runs of a workflow and an argument was renamed there.
|
For case 3: After we've supplied "A" and "C" (as parameters So that in case 4, we don't even get to the point of trying to call |
Yes, that would be ideal. I think there are some challenges to that (we need to ensure that some function returned further downward the chain will not be taking this parameter). We can relatively easily check this if the return value evaluates to something that is not a Function anymore. Then, if we still have 'pending' named arguments but have something that is not a Function, instead of a Type error, we could display this more specific error. But the general case and one shown in (4) is actually not that simple. The issue is currying - at the point where we are, we do not know if after we get the last parameter we are waiting for ( e.g.
As demonstrated in
Here we don't know what the parameter be and if If we do
Then But if we do
then this will reduce to a function waiting for parameters named |
I guess what we can do, is detect cases where a Type error is thrown or whenever a "Function value with pending unresolved named arguments" is encountered, and handle the errors specially. In particular, I'm not sure that the entity "Function value with pending unresolved named arguments" should be of type This is really hard, I'm not sure what the right solution should be but we definitely should try to improve this as currently the errors can be very misleading and basically unreadable. |
Can we include looking at partially applied constructors within the type checking in this ticket please. |
These seem to be rather completely unrelated issues, shouldn't we create a separate ticket for it? Or are they actually related? |
I think they are related.
If there is an argument that requires some type, but gets
... arguments. Of a function or ...
... at that moment we should look at |
I see, ok. It will be great to have both of these issues improved 🙂 |
Jaroslav Tulach reports a new STANDUP for yesterday (2023-08-23): Progress: - fixing
Next Day: Python Interop on Mac CI + fixing the |
Fixes #7359 by printing more information about the function including partially applied arguments and over-saturated arguments.
The improvements in #7629 are amazing and have improved the issue greatly. But I think there is still some cases that need some love. Please see the following example:
it yields:
I can see two problems with that:
The error like described in (2) / line 5 is acceptable if all arguments were filled in - we already computed a value and the user is providing it more arguments. But here not all arguments were filled in. It was only the required ones. I'm wondering if we could somehow be able to tell the user that the argument name was wrong (i.e. got I'm not exactly sure how we can best solve it (because there are limitations), but I think it may be worth to investigate this further. One problematic limitation to the example above is, I can have another example like:
Here, we can see that I cannot 'just' stop at 'expecting argument I'm not sure how to solve this. |
As designed. We don't display arguments with |
I believe it could be solved by removing the possibility to re-order arguments. But as @kustosz wrote:
I am not sure it is the most important point, I believe the point of named+defaulted arguments is to not have to specify them all. I believe that, if we remove the ability to specify arguments in random order, we can solve these issues. However it is a significant change to the language and needs to be discussed with major stakeholders. I don't think it would affect the IDE experience, so it may be acceptable, but I happily leave the negotiations up to you, Radek. |
my two cents: specifying w out of place should be an error - default parameters being able to be specified out of order is fine, but they shouldn't be allowed to be specified out of order when the arguments come from different declarations. i think this is especially true if w does not show up in the docs in the first place, in which case i think it would be counterintuitive to accept w before z ... alternatively another possibility may be to add metadata about function parameters to the type, to make the entire call possible to statically analyze? |
I though this applies only to argument with default value. Then that's ok. But here the value is overridden with value provided by the user. And in that case not displaying it does not seem ok. |
OK, that can be fixed. You can report a bug for me. |
One thing to mention is currying. There should be no way to tell a difference between However If we want to improve the error messages, then (I believe) we have to restrict the freedom people have when providing arguments to a function. E.g. |
Ok: #7723 |
I like your idea. I think looking at the practical use of the language, it is really important to get good, easy to understand, error messages. Your PR has already improved this vastly, but I think we are not yet 'there'. What you are proposing here could make it much better. As you mentioned, this would not change the semantics from the GUI perspective, since there we specify the arguments in the right order 'anyway'. It may make the life of text users slightly harder, but IMHO the benefit of better error messages far exceeds the benefit of being able to reorder named arguments. |
Enso reconciles currying, named arguments and argument default values. This however introduces some trade-offs.
TL;DR
There is a specification of named arguments behavior and to quote it:
@JaroslavTulach interprets that as a confirmation the current behavior is correct and all we can do is to improve error reporting as Radek concludes too.
Original Report
Here I encountered one such issue where the various trade-offs make the behaviour very confusing to the user.
yields us:
Let's unpack what is happening here.
b
argument as named - it is correctly reordered.b
argument comes last. This is the most interesting example showing the issue. Due to how our argument resolution works (and this is not fully avoidable if we want to support currying, at least not without some careful limitations), what the system sees: I see argument"A"
, I pass it to parametera
, then I see"C"
, I've got a function waiting for an argument namedb
- OK all looks good - let's take it. Then I see a named argumentb="B"
. OK but I have a function taking a parameterc
only - no match - the resolver "suspends" this argument, hoping that once more arguments are provided, maybe our function will return a new function taking more arguments and one of its names will match my pendingb
? Maybe. For now I return a value containing a Function waiting for one parameter - that is what is printed. Note that this 'suspended pending argument'b="B"
is hidden and it is impossible to see that we are waiting for this argument."D"
. So my function from step (3) was waiting for one more parameter (namedc
). I got an unnamed argument"D"
- OK - that sounds good - I provide this argument for the parameterc
. This runs my functionfun
with argsa="A"
,b="C"
andc="D"
- it executes and returns aText
value"ACD"
. But the resolution continues - I'm still pending a named argumentb="B"
. Ok but what the function returned is aText
value, not aFunction
- so a type error is invoked.The case (5) alone is problematic, as I get a weird type error which does not really tell me what went wrong. That case is actually an instance of #5219.
But (4) shows something even more concerning. What I do is I expect
fun
to return me aText
, so I calllength
on it. What happens then is that my resolution is currently suspended. It resolved to a function that is waiting for one parameter namedc
and is also waiting to apply one named argumentb="B"
. The object returned is aFunction
holding all that 'state'. I calllength
on this and I get a message that aFunction
does not have a method calledlength
. Well, fair - functions don't have those. But I have not expected a Function, I've provided 3 arguments to my functionfun
and I expect it to return aText
. Instead, I see I'm getting a function - so this looks like a usual case of "not enough arguments" - if I have a functionf x y
and provide justIO.println (f 1)
I get a function. But wait - I look at the code -fun
is expecting 3 parameters and I did provide 3 arguments!. The issue is that the argumentb="B"
did not match and is silently suspended, with no way to see it.I've just lost about 30-40 minutes trying to track down a case in my code when this was happening. It is a very confusing kind of error message, because it suggests we do not have enough arguments, but we have all the arguments that we need!
The text was updated successfully, but these errors were encountered: