5 ms·
What you said is rarely stated in public, but I've often felt it too: OTP obscures the underlying beauty of the Erlang platform. OTP is well engineered of cour
by tlack 6y ago
What you said is rarely stated in public, but I've often felt it too: OTP obscures the underlying beauty of the Erlang platform.
OTP is well engineered of course, but the basic notion of the spawn -> receive -> loop cycle is so clean and illuminating that I wish newbies would hold out before learning OTP sometimes.
It's natural to think of case-specific abstractions around the primitives that are more germane to the domain at hand than OTP's.
- dnautics 6y agoYeah but that's like saying the awkwardness of stl templates obscures the beauty of C++ or the Android app api obscures the beauty of the jvm. The genserver is messy because it deals with a good chunk of messiness around safely managing distributed systems for you. It probably could be improved (Dave thomas critiques comes to mind) but elixir had to be conservative because if it weren't it wouldn't have had buy in from the beam community and wouldn't have become the first truly successful non-erlang language targeting the BEAM.
- probotect0r 6y agoI finished reading Elixir in Action a few days ago. This was probably the best part of that book. It takes you through building a primitive GenServer with basic processes before moving onto actually using GenServer. It specifically goes over tail recursion optimization before it introduces the receive do loop, which seems like a very important part of the whole thing.
- AlchemistCamp 6y agoElixir in Action is fantastic. Its approach is so different from the other introductory books, but the payoff is real.
- arusahni 6y agoWould you recommend the book?
- bostonvaulter2 6y agoNot the OP, but it is a great book, I'd highly recommend it.
- RobertKerans 6y agoAlso not the OP, but unequivocally yes (though for full disclosure, I am biased as was one of the technical reviewers for the second edition). It was hugely important to me personally learning the language; the approach is excellent and it's very well written. You take a simple to-do application and write a number of versions of it, each one progressively more complex and featureful, and each one using progressively higher language/OTP abstractions.
- jeremyjh 6y ago> spawn -> receive -> loop cycle is so clean and illuminating that I wish newbies would hold out before learning OTP sometimes Yes it is neat and its fun to play with but it isn't usually something you want to use in production code. In production code it is important to have processes linked correctly so that errors propagate to callers. GenServer.call handles this for you, and also clarifies intent (blocking call to another process that must respond or fail).
- dnautics 6y ago> the basic notion of the spawn -> receive -> loop cycle I'm working on a video series about these concurrency patterns; even recorded the first one but the audio is bad so I'm going to re-record it before I publish it when some "real" audio equipment comes in (hopefully this weekend) - let me know what you think: https://www.youtube.com/watch?v=eoEcpcLVumc https://www.youtube.com/watch?v=eoEcpcLVumc
- tlack 6y agoPretty good! I knew most of that stuff already so I can't speak to the pure education value, but it made sense, and I think you hit the key points. I bet some visuals would help it make sense for total nooberz. AND! I didn't know that about "v" - thanks! :)
- dnautics 6y agoanother protip: you can also call v(n) and it will give you the item at iex(n)>
- oaferlanger 6y agoOTOH every decent erlang book or tutorial I've ready, from Armstrong's book[1] to Learn You Some Erlang[2] to Erlang and OTP in Action[3] and others all start off by introducing primitives like spawn, message sending , and receive. They then introduce OTP and explain all the cases it handles. I've never read a book or tutorial on OTP that just starts with OTP. In fact (a bit tangetially) whenever I encounter abstractions where I don't already understand the primitives I have a very difficult time. Maybe that's just the way my brain is wired though. I have a terrible time with OO programming for that reason. I much prefer a separation of functions and data because it's much easier for me to reason about what is happening. Anyway, I agree that programmers should start with the primitives, but I've never seen anyone really teach OTP any other way. Edit: also there are tools such as Erlang.mk[4] by Loïc Hoguin[5] that will handle a lot of the boilerplate for OTP projects and building releases, though it's good to do it manually at least once while learning. [1] https://pragprog.com/titles/jaerlang2/programming-erlang-2nd-edition/ https://pragprog.com/titles/jaerlang2/programming-erlang-2nd... [2] https://learnyousomeerlang.com/ https://learnyousomeerlang.com/ [3] https://www.manning.com/books/erlang-and-otp-in-action https://www.manning.com/books/erlang-and-otp-in-action [4] https://erlang.mk/guide/index.html https://erlang.mk/guide/index.html [5] https://ninenines.eu/ https://ninenines.eu/
- AlchemistCamp 6y ago> every decent erlang book or tutorial I've ready, from Armstrong's book[1] to Learn You Some Erlang... What a coincidence! I just tweeted about how you can get it and 12 other various programming books for just $8 now: https://twitter.com/AlchemistCamp/status/1311796404830892032 https://twitter.com/AlchemistCamp/status/1311796404830892032
- derefr 6y agoI agree. The reason we stick with OTP, is that OTP behaviors like gen_server handle two system-level concerns that "raw" Erlang code doesn't: 1. OTP behaviors integrate with the OTP supervisor lifecycle management system (i.e. the OTP framework offers the supervisors standardized hooks to start up and shut down your process, guaranteeing that the errors generated during such steps will be in a format the supervisor can use); 2. Processes that implement OTP behaviors will react to `sys` messages; and so can be debugged, hibernated, code-upgraded, etc. on a framework level, "between" the times the process runs developer-defined code, without the developer having to write such handlers into their module. This is all accomplished by passing control over the receive loop to a framework — `proc_lib` in this case — which in turn passes any messages it doesn't recognize back to your process. It's an inversion-of-control: proc_lib "is" your process; gen_server or whatever is a delegate of proc_lib; and your module is the delegate for gen_server. It's like an OOP class hierarchy in a GUI system, where the base class handles some events, subclasses handle others, and then your module only has to handle the few it's interested in. But, if there was a way to do exactly that — to specialize one receive statement, defined in some other function, with your own additional clauses — then we wouldn't need the inversion-of-control framework of OTP! We could just write a regular receive statement that "points to" another receive statement as its "parent" or "fallback" (sort of like a chain of firewall rules, each pointing to the next as "what to check next if this one didn't handle it.") Ideally, the compiled result would be one fused receive statement that has all the clauses from all its parents. And if you think about it, that's totally possible, even if Erlang itself doesn't offer a fancy chainable receive statement like that... because, in a language like Elixir tht has hygenic macros, you can use macros to generate such "fused receive statements"! I'm honestly really surprised nobody has yet tried. I realized the possibility of this a couple years back, and have been waiting with baited breath for somebody to attempt it. If it worked out, this "tech" could be used to build a wholly-different-feeling language.
- lpgauth 6y agoWell, the sys behavior is easy to implement. I also am not a fan of the complexity and overhead of gen_server so instead I use metal (http://github.com/lpgauth/metal http://github.com/lpgauth/metal). It's a simple receive loop with an optional init and terminate callback. It implement sys and can be supervised.
- AlchemistCamp 6y ago> the basic notion of the spawn -> receive -> loop cycle is so clean and illuminating that I wish newbies would hold out before learning OTP sometimes The frustrating thing is that when I made exactly such a tutorial two years ago, I was immediately chastised (on my old hosted commenting system) for showing something so low-level to start with: https://alchemist.camp/episodes/simple-process-example https://alchemist.camp/episodes/simple-process-example