
Elixir Streams - pgr0ss
http://blog.drewolson.org/elixir-streams/
======
phamilton
When people say Elixir is just syntactic sugar on top of erlang I point them
to Stream and Enum. It's a great example of how polymorphism via protocols is
an enabler for powerful designs.

~~~
MCRed
Elixir is so much more than syntactic sugar... but you can't deny that it's
also very, very sweet.

I think it's the best language out there-- the power of erlang and OTP and the
fun of, well, elixir. It's more fun than Ruby and Python.

~~~
rozap
That's the best way to describe it. The concurrency model and metaprogramming
bits mean that effortless to make cool stuff with it. And it turns out that's
way more fun that wrestling with the jvm or other high friction tools.

There's a lot of neat stuff in Elixir, and the community is great too. I
honestly it may be the first functional language that becomes widely used.
Hopefully.

------
doomrobo
Interesting to see this as a novel thing in another ecosystem. Rust actually
uses "stream" manipulation as a default way of dealing with things that might
otherwise be expressed as full data structures. For example, the equivalent to
one of the code snippets in the article would be:

BufReader::new(File::open("myfile.txt").unwrap())

.lines()

.enumerate()

.map(|(i, line)| format!("{}: {}", i, line.unwrap()))

.take(1)

.next().unwrap()

(formatted for non-monospace font readability). Note the .unwrap() is where
error handling should normally happen.

~~~
meowface
The problem with "stream/generator as default" is the boilerplate you
constantly have to add.

In Python 3, for example, map() returns a generator. So you can no longer
transform a list into another list with `new = map(func, lst)`. You have to do
`new = list(map(func, lst))`. One of the most subtle gotchas when upgrading
from 2 to 3 is having to wrap list() around functions and methods like map(),
range(), dict.items(), etc.

Discussion I've seen about Rust on less moderated websites often seems to make
fun of the .unwrap() spam seen in a lot of programs, to the point of the
mockery even dominating some discussions.

Streams and lazy evaluation are really nice, but sometimes you just want some
nice procedural handling.

~~~
icebraining
All the boilerplate you need to add is

    
    
      lmap = lambda f, l: list(map(f, l))
    

somewhere in your project, then use new = lmap(func, lst)

~~~
Willyfrog
One has to wonder why this is not included in the functools or some other
module.

~~~
icebraining
Dunno, to promote generators? I'd say people often convert to list for no good
reason, so adding friction might discourage that.

Then again, map() and friends are not exactly the recommended way, list
comprehensions and generator expressions are usually preferred by the BDFL.

------
_nato_
I wonder what the Erlang equivalent would look like (passing around data that
are funs)?

~~~
davidw
I'm mostly an Erlang guy, but I do like that about Elixir: they really seem to
be taking the Erlang base, and building on it in some interesting ways.

~~~
mjs2600
That's the macros. Phoenix's routing is an awesome example of the power of
Elixir macros. It leverages the BEAMs pattern matching capabilities to do the
routing, but the syntax is very clear and concise.

~~~
Skinney
Minor nitpick. BEAM doesn't have pattern matching built-in. Core Erlang does.
Core Erlang compiles to BEAM bytecode with functions using regular if-
statements. So basically: Erlang/Elixir -> Core Erlang -> BEAM. (Actually, I
think there is one more step there).

~~~
asonge
Minor nitpick to the nitpick, since I dug down in Elixir's compiler before.
Elixir spits out a normal Erlang AST, not a Core Erlang AST, which is a bit
different. There are a half dozen levels between the Erlang AST and BEAM as
well. There's several instances of a talk by Robert Virding about implementing
languages on the BEAM where he talks about which advantages different levels
of the compiler to hook into.

