christopheradams / elixir_style_guide Goto Github PK
View Code? Open in Web Editor NEWA community driven style guide for Elixir
A community driven style guide for Elixir
I've seen:
with {:ok, user} <- User.get(id),
{:ok, posts} <- Post.by_author(user)
do
{:ok, posts}
else
error -> error
end
with \
{:ok, user} <- User.get(id),
{:ok, posts} <- Post.by_author(user)
do
{:ok, posts}
else
error -> error
end
amongst others including using the do:
form of the block, although I'm not sure if that format works with an else
clause as well.
There's a nice list now to show the preferred ordering of things:
defmodule MyModule do
@moduledoc """
An example module
"""
use GenServer
import Something
import SomethingElse
alias My.Long.Module.Name
alias My.Other.Module.Name
require Integer
@type params :: [{binary, binary}]
@module_attribute :foo
@other_attribute 100
...
end
But where does defstruct go in this list? Since it's pretty tightly bound with the module, I figure it should go somewhere near the top, but I could see the defaults needing/wanting to use aliases, or perhaps the module attributes... I hesitate to put it too far "down" the list because then it may not be so obvious that the module is actually a struct... Suggestions?
First, you say to put spaces around operators. There was no mention of ranges, they use '..' which can be seen as an operator, yet I don't think most people put spaces around those.
Then there's '::'. They're present in specs (to specify the return type) and binaries. Should we surround them with spaces in both cases?
Maps and structs. If I understand correctly, tuples must be written {:as, :such}, however, does it still stand for maps and structs? %Point{x: 0, y: 0} seems a bit "crowded" to me, but I've seen it in multiple repos.
List patterns, head and tail. I've seen both [head|tail] and [head | tail], and I'm not sure which one to use. The second one looks cleaner to me, and it fits with the rule that says to put spaces around operators. You've used [first|rest] in your examples.
I probably forgot a few other things, but this is all I can think of right now.
Should there be a line length limit? I have my editor set up to make text after 80 chars a vivid red. I think there also needs to be guidelines for wrapping function definitions:
# This is too long...
def handle_info(:run_build_script, state = %{config: %{repo: repo, script: scr, git_cmd: git_cmd}}) do
...
end
Consider the codes below:
File.stream!("path/to/some/file", read_ahead: 100_000) # NEW!
|> Flow.from_enumerable()
|> Flow.flat_map(fn line ->
for word <- String.split(empty_space), do: {word, 1}
end)
|> Flow.partition_with(storage: :ets) # NEW!
|> Flow.reduce_by_key(& &1 + &2)
|> Enum.to_list()
Notice the pattern in this bit:
Flow.flat_map(fn line ->
for word <- String.split(empty_space), do: {word, 1}
end)
for
is only indented by two spaces, and end)
is indented on the line as Flow
I have seen many different ways on how they were written, but this seems to be cleanest way.
Ref: http://elixir-lang.org/blog/2016/07/14/announcing-genstage/
defmodule SomeNamespace.SomeModuleName do
defstruct name: nil
@type t :: %__MODULE__{name: String.t}
def new, do: %__MODULE__{}
end
What do you think about using __MODULE__
as it is used in new
method.
(Already saw @type t :: %__MODULE__
in Elixir sources and that looks good.) And in general what about a recommendation to use __MODULE__
through whole module against to manual qualification of the name like SomeNamespace.SomeModuleName
. Hope I was clean enough (:
In the Modules section, it would be nice to have some guidance on where defstruct should go in relation to @behaviour, use, import, etc.
In the section, "An atom can be used as a catch-all expression in a cond as it evaluates to a truthy value. Suggested atoms are :else or :otherwise"
suggestion of :default can also be added.
default is also the catchall condition in C switch statements, and should be familiar.
There's no guide for a function which has a long guard clause.
How Ecto project is doing:
def escape({{:., _, [{var, _, context}, field]}, _, []}, _type, params, vars, _env)
when is_atom(var) and is_atom(context) and is_atom(field) do
{escape_field(var, field, vars), params}
end
There is a rule under Source Code Layout which reads:
...but run single-line def
s that match for the same function together.
def some_function(nil), do: {:err, "No Value"}
def some_function([]), do: :ok
def some_function([first|rest]) do
some_function(rest)
end
I'm curious how applicable this is or if there are any edge cases or other issues or problems it causes. Should it be amended? Does anyone have counter-examples?
Thanks to @DavidAntaramian for bringing this up on another channel.
One of the things I discussed with Christoper earlier via Slack is that I didn't agree with some of the positions taken in the style guide. That's not a criticism of the guide; in fact, I think that the chain of maintainers for this guide has gone to great lengths to ensure that the guide is community driven.
However, I think that the guide can be improved by presenting the rationale of why the guide adopts each particular choice it does. That way, when someone expresses disagreement, they can present a counter-argument to the current choice that can be evaluated by the community. That will make future discussions like #116 easier since the evaluation happens without having to dive through "why was this decision made in the first place; what was the rationale?"
Swinging to the opposite side, I think it would be good to have a note at the top stating that we are presenting a community-reviewed set of options that allow for cohesion and a starting point. I realize that's partially addressed in the "Getting Involved" section, but I just think it would be good for people to see it when they first start reading the guide. We're not intending to create solemn law that must not be violated upon pain of exile. Or as I was telling @christopheradams, this "is more what you call guidelines than actual rules."
After you use a multiline pipe to set a result leave a blank line to as a visual marker that the pipe
is "over".
This :
inner =
args
|> Enum.map(fn(tp) -> format_doc_arg(tp) end)
|> Enum.join(", ")
"("<>inner<>")"
Not This:
inner =
args
|> Enum.map(fn(tp) -> format_doc_arg(tp) end)
|> Enum.join(", ")
"("<>inner<>")"
Great initiative with a style guide!
I'd like some directions in the guide on writing structs, both when doing defstruct
and when initializing them using %StructName{...}
. I'm new to Elixir so I don't have much to say here. Some scenarios that I've though about is when declaring och using structs and splitting it on multiple lines. Should the continuations be aligned with the first key/expression or just 2 spaces in?
I was wondering how to name a private method especially in a situation where it has the exact same intention but accepts some additional parameters(e.g.: accumulator)?
For example:
defmodule Factors do
def factors n do
_factors HashSet.new, n, n
end
defp _factors set, _, 0 do
set
end
defp _factors set, n, x do
if rem(n, x) == 0 do
_factors HashSet.put(set, x), n, (x-1)
else
_factors set, n, (x-1)
end
end
end
In the current style guide, the only real commentary on pipelines is:
# Multiline pipelines use a single level of indentation.
some_string
|> String.downcase
|> String.strip
(sidenote: "single level of indentation" here seems to imply no indentation, unless I'm missing something?)
But what about when the result of that pipelining should be bound to a variable? Like
result = some_string
|> String.downcase
|> String.strip
I've found myself indenting the pipelines by two spaces to give a little bit of clarity, like so:
result = some_string
|> String.downcase
|> String.strip
but I'm curious if anyone else has a take on this? Or is binding the result of a pipeline frowned upon for some reason?
Any suggestions about having/not having an empty line between module header and first function?
And could we add it to the guide?
So which one should be preferred?
defmodule some_module do
def some_function do
# function body
end
end
or
defmodule some_module do
def some_function do
# function body
end
end
I'd like to challenge this:
# Multiline pipelines use a single level of indentation.
some_string
|> String.downcase
|> String.strip
with:
# Multiline pipes should be indented.
some_string
|> String.downcase
|> String.strip
I realize that the first version is something that has been used pretty much everywhere but I believe it is misleading to the eye. Indentation implies a relationship to the outdented value, not indenting could imply there is no relationship.
Thoughts?
list the three styles ourselves, and maybe write a small description about each one, and what makes them different with this style guide.
Proposed by @eksperimental in a commit comment here.
I think it is both more readable and prettier to separate use/import/alias/require groups with a blank line.
# preferred
defmodule MyModule do
use Xenserver
import Something
import SomethingElse
alias My.Long.Module.Name
alias My.Other.Module.Name
require Integer
...
end
# not preferred
defmodule MyModule do
use Xenserver
import Something
import SomethingElse
alias My.Long.Module.Name
alias My.Other.Module.Name
require Integer
...
end
There is currently no guideline on function calls with multi-line arg lists. For use-cases I encountered most often, following rules works for me:
# call with parentheses, first argument in-line with function
some_func(:first_arg,
:second_arg,
:third_arg)
# call with parentheses, first argument in new line
some_funct(
:somewhat_long_expression_for_argument,
:second_arg,
:third_arg)
# call without parentheses and keyword list
some_funct :regular_arg,
keyword_arg: "option",
other_keyword_arg: "there"
I am aware that third example (without parentheses) is conflicting with Use parentheses in function calls, however I find it quite verbose in various configuration-related code with long keyword lists.
Thoughts? Suggestions?
The style guide states:
Later, it states:
# preferred
f(3) |> g()
I'm unclear about whether the parens in g()
are intentional (I don't believe there's any parsing ambiguity). If they're intentional, I suggest revising the language to say Use parentheses in function calls within a pipeline, even without arguments
. However, if that's just an oversight the example should be f(3) |> g
.
I'm happy to PR the change if someone can clarify the intent.
There are a number of examples of use of IO.puts "A string value"
, but by this style guide functions with arguments should make use of brackets.
Therefore I think the correct styling should be IO.puts("A string value")
Like Ecto.
Hi
I was reading the elixir documentations and I would like to know when should we use partials[1].
for example, what would be the prefer way to say this
list = [1, 2, 3]
Enum.find_index(list, &(&1 == 2))
or
list = [1, 2, 3]
Enum.find_index(list, fn(x) -> x == 2 end)
[1] http://elixir-lang.org/crash-course.html#partials-in-elixir
There are no examples for https://github.com/christopheradams/elixir_style_guide#comment-annotations
We should have some to make everything crystal clear.
Using the same "name fragment" (is there an established name for these?) multiple times in a module name causes some confusion. In particular in combination with alias. Advice against this.
defmodule Todo.Todo do
alias Todo.Todo
# Is confusing if you e.g. try to do alias Todo.SomeOtherModule here
end
For more background see: https://elixirforum.com/t/using-aliases-for-fubar-fubar-named-module/1723
The code Enum.map( ["one", "two", "three"], fn ( num ) -> IO.puts num end
needs an end ) to work, should be:
Enum.map( ["one", "two", "three"], fn ( num ) -> IO.puts num end )
The example in Syntax:
def some_method(arg1, arg2)
#body omitted
end
def some_method
end
is not in agreement with: ....but run different clauses that match for the same function together , from the previous §; the blank line between them should be removed.
Cheers,
Ivo
Hi,
I am quite new to Elixir, so excuse me if I missed something.
Enum.map( [1, 2, 3], fn ( num ) -> IO.puts num end
1) this code doesn't seem to work in iex
when adding a ) at the end:
(FunctionClauseError) no function clause matching in IO.puts/2
2) the spaces in fn ( num ) do they not contradict with the rule:
Never put a space between a method name and the opening parenthesis.
Cheers,
Ivo
Where should we put @callback
s in module attribute ordering?
What is the preferred way of placing brackets for the lists which span multiple lines:
1.
list = [
:first_item,
:second_item,
]
list =
[
:first_item,
:second_item,
]
list =
[:first_item,
:second_item]
Strictly speaking, Elixir does not have methods, we have functions. The guide should likely replace "method" by "function" throughout.
I've recently released an another Elixir style guide.
It will continue to grow intensively.
I hope that you can borrow many points from it, which don't present here.
\cc @eksperimental
I'm just working on a project where I have several modules that implement supervisors, several modules that implement registries for other modules and several modules that implement queues.
Basically I can name the directories queues
, registries
and supervisors
or queue
, registry
and supervisor
(the choice is between plural and singular).
I've went to check other elixir projects to see what convention they used( like Phoenix and Elixir) and I've noticed that most directory names are singular. But after reading the names of the modules in these directories I feel that in those cases it makes sense to use the singular form because the modules inside that directory are components of the thing
that the directory name refers to( for example in the Elixir Kernel it makes perfect sense to use singular for the kernel
directory because all the modules inside are components of it).
In my specific case I would have in the directory for queues modules named requests_queue.ex
and responses_queue.ex
, both different are two different types of queues
, and not components of a queue
functionality, therefore I think it would make sense to use the plural form queues
for naming the directory( in this specific case). The downside might be that some people might consider it confusing to have both singular and plural used to name directories.
What do you think?
Maybe
do_something
Instead of
do_something
This could very quickly lead to unreadable code. A function with many clauses that run together will be even less readable than a long if then else
block in other languages.
This is something I've been debating in my code. In OOP you have objects that combine state and behavior, so methods on those objects can be named like user.full_name
or struct.byte_size
, etc. In functional your data has no behavior, so it's always operated upon: User.full_name(my_user)
, Struct.byte_size(my_struct)
. However, this reads weird. In this configuration functions should say something like User.get_full_name(my_user)
, or Struct.calc_byte_size(my_struct)
. In various code examples I see that the verb tends to be omitted, which also makes sense, because if it wasn't, every function would be prepended with things like get_
, and calc_
, which creates noise. So should we consider the verb implicit and just omit it? Or maybe have a convention where we omit it only in cases where it would be something very generic like get_
or calc_
?
I think it would help to have a common place to put protocol definitions and also implementations. It would be in particular interesting if protocols are implemented for existing modules.
For discussion:
definition:
file: lib/protocols/incredible.ex
implementation for a new modules within the module.
implementation for an existing module (e.g. Integer) in:
file: lib/protocols/impl/integer.ex
or
file: lib/protocols/integer_impl.ex
?
I read the Elixir code and found that the following two styles are used at the same time:
assert expected == actual
assert actual == expected
I'd like to unify for consistency, but what do you think?
Probably better to use "Preferred"/"Not Preferred" or something similar.
Example: USPS IDE -->
Hi,
It would be nice with it's possible translate this guide. I'm member from phoenixframework-Brazil. We are translating the phoenix guide and we can help translate this style guide for portuguese.
Is there a good linter for implementing the details in this style guide (ideally one with a preset of some kind for the styles defined here)?
this is what we have now:
NOTE: From here on out, you get a PR merged, you get added as a
collaborator. People who have PRs merged have been added as collaborators.
I think we need some rewording here.
it's a bit too hard the imperative mode.
I will go with something more mellow as
NOTE: When you submit a PR and it gets merged, you are automatically added as a collaborator If you would like to be removed, please let us know.
I don't know what is the way of communicating, but there should be one.
As discussed in #113, there is no guidance regarding when keywords should be wrapped in square brackets and when they shouldn't be.
With regards to defstruct
, it seems that the same source material referred to in #113 establishes a precedent that keywords used in defstruct
declarations should not be wrapped in square brackets. The referenced sources:
I'm pretty new to Elixir and I'm building my first open source package. Obviously I'm aiming for good test coverage, but I'm not sure where to draw the line between using doctests in my modules, and using normal tests in test scripts.
Is there a convention for this? Can/should this be added to the style guide?
"# Multiline pipelines use a single level of indentation." but the pipe is not indented further than the previous line. Would "Multiline pipelines do not change indentation" or "Multiline pipelines do not indent further" be clearer, perhaps?
# Multiline pipelines do not change indentation
foo
|> do_something
|> do_something_else
#81 has introduced the PascalCase terminology replacing CamelCase as we know it in Elixir.
Please read the discussion there.
I think the PascalCase definition is vague, and the only strong definition of it is adopted mostly by Microsoft, and more over, use of CamelCase terminology in Elixir language is clear, and PascalCase is non existent.
And including it in the style-code is a source of confusion.
IMO 6cbee59 should be reverted until Elixir language itself adopts such terminology --if that ever happens--
I have not used it myself yet, but I know many (big) projects are using it, and it seems a great idea.
http://editorconfig.org/
a .editorconfig
file that can set stuff like
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
#4 space indentation
[*.ex, *.exs, .travis.yml, *.md]
indent_style = space
indent_size = 2
and many more such as charset
, trim_trailing_whitespace
, insert_final_newline
and it is supported by default by the github code editor and viewer, so that's a bonus when people want to contribute also for this guide.
I'm wondering if anybody out there is using it for any elixir project.
So my proposal are:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.