PragDave’s new Component library - his preferred way of building apps

Except it only uses those at compile time, and they are inline then, like here:

This is where you use Plug.Builder, it defines a few function, sets a few compile-time variables (behaviour and plug_builder_opts), and at the end it does register an attribute to aggregrate an attribute. However, a module attribute at compile time is the same as just normal bindings in a normal function at runtime (it is runtime at compile-time), they are not accessible before defined and they can be rebound just like function bindings.

Even still, this relates to Purity, not Functionality, it is not entirely ‘pure’ as I think Module.register_attribute/3 sets something in an ETS table, but it is still Functional. :slight_smile:

It is stateful in the same vein as bindings in a function are stateful, like this:

def something(a, b) do
  c = a + b
  blah(c)
end

This function is stateful in that there is intermediary state before the c = a + b expression, a new state where c is bound, you cannot use the c binding before it is bound (state!), and the state is passed into the blah/1 call, but this is still Pure and Functional both.

5 Likes

Personally I’m interested in the net gain, so I think both should be considered when evaluating some proposal. In this particular case, my impression is that the only supposed benefit is information hiding. Given the downsides I’ve listed, I think we lose much more than we get. In fact, I’m currently not convinced that there’s any benefit here. Information hiding can be done without processes too, by declaring the type as opaque and using dialyzer to verify it.

Note that my comments are related only to this single aspect of your exploration. The components experiment seems to pack a lot more than just separating concerns with processes. In fact, based on what I’ve read so far, I’m not really sure how important the “design with processes” approach is to the entire components thing.

In any case, I wish you best of luck with your exploration. My comments might be somewhat negative, but I’m actually a fan of challenging old dogmas, so I’m looking forward to see how your experiment will evolve!

10 Likes

Personally I quite like the idea and the implementation.

Provided you understand when not to (ab)use processes – which many comments here indicated can itself be a problem, but it’s one solved with experience regardless – then I think this library has a really good niche. Even if you use it to only reduce boilerplate, it’s still a big win.

Because a DSL compiles to functional code does not a functional language make :). Though, yes, it is much about “feel” and not technical details.

When I see a plug router with the DSL I do not see functions that take inputs and return results - -at least I assume Dave is referring to the router because he mentions the conn variable.

I wonder if it’s a documentation issue… I’ve seen plug as a purely functional construct that passes, essentially a monad from function to function to function, returning a new version of it, but I’m not sure I’ve even read half of its documentation, I learned it by reading its code. Maybe the structure of ‘what’ it is could be made more clear in the docs?

2 Likes