"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.)
Smalltalk faq: "Q28. What is the difference between chaining and cascading?"
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)
> 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/
"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.
More or less it rewrites
String.downcase("FOO\0BAR") |> String.split("\0")
to String.split(String.downcase("FOO\0BAR"), "\0")
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.
c. Try the pipe operator. Your code will closely follow the transformations of your data.Instead of this:
Or this: Try this: The result of each command will be passed as the first argument to the subsequent command.d. You get seamless interoperability with Erlang libraries.
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. 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: