syntax sugar for fn() ?

154 views
Skip to first unread message

mra...@gmail.com

unread,
Dec 12, 2013, 5:01:29 PM12/12/13
to elixir-l...@googlegroups.com
I was just wondering.... currently anonymous declaration requires an "end", which for a small funs take's too much space and keystrokes and is ugly, so would it make sense if you can use instead of
"end", a space separated dot " ." i.e.

fn x -> x + x end

is OK, but is also allowed :

fn x -> x + x .

From my knowledge there is no case where you use standalone dot for anything.
The case where you can have :

fn x -> x + x.

can be error OR allowed !! not sure..
The most common case is where you have closing brackets, which can be OK, I think :

Enum.map(list, fn x -> x + x .)

just wondering... it seems cleaner to me, but not sure if it is hard to implement and/or can be prohibitive because it can cause more errors than benefits !!

PS> I know exception to the rule is bad, but there is already one ;)

func,(a,b)

may be it can become :

func a,b .
OR
func(a,b).


Vincent Siliakus

unread,
Dec 12, 2013, 5:15:26 PM12/12/13
to elixir-l...@googlegroups.com
For small anonymous functions, like fn x -> x + x end, one can already use the capture operator: &(&1 + &1). Besides this, I'm not sure if it would be an good idea to replace a clear 'end of block' keyword with a single character that can be easily missed, in order to save two keys strokes.

-vincent

Op donderdag 12 december 2013 23:01:29 UTC+1 schreef mra...@gmail.com:

Bruce Tate

unread,
Dec 12, 2013, 5:28:17 PM12/12/13
to elixir-l...@googlegroups.com
I disagree. I think the use of "end" for full anonymous functions has always looked out of place, and a shortcut for end-of-statement would be most welcome. An alternative syntax could be to specify parens around the anonymous function where there is any ambiguity. Like this:

fn x -> (x + x)

so that this would be legal too:

fn x -> Kernel.+(x + 1)

and so would this:

fn x -> {:ok, x}

The problem with 'end' is in-line readability. 

-bt




--
You received this message because you are subscribed to the Google Groups "elixir-lang-core" group.
To unsubscribe from this group and stop receiving emails from it, send an email to elixir-lang-co...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.



--

Bruce Tate  |  CTO  |  512.772.4312

icanmakeitbetter.com

Innovation + Research. Made Simple 

powered by Sentient Services

Dave Thomas

unread,
Dec 12, 2013, 6:01:25 PM12/12/13
to elixir-l...@googlegroups.com

Remember that fn can be multi-headed:

iex> Enum.map 1..5, fn x when x>3 -> "big"; _ -> "small" end
["small", "small", "small", "big", "big"]

Bruce Tate

unread,
Dec 12, 2013, 6:33:36 PM12/12/13
to elixir-l...@googlegroups.com
ok... so you need a terminator. 

fn x when x>3 -> "big"; _ -> "small" .

Does space dot work?

-bt

mra...@gmail.com

unread,
Dec 12, 2013, 9:28:05 PM12/12/13
to elixir-l...@googlegroups.com, br...@icanmakeitbetter.com
I agree the approaches you mentioined i.e. (...) and { ... } seems more inline with the general rules..  "space-dot" is more beautiful, but more prone to errors .

José Valim

unread,
Dec 13, 2013, 4:07:57 AM12/13/13
to elixir-l...@googlegroups.com, Bruce Tate
There is one syntax we could support and that is already valid today. You use (x -> y) in typespecs to define functions:

    Enum.reduce list, 0, (x, y -> x + y)

Just as a note, historically, "fn ... -> ... end" was added as a shortcut to "function do ... end":

    function do
      x -> x + 1
    end

Became:

    fn
      x -> x + 1
    end

I.e. "fn" became a keyword that represents "function do". We no longer have "function do", but remember that:

    case x do
      y -> z
    end

Translates to:

    case x, do: (y -> z)

Bruce Tate

unread,
Dec 13, 2013, 4:13:12 AM12/13/13
to José Valim, elixir-l...@googlegroups.com, Bruce Tate


    Enum.reduce list, 0, (x, y -> x + y)

I like this it is much nicer for inlines. 

-bt

On Friday, December 13, 2013, José Valim wrote:
There is one syntax we could support and that is already valid today. You use (x -> y) in typespecs to define functions:

    Enum.reduce list, 0, (x, y -> x + y)

Just as a note, historically, "fn ... -> ... end" was added as a shortcut to "function do ... end":

    function do
      x -> x + 1
    end

Became:

    fn
      x -> x + 1
    end

I.e. "fn" became a keyword that represents "function do". We no longer have "function do", but remember that:

    case x do
      y -> z
    end

Translates to:

    case x, do: (y -> z)

Vincent Siliakus

unread,
Dec 13, 2013, 6:02:37 AM12/13/13
to elixir-l...@googlegroups.com
I agree it looks pretty and think it's pretty easy to read, but could this syntax also support zero arity and multi clause anonymous functions? If yes, and everybody agrees that this syntax should be allowed, I would propose to deprecate the fn syntax, although I realize that would require a massive refactoring of code.

The reason for this is that I think if we keep adding syntax to Elixir that optimizes for certain situations, it can significantly increase the cognitive load needed to read Elixir code, making the language ultimately more difficult to read. For example, if this anonymous function syntax would be allowed, someone reading some Elixir code already needs to memorize 3 different syntaxes for anonymous functions. At a certain point, one needs to memorize so many syntax variations that there isn't much room left for understanding what the code actually does :)

I know from experience that it can be very tempting to think while writing some code: "If only I could use this or that syntax in this situation, it would make my code look so more beautiful!", without really thinking about if it would make that code actually more easy to read when looking back at that code after a few months.

I understand this is partly subjective matter, but for me Elixir is already near the sweet spot of allowing one to express various idioms in an elegant, concise way, without having too much syntax constructs to learn and memorize and it would make me sad to see Elixir crossing this border for me.

To be clear, I actually don't think that adding new syntax for anonymous functions would make Elixir suddenly difficult to read, but it will be if we keep adding little things here and there that optimize for certain situations and José and the other core devs: please don't take the above as a critic to the fantastic work your doing, I guess I just had to take this off my chest :)

Best,
Vincent

Op vrijdag 13 december 2013 10:07:57 UTC+1 schreef José Valim:

José Valim

unread,
Dec 13, 2013, 6:17:03 AM12/13/13
to elixir-l...@googlegroups.com
Vincent,

I agree 100% with everything you said. Having too many syntaxes for declaring functions was exactly one of the concerns raised when we added the current capture syntax (&...).

I also want to point out that I am going to frequently bounce ideas through this mailing list and they do not mean, by any chance, that they will be added to the language. The point is to simply get feedback or start a discussion about a particular topic.

Now, answering your questions, the syntax above does support 0 arity functions:

spawn_link (->IO.puts "Hello")

What I dislike about it though is it interacts with optional parentheses in the language:

# This works
spawn_link (-> IO.puts "HELLO")
spawn_link((-> IO.puts "HELLO"))

# Invalid syntax
spawn_link(-> IO.puts "HELLO", :some_arg)
spawn_link(:some_arg, -> IO.puts "HELLO")

# Invalid (because it is ambiguous) but could be made to work
spawn_link(-> IO.puts "HELLO")

In any case, there are already plans for supporting 0 arity with the capture syntax, so I definitely don't think that it should be our main drive.

José Valim
Skype: jv.ptec
Founder and Lead Developer


Tom Janssens

unread,
Dec 13, 2013, 6:27:05 AM12/13/13
to elixir-l...@googlegroups.com, José Valim, Bruce Tate
+1 
And I prefer this over Enum.reduce list &(&1+&2)

Op vrijdag 13 december 2013 10:13:12 UTC+1 schreef Bruce Tate:

Vincent Siliakus

unread,
Dec 13, 2013, 7:06:20 AM12/13/13
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
Happy to hear you agree.

Op vrijdag 13 december 2013 12:17:03 UTC+1 schreef José Valim:

Now, answering your questions, the syntax above does support 0 arity functions:

spawn_link (->IO.puts "Hello")

What I dislike about it though is it interacts with optional parentheses in the language:

# This works
spawn_link (-> IO.puts "HELLO")
spawn_link((-> IO.puts "HELLO"))

Nice


# Invalid syntax
spawn_link(-> IO.puts "HELLO", :some_arg)
spawn_link(:some_arg, -> IO.puts "HELLO")

Not sure if that would be a problem, as parenthesis for this type of anonymous functions would be mandatory anyway. Although I can foresee myself accidentally writing:

spawn_link (-> IO.puts "HELLO", :some_optional_arg)

when I decide to later add an optional optional argument to a function call, ie:


spawn_link (-> IO.puts "HELLO")

to

spawn_link (-> IO.puts "HELLO"), :some_optional_arg

At the other hand, I guess this will be a compile time error, so it won't lead to unexpected behaviour.
 
# Invalid (because it is ambiguous) but could be made to work
spawn_link(-> IO.puts "HELLO")

I'd say keep this invalid, to keep it clear that f(..) is always a call with parentheses and f (...) is a call without parentheses, but happens to have an argument that uses some form of parentheses.
 
I also want to point out that I am going to frequently bounce ideas through this mailing list and they do not mean, by any chance, that they will be added to the language. The point is to simply get feedback or start a discussion about a particular topic.

That being said, is there already consensus about the anonymous functions calling syntax (keeping the f.(x) syntax, or changing to f(x), etc.)?

José Valim

unread,
Dec 13, 2013, 7:17:58 AM12/13/13
to elixir-l...@googlegroups.com
That being said, is there already consensus about the anonymous functions calling syntax (keeping the f.(x) syntax, or changing to f(x), etc.)?

There was a final discussion where I posted to the mailing list about Lisp 1 and Lisp 2 semantics and why we need to have required parentheses for 0-arity calls if we want to remove the dot. Given the restriction, there was no consensus that the dot should be removed.

Vincent Siliakus

unread,
Dec 13, 2013, 7:35:20 AM12/13/13
to elixir-l...@googlegroups.com, jose....@plataformatec.com.br
Ah, good to hear. Although I followed that discussion, I didn't realize that was the outcome ;)

mra...@gmail.com

unread,
Dec 13, 2013, 10:53:10 AM12/13/13
to elixir-l...@googlegroups.com, Bruce Tate, jose....@plataformatec.com.br
Make sense and looks natural..
Reply all
Reply to author
Forward
0 new messages