Hacker News new | past | comments | ask | show | jobs | submit login
History of Erlang and Elixir (medium.com/serokell)
132 points by factandfiction on April 2, 2020 | hide | past | favorite | 36 comments



Argh. Odd statements about "Erlang was implemented in Prolog, therefore, it's an FP language" aside, I was interested to read more on Elixir's meta-programming, and was assured that this code was a great example[1]. But there was no further discussion, just a Github link.

For anyone else wondering the same, the Elixir docs give more insight into quote/unquote[2]...

...but I'm still unsure as to why the Unicode code uses it. Most of the time it's unquoting byte_size - but why does what looks like a function call need to be unquoted?

It looks like it's defining the same function with different pattern matching clauses using it, e.g.,

  for codepoint <- cluster["CR"] ++ cluster["LF"] ++ cluster["Control"] do
    def next_grapheme_size(<<unquote(codepoint), rest::binary>>) do
      {unquote(byte_size(codepoint)), rest}
    end
  end
Would define next_grapheme_size with an arg pattern that matches each code point, effectively creating a pattern match switch without boilerplating it? I think? Keen to hear from someone who knows Elixir.

But yeah, some more detail on a) what it's doing and b) why it's awesome would've been nice.

[1]: https://github.com/elixir-lang/elixir/blob/0d32ea6bc4bcbd626... [2]: https://elixir-lang.org/getting-started/meta/quote-and-unquo...


The unquote in your code example doesn't necessarily need to be unquoted, it would be enough to unquote the codepoint variable here. The point, I guess, is about at what point you want to evaluate the code. There is a great little function called Macro.to_string that might make this more clear:

  Macro.to_string(quote do: length([1,2,3]))
will return "length([1,2,3])", so it basically creates a macro that, if included in some code, will calculate the length of the list [1,2,3] at runtime.

  Macro.to_string(quote do: unquote(length([1,2,3])))
will return "3" instead, it basically executes the length function at compile time and then the macro will simply return that if called.

So the code example you provided basically calculates the byte size at compile time and will then only return static results at runtime.


Thanks! That makes it clearer. So presumably the for loop it's nested in is also evaluated at compile time?


Yes, exactly. This code basically runs at compile time and creates functions that return static results. This case doesn't have to be wrapped inside of the quote thing (I'm not even sure if it would compile if you did...), which is somewhat confusing in my opinion.


Recently i've been writing a lot of compile-time checks in elixir's metaprogramming, like verifying that compile-time configuration TOML files are correct.

One way to think about it is that it's an in-line plugin system for your compiler. It's fantastic that the metaprogramming language is the same as the programming language.


Not a bad article but Phoenix is not "hands down the best web development framework that is out there".

It's quite great at what it does, and it's obviously technically well done, but it's also very not "battery included" so you have to shop around for a lot of things like Authentification/Authorization, i18n etc.

Also templating feels a bit old school. After using extends and blocks with Jinja2 and Twig the "layout that includes your action view" model feels so rigid and limited. It seems you can use render_existing/3 that would be equivalent to content_for in Rails but that's not that obvious to me

It's unfortunate because LiveView puts back server-side rendering on the map and it's exciting.


Here is something interesting that José Valim says about authentication frameworks: https://dashbit.co/blog/a-new-authentication-solution-for-ph...


It looks like a great start but it looks like they only plan to handle password based authentication based on the bullet points of features.

That would mean if you wanted to do magic link style authentication you'd be on your own. That's why I'm a fan of rolling my own authentication while using well tested libraries and modules to handle the lower level scary bits like session / cookie management, etc..

It also looks like it doesn't handle things like creating honey pots to help prevent bad actor sign ups. That's a very important feature to have on a system that will send out confirmation emails.

With that said, Phoenix and Elixir are great. At least we have the options to build our own solutions without too much effort -- especially around things like authentication.


Oh thanks, didn't kow they launched their blog.

Sadly they have apparently no RSS link.


Looks like it’s a completely custom blog engine judging by some of their other posts so you could probably ask them to add that feature if it’s not already there.


You’re right about batteries not included in Phoenix. The jinja2 extends sounds a bit terrifying to me.. Not only do you have to deal with figuring out Python class inheritance you have to figure out template ones in a pseudo-language?! It doesn’t look as bad as I feared but still [1]. Despite that I made a recent comment on HN regarding Jinja templates [2]. EEx looks basic but since Elixir is functional the templates are pretty powerful. I’m working on a LiveView wrapper for Bulma, which essentially needs “blocks” and was pleasantly surprised how easy it was to embed multiple layers of templates and it mostly Just Worked(tm) [3]. That was amazing to me! No need to deal with extra pseudo language inheritance. I'd like to use macros to simplify specifying child blocks and provide compile time check of block types, but I’ve got work todo.

1: https://flask.palletsprojects.com/en/1.1.x/patterns/template... 2: https://news.ycombinator.com/item?id=22746088 3: https://github.com/elcritch/bulma_widgets


I know "template inheritance" sounds horrible because of the name and the abuse of the concept in some oo languages ... especially discussed here in the context of a functional language ;) ... but I can really testify that extends&blocks work WAY WAY better than the traditional includes, especially for the layout level (by the way, you can still do includes when it makes sense).

Currently I'm doing a LiveView project where I have two layouts and a mix of traditional and LV pages. It really feels non-optimal to me to have to create plug pipelines just to use some put_*_layout() plugs.

I'm not even sure it should be a concern at the router level, whereas I could have just declare in each template the layout I wanted (extends) and/or use the three-level model, cf https://symfony.com/doc/3.4/templating/inheritance.html

I checked your library, I haven't tried LiveView components yet though, I only read the docs.


That symfony case makes a bit more sense. Especially in the context of views and layouts. Phoenix view/layout things still confuse me. Never tried learning them so I’ve got one global layout view setup on Bulma (or Bootstrap). It works as I’m doing more of an SPA style UI. I set a title using the controller which feels klunky too, like the put_*_layout setup.

Given Elixir templates are functional you probably could create a view “template inheritance” with a single macro. My Bulma library is intended to be pretty basic, but hopefully you see it’s easy to pass an case with sub-blocks.

I wonder if setting up a macro that could take named blocks and inject them into an EEx template might work for your case of including a view-template in a template. That’d be similar to what I’d like in my library, as it’d be nice to remove the extra “case / block” and just have a “template MyProject.Template, do :header -> <H1>Title</H1> end“. Bonus would be that approach would check block names at compile time! Also you should checkout live components. They’re handy for widgets!


> Phoenix view/layout things still confuse me.

When I worked through the Programming Phoenix book, for some reason the view/layout thing was what I struggled with most, and even in the years since its only been recently that I feel I have a proper 'grasp' of how it works.

I've been scratching my head as to why this, of all things Phoenix, has been tripping me up so much. Maybe it's right at the 'sweet' spot between Rails magic and (often) Phoenix explicitness, while also being the kind of thing that I find myself least interested in 'grokking'?


> Maybe it's right at the 'sweet' spot between Rails magic and (often) Phoenix explicitness, while also being the kind of thing that I find myself least interested in 'grokking'?

Think you nailed it on the head! It's a chore, and there's a bit of implicitness / Rails-style magic involved. Not much mind you, but the implicit naming thing trips me up.


I suppose the good part of the experience is that it taught me, once again, that as soon as I run into issues I should probably go read the docs until I properly understand things, rather than tweak things for a while until they magically work and then move on...


> Also templating feels a bit old school. After using extends and blocks with Jinja2 and Twig the "layout that includes your action view" model feels so rigid and limited. It seems you can use render_existing/3 that would be equivalent to content_for in Rails but that's not that obvious to me

There are some things to keep in mind with eex: it's built into the base language, it's meant to be super simple and explicit, and it built to be represented as a linked list. All of those things make it really fast, the simplicity makes it easy to understand.

There are some trade-offs of course, but it's not unpleasant to work with.


I personally like that Phoenix is kind of a middleweight framework, but at least one of batteries you mentioned as missing is being addressed. José is working on an authentication solution built into Phoenix.


Authentication is hard, but to be honest, building your own authorization framework is actually really easy in phoenix. Mine is about 80 LOC, and most of it came from the phauxth generator. Granted the default is rather broad, so I've added a few functions to handle some role specific stuff.


> It's quite great at what it does, and it's obviously technically well done, but it's also very not "battery included" so you have to shop around for a lot of things like Authentification/Authorization, i18n etc.

FWIW, Phoenix does come with I18n support, through GNU Gettext.


Thanks. Is it sufficient to handle date or number formatting ? I was under the impression you had to use elixir-cldr, Timex etc for a comprehensive localization.


Yeh, you'd probably want to use Timex.


Phoenix + Ecto has been the best web framework experience I've ever encountered. I have experience with Django, Flask, Express and Rails. I'm a huge fan of Elixir as a language and the BEAM runtime. The libraries have been pretty great too.

I agree that templating could use a more forward-looking approach as a first-class concept (something like https://github.com/github/view_component).


https://powauth.com is a great Phoenix auth framework for API and HTML based apps.

It ships with gettext by default for i18n.


phoenix seems like a throw back. compared to rails or django it's pretty good, but it does not seem forward looking. i haven't worked on anything that relied on server side rendering in four years and it's 'opinionated' macro based module generation is a hindrance to building a more typical api based http service


There are a lot of reasons to move to client side templates but virtually all of those reasons go away in a BEAM environment.

Let's start with the biggest one: template performance.

When you benchmark the template rendering in Rails, Python, etc usually you find that the View layer accounts for well over 50-60% of the request time. That's because for the most part these systems are creating new string based output that needs to be sent back to the client which means allocating and cleaning up lots of RAM.

Within Phoenix, each snippet of text in the template exists in memory exactly one time. The rendered template never even exists on the server, it simply loops through a list of parts to stream back to the user's connection, injecting variables where needed. In my own testing (and testing echoed by many shocked people) this approach will border static file performance. Most people avoid caching entirely within Phoenix applications.

Here's a detailed write up if you're curious:

https://www.bignerdranch.com/blog/elixir-and-io-lists-part-2...

And here was my own experience:

https://www.brightball.com/articles/insanity-with-elixir-pho...

Next up is payload isolation. One of the big pushes for client side rendering (outside of interactivity) is the ability to make separate async requests to different APIs in isolation to avoid the sequential loading bottleneck.

BEAM languages are designed for millions of asynchronous calls at once without overloading the system and as a result this means that you can easily make all of those async service calls on the server side within a single HTTP request.

The combination of these two characteristics is what makes LiveView possible in Phoenix, where it's really not a feasible exercise in most other languages.

https://dockyard.com/blog/2018/12/12/phoenix-liveview-intera...

Because of that ability to handle so many async processes, it also create an ideal environment for websocket based work along side standard HTTP based projects.

Client side applications tend to account for this by storing data within the browser to keep a running log, but Phoenix channels create the ability to maintain user state in a dedicated process for each user's connection...rather than in the browser or a server side data store. Aside from extremely data heavy workloads in browser, this eliminates the need to store data in the browser and makes it simpler to sync data across multiple browsers, devices or applications.

And this improves further with the ability to expand an elixir cluster horizontally without the need for a central data store to help those web servers communicate.

The author isn't exaggerating when he promotes Phoenix as a premium option. There are things you simply can't do in any language that has a shared memory model. The BEAM capabilities create an environment where layers upon layers of complexity just, go away.

Including the need to depend on client side templating.


even if these were the only considerations for moving rendering to the client side (i don't believe this to be true, but it's irrelevant) the vast majority of ongoing http development i see working at both small (< 50 people) and large companies has nothing to do with html


If it renders in the browser it does.

There's nothing stopping you from also building an API. The design of an elixir application pushes you to assume that your code has a job to do and that job may be accessed via multiple different interfaces:

- Websocket

- API

- HTML

- Command Line

- Another node in the cluster

Any of these will be calling the same logic behind the scenes. There's nothing preventing you from breaking it into smaller pieces or still leaning on client side logic if it makes sense.

The important thing is that you have the flexibility to attack the problem in an direction that suits it without language limitations dictating the client side approach as your only feasible option.


Can you expand on what you mean by "it's 'opinionated' macro based module generation is a hindrance to building a more typical api based http service"?


sure. what i mean is by opting in to `use Phoenix.Controller` you are also opting into `MyApp.PageController`, `MyApp.Endpoint`, `MyApp.PageView`, `MyApp.ErrorView`, `MyApp.LayoutView`... which are all modules you include via macros in your actual implementation (or which are included by other includes)

all of these modules assume a traditional server rendered html environment with appropriate CORS, session handling, form security, etc none of which are particularly relevant to returning json from an api request

it is possible to opt out and directly manipulate the Plug conn (and set the response) but at that point Phoenix is bringing almost nothing to the table


elixir is npm for erl.

the single example you need to know to snub it:

   x = 1
   x = 2
thats valid elixir. you're better off using javascript or php at this point


that's valid javascript (it's also very dangerous javascript)... and would be valid php if you sandwich it between a $ and a ;

elixir is not npm for erlang, hex is more like npm.


elixir is mix. mix is hex.

hence elixir is npm for erlang


nope. variable rebinding is not what makes and breaks elixir.

elixir is awesome and has done more to popularize the good ideas behind erlang than a lot of other languages/tools.


   x = 1
   x = 2
Why is that a problem? It's shadowing, not mutation.


Ahh you seem to be on that phase...




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: