-
Notifications
You must be signed in to change notification settings - Fork 69
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
Add proposal for non-skipping generators #62
Add proposal for non-skipping generators #62
Conversation
Hi @dszoboszlay! I understand the need for this proposal but unfortunately I find the operators quite confusing. Reviewing code that uses this:
would be hard to decompress what exactly it means. Especially if I use Counter-proposalI'd personally go with the "binders" version with a couple tweaks.
The reasons to consider this counter-proposal are:
Downsides:
Edit: fixed a snippet based on @essen's feedback. |
Thanks for looking into this. Everyone had bugs caused by skipping at some point in their Erlang developer life. Binders seem less of a mouthful than the other solutions.
Not sure what that means, you probably meant
This should be deprecated regardless of this feature being implemented. |
Hi and thanks for the feedback!
With all due respect, I disagree with you on this one. I believe the operators may be confusing now because they're new, but they wouldn't be confusing once you've got used to them. Just like how
I don't see how this proposed syntax would unify all generator syntax? You'd still have If you want to sanitize and unify generator syntax, I believe EEP 12 has a much better proposal with
I disagree on this one. It's true that reusing the conditional match operator in comprehensions would avoid introducing a new operator, however it would give a very different semantic to the same operator in the two contexts. In a
While in case of comprehensions the documentation should probably read something like this:
I see some analogy here, but it's far from making the language more uniform. On the other hand I don't think introducing more operators for non-skipping generators would make Erlang significantly more complex. There are already many language elements exclusively used only in a comprehension context: Furthermore, here's this:
This is very true, and I believe it's mostly because skipping isn't properly documented. If you read through the docs on comprehensions it doesn't even mention the word "skip" (I only found out this is the official term by reading the compiler source code, I intuitively first called the current generator behaviour filtering), or specify what happens when the generator's pattern doesn't match. Now you may say that just documenting skipping would solve this problem. And it would indeed be a step in the right direction. But I'm afraid it won't be a solution. Because when there's only one way of doing something you do it that way, regardless of whether you understand all the edge cases or not. I think giving two different kind of generators to programmers would help them much more to keep in mind what's the difference between them. Because once you have to make a choice, you have to know what are you choosing between? It's like with I maybe wrong, but I strongly believe that for example in case of Javascipt people are aware of its horrible equality rules for two reasons:
So I think having two flavours of generators is the best way to eliminate skipped element bugs. Better than educating everyone to always use match-all patterns in generators and bind in a follow up step. |
I guess your mileage may vary, because I still get them confused from time to time and I have the Erlang compiler tell me what to do (especially in patterns). :) The issue is that the operators do not tell me what they do, so I have to rely on my memory all the time.
I agree this is better, in the sense that it is even clearer on what which operator does, I don't have to guess! However, it is quite verbose. The issue with today's comprehensions is precisely that I am meant to look at both By adding
Those would all be valid and have well-defined runtime behaviour. This is, IMO, too much syntax variation without context. TL;DR: this proposal uses one syntactical construct (operators) to control two things: the data type of the generator and if it skips or not, leading to too many variations. If bitstring generators could be unified to use |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good as EEP and can be accepted to the EEP list. Please post this EEP into the Erlang Forums.
We have taken all the feedback of this EEP into account but, as far as it goes, this is good enough.
As usual, syntax is the main issue. We suggest making the operators <:-
and <:=
instead of <-:-
and <=:=
because list comprehensions are syntactic sugar meant to make common operators shorter, and the latter will be needlessly verbose five years down the line when everyone is familiar with this -- similar to the story for maps. Having them differ by a single character, :
, also makes the operators easy to remember as ":
means non-skipping."
More feedback from the Erlang Forums can be taken into account later.
This is based on the feedback from @kikofernandez in PR erlang#62.
Updated this PR and the implementation with the proposed new operator syntax. I've also posted the EEP on Erlang Forums, but my post is pending approval at the moment. |
I generally agree with what José said about this proposal. I do not think the current "skipping" behaviour is surprising. For the languages that I checked that have both comprehensions and pattern matching (scala, haskell, elixir) the behaviour is the same as in Erlang. F# that I checked requires patterns to be complete and fails at compile-time with a "filtering" pattern. In my opinion, what is surprising in the Erlang comprehension implementation (and different from others) is that a binding is treated implicitly as a filter expected to return a boolean value. Indeed, if we look at how scala or haskell expect the fallible comprehension to be handled it's to have a plain variable binding followed by a fallible match. The proposal does correctly point out that fixing the matching behaviour does not address the problem of binary comprehensions, and it indeed is something to consider, but I'm not convinced that it warrants making other types of comprehensions more complex and introducing additional, non-standard operators. |
@michalmuskala Changing how variable binding works would be a breaking change though. Or are we still considering the pinning operator? I'd prefer that we don't add these operators. They make the language more complex. The convenience of this feature is not worth the added complexity. |
@zuiderkwast IMO we would find a syntax that uses the same operator |
The pinning operator is actually a good context to discuss here as well, though I wasn't actually thinking about it. With this proposal what would be the semantics of: X = 1
[X || X <:- List] Would it be matching (like patterns generally do) or shadowing (like generators in comprehensions do). This is probably an important semantic question to clarify before this proposal is finalised. With regular matching allowed, this question goes away since semantics of And yes, changing the meaning of |
Shadowing, like the |
This is an EEP accompanying erlang/otp#8625 that proposes the addition of a new, non-skipping variant of all existing generators (list, bit string and map). Currently existing generators are skipping: they ignore terms in the right-hand side expression that do not match the left-hand side pattern. Non-skipping generators on the other hand shall fail with exception
badmatch
.