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

Guidance on parentheses, more is better #3

Merged
merged 1 commit into from
Sep 24, 2013

Conversation

pminten
Copy link
Collaborator

@pminten pminten commented Sep 24, 2013

Parentheses often avoid problems and make code easier to recognize.

@nessamurmur
Copy link
Collaborator

Your examples are really helpful. Are you aware of any possible negative outcomes using def without perens, similar to the issue with the pipeline operator?

@pminten
Copy link
Collaborator Author

pminten commented Sep 24, 2013

No. But note that where Ruby has parenless methods that are virtually indistinguishable from fields, which is great to change a field to a computed value. I suspect this is where the Ruby convention for def is from. In Elixir this doesn't apply.

The parents after a def help as a visual hint that this is a function.

Ultimately it's a matter of preference though.

@nessamurmur
Copy link
Collaborator

Cool. Just curious because if there was I wanted to add an example for it.

Thanks for all your help!

nessamurmur added a commit that referenced this pull request Sep 24, 2013
Guidance on parentheses, more is better
@nessamurmur nessamurmur merged commit 4665ad8 into christopheradams:master Sep 24, 2013
@rsslldnphy
Copy link

I have to respectfully disagree with this - if there are no arguments to a function then the parens are just noise. Especially if you're chaining together a bunch of functions with the pipeline operator.

As an example from an exercism.io exercise:

def count(phrase) do
  phrase |> downcase |> sanitize |> split |> aggregate
end

versus

def count(phrase) do
  phrase |> downcase() |> sanitize() |> split() |> aggregate()
end

Parens are optional in Elixir for a reason :-)

@nessamurmur
Copy link
Collaborator

I actually agree with that... Really I'm thinking if anything there should be an example in the style guide that says "Don't start a chain of functions with a function call"... That's really the problem in the example that was given of how no parens could be a problem.

For example

#bad
downcase phrase |> codepoints

#good
phrase |> downcase |> codepoints

The function call at the beginning just looks messy to me and I feel like it could be easy to miss it's part of the chain.

Further more... maybe a section that says "No args = don't use parens, args = use parens"

#bad
function arg
function()

#good
function(arg)
function

What say you @rsslldnphy @pminten !?

@rsslldnphy
Copy link

Yes, you're absolutely right. To use the example from the commit:

# bad and parses as f(3 |> g), which is not what you want
f 3 |> g

# good
3 |> f |> g 

@rsslldnphy
Copy link

Although I tend to judge each situation on its own merits when deciding to use parens. Sometimes they aid readability, sometimes they hinder it. Readability should be the prime aim over conformance to any style guide! (as useful as I think this is :-))

@nessamurmur
Copy link
Collaborator

YES! Agreed!

I'm pretty deep into something else so if you're free to and desire please submit a pull request so it can either be pulled in or the discussion can be continued a little more visibly than on a merged PR.

If not, I'll probably do so late-ish this evening or early in the morning.

Thanks for you input!

@rsslldnphy
Copy link

No problem! Just about to cook tea but if I get a chance in a bit will submit a PR.

@pminten
Copy link
Collaborator Author

pminten commented Oct 16, 2013

Looking at the elixir source both function call as first element of pipeline and argument as first element of pipeline are used. Parentheses around unary function call (so empty parentheses) or not is also mixed (though admittedly most cases omit the parens).

@pminten pminten deleted the parens-are-good branch October 16, 2013 09:34
@nessamurmur
Copy link
Collaborator

Hmm... I made a couple changes last night on this topic. Maybe look over it and if you think it should be different open a new issue. I think that will be more visible and I'd like to hear more discussion on this topic and see more examples.

@pminten
Copy link
Collaborator Author

pminten commented Oct 16, 2013

Well I have to say I'm beginning to understand why some people are opposed to style guides. You can really only write them in two ways: by the original developers with a well thought out and reasoned style (which is what Go does) and by very experienced members of the community once an informal standard has developed. To do otherwise is to risk encoding arbitrary decisions.

What I mean by arbitrary decisions is things that "are about readability" without thinking about the subtleties of communication. I admit I'm guilty of that as well.

A few examples: def some_method() is considered bad. But think about what the () says. That's an almost universal programming convention for "does something". So where def foo by analogy to having a value foo implies that there is little computation involved def foo() implies significant computation.

Another example is the blunt rule that bare variables have to be used in the first part of a function chain. That makes sense for strings but consider Stream.concat(1..10, 20..3) |> Enum.reverse(). Do you honestly want to write 1..10 |> Stream.concat(20..3) |> Enum.reverse()? A more subtle point about pipelines that's often missed is that they are designed for functions that take their subject as the first argument, think methods. But functions like Stream.concat/2 don't really have a subject. Or take Stream.unfold/2, is the initial accumulator really the subject?

Writing good elixir code requires a feel for the language, to understand where to use which form, and I honestly doubt a style guide can convey the background necessary for doing this. Style guides convey strict rules, this is good and this is bad, but in reality things are never that simple.

Of course one could argue that strict rules are good for beginners but I'm seeing the downside of them there as well, a beginner that follows the "bare first argument to a pipe rule" might never pick up the feeling for how to use pipes effectively. And a beginner that follows the "every nested function call for the first argument must be a pipeline" rule might never pick up where pipelines make sense and where it's best to just use temporary variables. On exercism.io I've seen lots and lots of beginners write as if it is mandatory to use pipelines. The main Elixir code on the other hand doesn't use as much pipelines as possible, only where they make sense (such as with enumerables).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants