elixir-lang / elixir

Elixir is a dynamic, functional language for building scalable and maintainable applications
https://elixir-lang.org/
Apache License 2.0
24k stars 3.33k forks source link

LC syntax is incorrect #335

Closed yrashk closed 12 years ago

yrashk commented 12 years ago

I think usage of 'when' in list comprehensions is plain wrong. The problem here is that when is supposed to work with a very limited set of "guard expressions", while in Erlang, list comprehensions' conditions are any boolean expressions.

In Erlang, what you have is a comma-delimited list of (|). So I think this should be solved similarly.

Now, come to think of it, use of in in LCs is wrong too. Other use of 'in' implies a boolean test of A in B, and this is not that, this is a generator. So, it would be natural to use some "generator" operator to signify generators.

The tricky part comes from the fact that Elixir uses <- instead of '!' for message sending which effectively renders us unable to use it for generators. I see two solutions too this: 1) pick another operator that is as expressive 2) replace <- with ! for message sending.

Thoughts?

josevalim commented 12 years ago

There are a few things that is worthy considering here. Elixir is a homoiconic language and allow people to come up with their own control flow structures. While we could control what when means inside Elixir, we cannot ensure its semantics on the outside world (nor we would like to, this is the point of being homoiconic + having macros).

Take case in Clojure, how do you know what each argument is suppose to mean and the format they must be passed? You consult the docs.

That said, I am perfectly fine with when in comprehensions being a superset of guards and I foresee this happening in many other situations. The way to look at this is as lc and bc are macros that manipulates the incoming syntax tree to its own semantics, they are not keywords.

Regarding message sending, we already use ! to mean negation since Elixir introduces nil and Erlang's only negation operator (not) is strictly boolean.

yrashk commented 12 years ago

I will go nuclear on this. As much as I understand that it is hard to make decision to change syntax, but in this case it is not about Elixir being homoiconic, but inconsistent. Big time inconsistent.

Seriously, it is a very bad defence. "We're making this inconsistent because it is possible for us to do so!". Not only we redefine what guarding is and making it confusing to outsiders, we also make it extremely confusing to Erlang developers as well. We also use guard syntax for generators in comprehensions and break the simplicity of comprehensions right at the door.

I am declaring war on this. I'll come up with examples of how this might look.

It is the best time to adjust the syntax. It will be too late to do that soon.

yrashk commented 12 years ago

First two ideas:

lc a from list, a > 1, do: lc a :: list, a > 1, do:

yrashk commented 12 years ago

As per IRC discussion the plan is:

  1. replace in with inlist and inbits
  2. drop when
yrashk commented 12 years ago

In support of this change:

2> Tables = [tab1, tab2, "tab3", tab4].
[tab1,tab2,"tab3",tab4]
3> put(tab1, [f1,f2]).                 
undefined
4> put(tab2, [f3,f4]).
undefined
5> put(tab4, [f5,f6]).
undefined
6> [ Field || Tab <- Tables, Field <- get(Tab), is_atom(Tab) ].
** exception error: bad generator undefined
7> [ Field || Tab <- Tables, is_atom(Tab), Field <- get(Tab) ].  
[f1,f2,f3,f4,f5,f6]
8> 

The order is important. I just encountered this issue while developing ExQL.