Hacker News new | ask | show | jobs
by klibertp 3372 days ago
Others provided an explanation of the Ecto DSL, I just wanted to add the explanation of basic syntax. It goes like this.

In Elixir, the most basic function application looks fairly standard:

    func_name(arg1, arg2, ...)
But the parens are optional, so you can write:

    func_name arg1, arg2, ...
as well.

Next, in Erlang and Elixir function arity (number of arguments it takes) is always fixed (i.e. no varargs or Python's *args). Because of this you generally have to pack your arguments in a list; functions like `printf` work that way:

    iex(2)> :io.format("fmt ~p foo: ~p bar: ~p", [1, 3, 4])
    fmt 1 foo: 3 bar: 4
That takes care of (positional) varargs. There are some other functions, however, which would benefit from "keyword arguments", which also isn't directly supported. To get around this, you can take a list of pairs (keyword, value) as one of your arguments (usually last):

     some_func(arg1, [{:keyword1, value}, {:keyword2, value}])
Where `{}` creates a tuple and `:` creates an atom (called symbols in Lisp), which you can think of as a special[1] string value. This pattern is so common, that Elixir provides a syntactic sugar for it. The above is equivalent to:

     some_func(arg1, [keyword1: value, keyword2: value])
The brackets around keyword list are also optional, but only inside function call. The most sugar-y way to write this looks like this:

     some_func arg1, keyword1: value, keyword2: value
The last thing of note is that the `do ... end` is just a syntactic sugar for `[do: ...]`, where `...` is treated as a block of code.

Normally, the block of code would be evaluated and only last value would be passed to the function:

     some_fun arg1, kwarg1: 1, kwarg2: 3 do 1; 2; 3 end   # notice no comma before `do`
would be equivalent to (after all the sugar being resolved):

     some_fun(arg1, [{:kwarg1, 1}, {:kwargs2, 2}], [{:do, 3}])
However, when writing a macro, the macro gets the unevaluated block, which then can be modified or executed. See http://elixir-lang.org/getting-started/meta/macros.html for more info on that.

Edited to add: Capitalized names in Elixir are actually special atoms, mostly used for naming modules. It works like this:

    iex(5)> :'Elixir.Change' == Change
    true
There is more going on because of the fact you can alias module names, but mostly you can think about this as (another) special syntax for atoms.

[1] Allocated once and cached. When working with normal strings:

    a = "Asd"
    b = "Asd"
you have no guarantee that `a` and `b` point to the same thing in memory, while with atoms you do have that guarantee. This makes comparing them efficient.
1 comments

> But the parens are optional

In the newest Elixir I get a warning about a variable not existing when I omit the parenthesis, and it suggests to add them.

This is usually the case when there is potential for ambiguity, but there's also a matching function the non-parens version can be expanded to.