Skip to content
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

Make the compiler report 'and'/'or' operators as obsolete #9115

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

richcarl
Copy link
Contributor

@richcarl richcarl commented Nov 26, 2024

The strict 'and'/'or' operators are mostly useless, confusing for newcomers, rarely used in practice, and when used they can always be replaced with andalso/orelse. I think they should be obsoleted and subsequently dropped from the language.

Copy link
Contributor

github-actions bot commented Nov 26, 2024

CT Test Results

    23 files     856 suites   6h 34m 0s ⏱️
10 834 tests 10 281 ✅ 551 💤 2 ❌
21 273 runs  20 300 ✅ 971 💤 2 ❌

For more details on these failures, see this check.

Results for commit 875a5eb.

♻️ This comment has been updated with latest results.

To speed up review, make sure that you have read Contributing to Erlang/OTP and that all checks pass.

See the TESTING and DEVELOPMENT HowTo guides for details about how to run test locally.

Artifacts

// Erlang/OTP Github Action Bot

@essen
Copy link
Contributor

essen commented Nov 27, 2024

Should and and or be made to work the same as andalso and orelse in the future (after deprecation, removal, reintroduction, any other necessary steps, perhaps over a span of 5-10 years) so that we can shorten a bit our function clauses?

@richcarl
Copy link
Contributor Author

Should and and or be made to work the same as andalso and orelse in the future (after deprecation, removal, reintroduction, any other necessary steps, perhaps over a span of 5-10 years) so that we can shorten a bit our function clauses?

Nah, I thought I'd try to introduce && and || instead. :trollface:

Honestly I'm not sure. I think there's a bit of pedagogical value and visibility in the andalso/orelse keywords. (These names go back to Standard ML, if anyone wonders.) As I was replacing the occurrences of and/or in the code, I saw that a tiny 'or' or 'and' was easy to miss, but 'orelse' and 'andalso' stood out much better. So it might not even be worth doing, even if it saves horizontal space. We can submit a followup EEP in 2030 and see what people think then. 😜

Btw, replacing existing uses showed mainly two categories: 1) valid ways of writing more complex guards or other nested logical expressions (not all that common, in comparison to the total size of the codebase), and 2) as a personal style thing, where you could just as well have used comma and semicolon in a guard instead (only found in a few isolated modules) , possibly due to a lack of understanding of guard syntax. Also, a some of these occurrences probably go back to before semicolon was added to guards.

@essen
Copy link
Contributor

essen commented Nov 27, 2024

I saw that a tiny 'or' or 'and' was easy to miss, but 'orelse' and 'andalso' stood out much better.

Indeed. I just tried finding them in RabbitMQ to fix them and it is clearly non-obvious. The other two have this advantage.

@jhogberg jhogberg added the team:LG Assigned to OTP language group label Dec 2, 2024
@richcarl
Copy link
Contributor Author

richcarl commented Dec 3, 2024

@essen I did however come up with another use for 'or' (doesn't strictly require removing the original). Here's a very small proof of concept: master...richcarl:otp:or-patterns - e.g. case X of {a, Y} or {b, Y} or {c, Y} -> {yes, Y}; _ -> no end.

@essen
Copy link
Contributor

essen commented Dec 4, 2024

case X of {a, Y} or {b, Y} or {c, Y} -> {yes, Y}; _ -> no end.

That would definitely remove a frequent pain point with regard to case clauses! 👍

@richcarl
Copy link
Contributor Author

richcarl commented Dec 4, 2024

That would definitely remove a frequent pain point with regard to case clauses! 👍

Yes. It might be technically possible to use ; as separator, but I'm afraid it would get too unreadable. For example, foo({a, Y}; {b, Y}, {c, Y}) when Y >= $0, Y =< $9; Y =:= $@ -> {yes, Y}; _ -> no end. has the problem that ; binds tighter than , in the patterns, but the other way around in the guard. foo({a, Y} or {b, Y}, {c, Y}) when Y >= $0, Y =< $9; Y =:= $@ -> {yes, Y}; _ -> no end. is easier to read.

Copy link
Contributor

@bjorng bjorng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personally, I think that , and ; should be used if possible. I know that everyone does not agree with that.

As a compromise, if a guard only uses and, replace all and operators with commas. I think that is reasonable because , has been there since the beginning.

I strongly suggest that you remove the unnecessary parentheses on either side of andalso/orelse; not having to add those parentheses is one of the advantages over the older operators.

erts/preloaded/src/prim_zip.erl Outdated Show resolved Hide resolved
lib/common_test/src/ct_groups.erl Outdated Show resolved Hide resolved
lib/common_test/src/ct_run.erl Outdated Show resolved Hide resolved
lib/common_test/src/ct_run.erl Outdated Show resolved Hide resolved
@richcarl
Copy link
Contributor Author

Updated like @bjorng suggested. Definitely yields nicer code, but a bit harder to review.

@richcarl
Copy link
Contributor Author

Fixed , instead of ; in megaco that failed the type check.

@richcarl richcarl force-pushed the andor-obsolete branch 2 times, most recently from 36a6fd5 to 31d81e6 Compare December 14, 2024 22:08
@richcarl
Copy link
Contributor Author

The windows build died for some reason: /mnt/d/a/_temp/87953a19-9c2f-4c2d-bffc-af974820c086: line 1: 284 Segmentation fault apt install -y g++-mingw-w64 gcc-mingw-w64 make autoconf unzip.

@garazdawi
Copy link
Contributor

The windows build died for some reason: /mnt/d/a/_temp/87953a19-9c2f-4c2d-bffc-af974820c086: line 1: 284 Segmentation fault apt install -y g++-mingw-w64 gcc-mingw-w64 make autoconf unzip.

I re-triggered the windows run and now it seems to have passed.

@ieQu1
Copy link

ieQu1 commented Feb 8, 2025

and when used they can always be replaced with andalso/orelse

False. Sometimes one is after the side effects of an expression that returns a boolean, e.g.: [edited] This code runs several actions and returns true when any of them detects a change. orelse would totally wreak this logic.

confusing for newcomers

Please stop using this excuse to cripple a language: virtually anything can be confusing for a newcomer, depending on their background. Imagine the bewilderment of someone who switches from COBOL.

@essen
Copy link
Contributor

essen commented Feb 8, 2025

and when used they can always be replaced with andalso/orelse

False. Sometimes one is after the side effects of an expression that returns a boolean, e.g.: https://github.com/k32/anvl/blob/master/src/anvl_erlc.erl#L158

This is typically written over multiple lines, with the result computed from the intermediate results like

R1 = precondition(...),
R2 = [...]
R3 = [...]
R4 = [...]
R1 orelse R2 orelse R3 orelse R4

It's more verbose but also a lot clearer since you don't need to know the semantics of or or orelse to understand what is going on.

@ieQu1
Copy link

ieQu1 commented Feb 8, 2025

It's more verbose but also a lot clearer since you don't need to know the semantics of or or orelse to understand what is going on.

We can go further: orelse is utterly redundant (just as if, case, variables, function names, ...), and nobody should be forced to learn its semantics, because ι-combinator alone is Turing-complete.

@essen
Copy link
Contributor

essen commented Feb 8, 2025

We can go further: orelse is utterly redundant (just as if, case, variables, function names, ...), and one shouldn't have to learn its semantics, because ι-combinator alone is Turing-complete.

Let's not exaggerate, the problem is that there's two or and and, where there should be one.

Some people argue that if and case are in a similar boat and if should be removed.

I don't think I've seen calls to remove anything else.

@ieQu1
Copy link

ieQu1 commented Feb 8, 2025

Let's not exaggerate

I simply explained why "more verbose but also a lot clearer" is flawed argument, because syntactic reductionism leads there: [edited]
Sure, I can rewrite any code to avoid any syntax construct and semantic overhead.

the problem is that there's two or and and

There's no such problem. There are two pairs of operators with different semantics, just like & and && in C.

These operators have existed in the language since time immemorial, removing them won't make any code clearer, it will just litter the existing code with compiler pragmas: or is clear code, -compile(nowarn_or_and_and). isn't.

@ieQu1
Copy link

ieQu1 commented Feb 9, 2025

P.S. I speak on behalf of a small and unimportant group of people: those who're deeply invested in large and/or complex Erlang projects. There's already a growing problem of abandoned dependencies that we have to fork and maintain due to bit-rot. Such arbitrary changes to the language driven by subjective arguments will just waste more of our resources that could be invested into building new things.

@essen
Copy link
Contributor

essen commented Feb 9, 2025

syntactic reductionism

That is not what is happening. Some syntax gets added, some gets removed. We have to remove some things in order to improve the language.

P.S. I speak on behalf of a small and unimportant group of people: those who're deeply invested in large and/or complex Erlang projects. There's already a growing problem of abandoned dependencies that we have to fork and maintain due to bit-rot. Such arbitrary changes to the language driven by subjective arguments will just waste more of our resources that could be invested into building new things.

Me too? The removal of or/and has a very small maintenance impact. There's been far more complex removals such as parameterised modules.

@jhogberg
Copy link
Contributor

jhogberg commented Feb 10, 2025

Friendly reminder that a compiler warning is just a warning, and that we still retain obsolete things like atom/1 (obsoleted by is_atom/1), functions like queue:lait/1 (misspelled version of queue:liat/1), the aforementioned parameterized modules (now handled by the compiler rather than the runtime), et cetera.

As such, we are not going to drop and/or from the language. Warnings are nothing more than recommendations from the OTP team, and the PR asks us to recommend against the use of and/or. I am personally inclined to do so: the only reason to use these over andalso/orelse is to evaluate all arguments for effect, however, the evaluation order of these operators is undefined so a small change in the compiler can cause code to stop working when there's an implicit dependency between the arguments.

If the PR is accepted, you're free to disable the warning project-wide because it's fine not to follow our recommendations. Again, warnings are not an indication that we are about to remove something.

Comment on lines +2520 to +2527
warn_obsolete_op(Op, A, Anno, St) ->
case {Op, A} of
{'and', 2} ->
add_warning(Anno, {deprecated, "'and'", "use 'andalso' instead", "OTP 29"}, St);
{'or', 2} ->
add_warning(Anno, {deprecated, "'or'", "use 'orelse' instead", "OTP 29"}, St);
_ -> St
end.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a way to disable this warning, and keep it disabled by default for now. Regardless of what decision we're going to make, I still see it as a useful optional warning.

@michalmuskala
Copy link
Contributor

There's one more issue with and and or that hasn't been mentioned here and that is their quite surprising precedence. X > 3 or is_tuple(X) is parsed as X > (3 or is_tuple(X)) - normally this would result in an exception, but in a guard this causes a silent failure and can lead to hours of debugging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
team:LG Assigned to OTP language group
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants