Hacker News new | ask | show | jobs
by dv_says 3918 days ago
I'm really glad to have recently picked up Elixir. For anyone just starting, a few tips from someone similarly new:

a. After launching the "iex" shell, press Tab. You'll get the list of all built-in commands.

b. The help feature is also very handy for when you're wondering what an operator does. Type "h <command>" for a definition.

    h !/1
c. Try the pipe operator. Your code will closely follow the transformations of your data.

Instead of this:

    m1 = "moo"
    m2 = String.replace(m1, "m", "z")
    m3 = String.upcase(m2)
Or this:

    String.upcase(String.replace("moo", "m", "z"))
Try this:

    "moo" |> String.replace("m", "z") |> String.upcase()
The result of each command will be passed as the first argument to the subsequent command.

d. You get seamless interoperability with Erlang libraries.

    :crypto.hash(:md5, "bob") |> Base.encode64
e. Try the Observer tool in iex to visualize various aspects of your running application, including the supervision tree, details on each running OTP process, and much more. Seriously very handy stuff.

    :observer.start()
f. If you're using EC2 like I am, Amazon images have a too-old version of Erlang, but it's trivial to compile things yourself:

   sudo yum install gcc glibc-devel make ncurses-devel openssl-devel autoconf
   wget https://www2.erlang.org/download/otp_src_18.0.tar.gz
   tar xvzf otp_src_18.0.tar.gz
   cd otp_src_18.0
   ./configure && make && sudo make install
   sudo ln -s /usr/local/bin/escript /usr/bin/escript
   sudo ln -s /usr/local/bin/erl /usr/bin/erl
1 comments

I want to rave a little bit about this:

    "moo" |> String.replace("m", "z") |> String.upcase()
This is always what I thought OOP should be, but could never put my finger on. Effectively, you're calling a chain of "methods" of "objects", but each method lives in its own namespaced module, rather than automatically being assumed to live in the class associated with the data. No "this object implements two interfaces that both define add()" confusion; no objects extended to infinity with extra mix-ins and interfaces just so that more methods could be called on the object rather than having the object passed to utility functions; etc.

And when you do use classes (Structs), there's line-local context-free crystal-clarity between code that expects a generic object expressing one of the class's interfaces (where calls are made on the interface's Protocol module) vs. code that expects that particular class (where calls are made on the class's module, which contains the implementations of the Protocol functions.)

See also:

Smalltalk faq: "Q28. What is the difference between chaining and cascading?"

http://www.ipass.net/vmalik/smalltalk.html#Q28

So, pretty much whether everything is being applied right to left vs being applied left to right?

Personally I like chaining because, since I read going right to left, in my head I can go "x goes to y then the result of y goes to z" versus "z is the result of y which is the result of x" (reading it backwards)

I wasn't clear, but I meant that mostly as a comment to:

> This is always what I thought OOP should be, but could never put my finger on.

I'm not sure what Simula did, but at least in Smalltalk this is how OOP have worked :-)

> So, pretty much whether everything is being applied right to left vs being applied left to right?

I'm not sure that's the best takeaway; consider:

    $ gst
    GNU Smalltalk ready

    st> 2 * 3; * 3; * 3
    6
    st> 2 * 3 * 3 * 3
    54
Now, if the object on the far left was some kind of accumulator/container, the effect of sending something like three "add the number 3" would be similar to chaining. But even if you mulitply the number 2 by 3, three separate time, 2 * 3 still equals 6.

In fact, in order to get chaining with keyword messages, you apparently need to define it, or especially adapt eg: containers to return ^self. But as should be obvious, I'm not very familiar with Smalltalk. Some more on the subject: http://blog.3plus4.org/2007/08/30/message-chains/

You can do this in other languages just the same with maybe some different syntax, for example C#

"moo".Replace('m', 'z').ToUpper();

Or, fully qualified with "every method in its own namespaced module";

"moo".(string.Replace('m', 'z')).(string.ToUpper());

I'm not sure if elixir is doing anything fancy here that I'm not seeing, though. I still haven't had a chance to try it out.

It's a macro. It takes the result of the prior operation and inserts it as the first parameter of the next operation.

More or less it rewrites

    String.downcase("FOO\0BAR") |> String.split("\0")
to

    String.split(String.downcase("FOO\0BAR"), "\0")