torimus

torimus

Hello.

I’m relatively new to Elixir, but not to programming generally.

In the learning process I’ve been recently struck with following inconsistency, at “capturing” an anonymous function with & operator:

iex> &(:just_return_this_atom)
** (CompileError) iex:350: invalid args for &, expected an expression in the format of &Mod.fun/arity, &local/arity or a capture containing at least one argument as &1, got: :just_return_this_atom

I’ve read the docs, where the limitation is stated:

The only restrictions when creating anonymous functions is that at least one placeholder must be present, i.e. it must contain at least &1 , and that block expressions are not supported:

What is the rationale behind this limitation ? I’ve already searched some mailing lists but so far no satisfactory explanation has been found.

I’m aware by choosing unary ampersand operator for converting both - normal expression and function name with arity - to Function instance, already did introduced ambiguity itself. In addition, by choosing slash operator both - for arithmetic division and separator between function name and its arity, only made it worse.

As far as I know, function_name/arity_num is not even valid token itself and does exist only for the sole purpose of capturing with &. Just in this single special case.

Are there some plans, work in core dev to fix above described inconsistency in some major release, like 2.0 ? Or find it as unsolvable problem without breaking backward compatibility and accepting damage has been already done ?

I’d probably need dive deeper into Elixir’s parser, but so far I’d imagine it could be handled with fixing operators precedence incl. parens and capturing function_name/arity_num would always require explicit enclosing in parens.

Showing Posts 1 to 6

rodrigues

rodrigues

Hi @torimus, welcome to the forum!

I don’t know why it’s like this, if there’s any technical reason, but I suspect it’s intentional, a language design choice.

For some time I also liked the idea of the capture operator working without &1, but now I see it potentially bringing confusion, this ends up helping to bring clarity and consistency to elixir code IMO.

Some meta examples where I see it becoming cryptic or misleading:

# this "lispy wrapping" could become very confusing, specially for beginners
[&(42), &(nil), &([]), &(:foo), &(@foo), &(foo), ...]

# & easily unnoticeable
[&%{foo: :bar}, &"wut", &[1, 2, 3]]

&fun(1) # easy to mistake with fun(1) or &fun(&1)
&Mod.fun() # easy to confuse with Mod.fun(), &Mod.fun/0 wins IMO
&Mod.fun(a, b) # easy to confuse with Mod.fun(a, b)
hauleth

hauleth

name/num is perfectly valid and token and can be used for division. Which mean that in situation like:

f = &(a/2)

The compilation need to “deduce” whether a is a function or not.

Another reason can be the fact that &foo(1) and &foo(&1) can be easily confused one with another and could lead to strange bugs.

torimus

torimus OP

name/num is perfectly valid and token and can be used for division. Which mean that in situation like:

Yeah, I’ve meant standalone expression in function_name/arity meaning. I was not too clear, my bad.

f = &(a/2)
The compilation need to “deduce” whether a is a function or not.

Another reason can be the fact that &foo(1) and &foo(&1) can be easily confused one with another and could lead to strange bugs.

Right. Abuse of function argument reference &n for “deduction” purposes seems the true reason. Forcing existence of at least one reference signalizes function body else expression is considered as function/arity specification.

defmodule MyMod do
  def zero_arity_fn(), do: 42
end

# myfn = fn -> zero_arity_fn() / 2 end
# anon. function capture attempts:
myfn = &zero_arity_fn/2    # BadArityError
myfn = &(zero_arity_fn() / 2)    # BadArityError
myfn = &((zero_arity_fn()) / 2)    # BadArityError
# can't mix function specifier with body 
myfn = &((&zero_arity_fn/0) / 2)    # CompileError - nested captures not allowed

# Forced explicit declaration of argument reference allows parser cheat ...
myfn = &zero_arity_fn/&1    # "deduction"

#IO.inspect myfn.()
IO.inspect myfn.(2)    # 21.0

I don’t know guts of Elixir parser, not sure what solution would be possible while not introducing another inconsistency at the same time.

&<expression> or &(expression) - capture anonymous function body by default
(&expression/expression) - edge case of capturing function_name/arity
or
&:function_name/arity: - atom-like specifier to capture existing function, inspired a bit by Ruby’s Symbol#to_proc

peerreynders

peerreynders

https://groups.google.com/d/msg/elixir-lang-core/3HVYGqimS9o/8x9L6PNeHewJ


https://github.com/pragdave/elixir-fx

torimus

torimus OP

Thanks for the link to related discussion.
I can live with that, but it only leaves a bitter taste.

  • named functions can have zero or more arguments
  • anonymous functions can also have zero or more arguments
  • operator & does convert(capture) named function to anonymous Function instance, that function still can have zero arguments
  • operator & does also convert(capture) single expression to anonymous Function instance, that function now illogically can not have zero arguments
  • by mixing apples with oranges, & operator obviously introduced exception to the rule, but hey having cool-looking syntax is worth the hassle. Or not ? You won’t need zero-arity that much anyway. Or would ? Use full syntax for anon. functions then. But there is & macro … :zipper_mouth_face:
hauleth

hauleth

& operator when used as a sugar for generating lambda has more limitations, for example this is illegal:

fun = &(&2)

As you need to use all arguments within such lambda body. So no, there is no exception to the rule as &function/arity is something completely different from & &1 lambda as these will behave differently. First one will cause call to function/arity while second will expand to fn a -> a end which will expand even further to generate function with generated name, for example :'-lambda-line-1-arity-1'/0 which will be internally used by the compiler. So yes, there is huge difference between these two.

— All posts loaded —

Where Next? Top

Trending in Discussions Top

cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

Other Trending Topics Top

Potions
A new screencast on live LiveView updates with PubSub, the Oban Web dashboard, and smarter retries. Part 2 of 2. Screencast + full walkth...
New
GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews