-
Notifications
You must be signed in to change notification settings - Fork 3.4k
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 option to formatter to rewrite unless #13769
Conversation
Thank you @sabiwara. ❤️ I am generally ok with this change. I think the automatically rewriting will definitely leave some gaps for improvements, but I really can't see any loss of readability in any of these changes (before or after adjustments). I'd love to hear folks thoughs on this one. PS: Also a separate discussion, but we should probably pick a default name for all "rewrite" options. The two that exist today are called |
Co-authored-by: José Valim <jose.valim@gmail.com>
5f0d749
to
3d2dbff
Compare
Rebased and opening for reviews. Opinions welcome. If we agree on this one, the next step would be to add the I'm still on the fence if we should include the existing |
I think changing normalize is fine. If you are setting it today, is to set it to false, which will be the new behavior anyway. Plus if you ran it once, you don’t have to run it again, which makes it a perfect candidate for migrate. |
Sounds good. If we are OK with this current PR, perhaps I can merge it and work on the flags in a follow-up PR? |
I'm all for it! the only thing i'll really miss is the succinctness of using it to raise exceptions ( styler rewrites some forms to that said, here's a very convoluted code snippet (people have done stranger) that i'd be curious to see a rewrite for: unless x = false, do: !x neeeeevermind, i saw it gets negated (didn't know you could wrap assignments in
|
@@ -1794,7 +1794,7 @@ defmodule FileTest do | |||
stat = File.stat!(fixture) | |||
assert stat.mode == 0o100666 | |||
|
|||
unless windows?() do | |||
if not windows?() do |
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.
these are manual !
to not
tweaks right?
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.
Correct (you can see individual commits to see what is automatic or tweaked)
:>, | ||
:>=, | ||
:<, | ||
:<=, | ||
:in |
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.
and
and or
could be added here?
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.
I wish we could, but unfortunately this wouldn't be safe and might break code that is working today, since false or 42
is valid (also arguably pretty bad) but not (false or 42)
would raise.
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.
ahhh right, i always think that those are bool, bool -> bool
, forgot it's bool, any -> any
i'll just join you in wishing we could then
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.
I guess we could try harder in these cases, checking if the right handside itself is a guard/comparison... but I'm not sure it's worth the extra complexity and it won't capture cases like and enabled?
anyway.
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.
alternatively, only use not
with in
, and for the 4 comparisons rewrite them to their opposite like with the equality operators:
{:>, meta, [left, right]} -> {:<=, meta, [left, right]}
{:>=, meta, [left, right]} -> {:<, meta, [left, right]}
...
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.
I hesitated between the two approaches, not sure which would be better. Maybe yours is more natural indeed.
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.
Actually not
might be better in this case, if we consider that the user explicitly wrote:
unless x > @limit do
over
if x <= @limit do
which they could have done in the first place, then
if not x > @limit do
might read better to them for some reason?
It is not critical though, people might see the diff and fix it to their preference eventually.
So I'm fine with either approach.
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.
yeah, i think you're right. if not
is a simpler change to reason over than if $swapped_equality_operator
. thanks for spelling that scenario out.
Yes it is quite unreadable and people might want to do it differently, but it feels quite a rare case since assignment is mostly useful for |
Closing this one for now, merged #13808 and will reopen when I have something more ready with the full implementation. |
@sabiwara we also don't need to rewrite all of them. If we can rewrite most, that will already help many codebases migrate. |
May I ask for the context I'm missing on the motivations for this work? is |
@novaugust yes the idea is to eventually deprecate |
cool -- if that's for sure happening i'll steal what you've started here and have styler drop unless as well then =) |
{op, _, [_, _]} when op in @bool_operators -> {:not, [], [condition]} | ||
{guard, _, [_ | _]} when guard in @guards -> {:not, [], [condition]} |
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.
a thought i had while implementing this for styler -- being smart and using not
here might be dangerous, because it's possible the user did something whacky like
import Kernel, except: [is_atom: 1]
def is_atom(...), do: :ok
better to just always use !
and leave it to the user to translate to not
as they want?
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.
The idea behind migrate option is that they rewrite the AST and cannot guarantee to work in edge cases where metaprogramming assumes a given AST or Kernel overwrites are done (after all people can have re-defined unless
itself, or ==
, etc...).
This particular one feels like an unlikely case, the need to overwriting is_atom
feels low, the convention that only guards returning booleans should start with is_
should also discourage it... I think we're fine.
This is still a draft in order to explore the possibility, not ready yet.
I haven't started to work on the
--migrate
flag inmix format
yet, this is focusing on theunless
rewrite itself.Commits are organized to help the review:
defmacro unless
)