> Mainly, you should use throw for control-flow and reserve raise for errors,
> which happens on developer mistakes or under exceptional circumstances.
> In Elixir, this distinction is rather theoretical, but they matter in some
> languages like Ruby, where using errors/exceptions for control-flow is
> expensive because creating the exception object and backtrace is expensive.
This makes sense and I think it's a good choice to reserve exceptions
exceptional cases. In Objective-C land, for instance, exceptions are
only used for programmer's errors.
The point to make here is that at some point in the future we'll need
example in a working app or a short write-up on this convention
Elixir, since it's not mentioned at all in the guide.
> This question in Elixir is just a matter of syntax. If we allowed `var()`
> to call a function, `some_code()` could either mean that we are invoking a
> function in the variable some_code or invoking a named function some_code.
> In order to remove the ambiguity, Elixir reserves `some_code()` to call
> only named functions and requires `var.()` to invoke functions.
> Also, regarding Higher Oder Functions, Elixir allows functions to be passed
> and returned from functions, but retrieving a named function from a module
> cannot be implemented trivially because functions in Erlang/Elixir are
> defined by their name and arity. Erlang for example has a special syntax
> like `fun map/2`, but I haven't added it to Elixir yet. Fortunately, we can
> achieve the same (and more) with partial application.
I think I've figured it out finally. My biggest misconception was that
think of defining functions with different arities as defining
functions, even if the same name was used in both definitions. This
is, in fact,
the case in Erlang and Elixir: functions with different arities are
independent of each other, so my_fun/1 and my_fun/3 are different
that just happen to have the same name. That's exactly what you have
telling me, it was just my thickness that got in the way :)
I'm ok with the default that functions are invoked regardless of
parentheses are used. You've summed it up nicely in your gist --
https://gist.github.com/b0df374ef6483fafc380. Basically, as I
understand it, fn
returns a partially applied function, that is:
my_size = fn(x) -> size x end
is conceptually exactly the same as
my_size = size &1
This makes it possible to pass functions as arguments and return
content with this mechanism.
But I think using the postfix dot to invoke a partially applied
in other words, a function assigned to a variable) is not the best
idea. It is
like something from another world, something that hasn't been used in
language. This syntax is going to be used in all functions that accept
functions as arguments. The dot can be included by mistake, it can
omitted by mistake. It has to be more prominent than that.
Every language I know of uses prefix notation for an operator when its
meaning is "dereferencing" or "extraction of value". For instance,
&x -- take an address of x in C
*x -- dereference a pointer in C
::x -- use the global x, instead of the shadowing local x in C++
*list -- splice a list in Python
**dict -- splice a dict in Python
#'x -- get a var object x rather than the value of x in Clojure
And so on. I'm sure you see my point. The dot is too strongly
property access, in my opinion.
We have a ^ syntax used in pattern matching: ^x means match against
of x instead of binding x to the value. It can only be used inside an
assignment, so why not extend its usage outside of assignment to mean
function call of the function stored in x?
Alternatively, we could pick something that intuitively means "apply".
what dot is doing is it applies the function to the list of arguments:
apply my_size, ["123"]
This explanation can be included in the guide, and I believe it is
intuitive. We just need to pick an appropriate character for the task.
be @x, $x, or `x, whichever you like the most. I'm just proposing that
it is not
the dot and that it is used as a prefix.