4 ms·
Do you have any concrete examples you can link to show these differences? I'm unsure what you mean by architectural decisions made at the language level.
by ducharmdev 6y ago
Do you have any concrete examples you can link to show these differences? I'm unsure what you mean by architectural decisions made at the language level.
- jkhdigital 6y agoI am porting a cryptocurrency arbitrage trading platform from Node to Elixir and the difference is extremely refreshing. The actor model lends itself naturally to abstractions like producer, consumer, batcher, dispatcher, etc. which are like stations on an assembly line. “Pulling the chain” when problems occur at any point along the line is simple and clean since the actors are not tightly coupled in the first place. I think the key “architectural decision” here is that code and execution (i.e. the process) are bundled together by design.
- argvargc 6y agoMaybe a good example could be the recursion pattern in Elixir. This is considered almost a base element of the language. Typically in Elixir recursion and "guards", are used instead of things like for-loops and if-else statements in other languages. Take a basic factorial function in Elixir: defmodule Math do def factorial(0), do: 1 def factorial(n), do: n * factorial(n - 1) end There is almost nothing there that isn't directly representative of the base math equation itself (which, by convention, treats the result of factorial(0) as equal to 1). The function order is important in this case, the first is a "guard" that prevents the second from being executed when the firsts case is met. At this point the module exits out of the second function by multiplying the (silently) accumulated result by 1 and returning it. Versus, in JS: function factorial(n) { if (n == 0) { return 1; } else { return (n * factorial(n - 1)); } } It's not too bad, but the if-else, comparison, multiple return statements and nested brackets at the second return are all done away with in the Elixir version. Further, recursion is not something many programmers reach for first when working in many other languages, perhaps out of habit, or maybe of the concern that extending such implementations later can become difficult. As such, most programmers might implement the above as more something like: function factorial(n) { if (n === 0 || n === 1) return 1; for (var i = (n - 1); i >= 1; i--) { n *= i; } return n; } Compared to the Elixir code, many steps are required to read and understand this. When this type of laboured patterning is expanded out into a larger project, with many interlocking parts, it may quickly become difficult to work with, and can become necessary, and necessarily difficult, to refactor into something simpler, which then may require rethinking the entire process.
- jake_morrison 6y agoThat's a good example, but I would not want to overstate the need for recursion. Most people look to the standard patterns in https://hexdocs.pm/elixir/Enum.html https://hexdocs.pm/elixir/Enum.html unless they are doing some custom control flow. Pattern matching is really helpful, though. It turns complex nested logic into simple truth tables and acts like Eiffel's design by contract, just pattern match on valid inputs, then handle the errors. The same functional patterns repeat at different levels in the stack. For example, in the Phoenix web framework, processing a HTTP request can be considered as pattern matching on the expected inputs (validating them), then a series of transformations (making a db request, taking the result and rendering it into HTML via a template), then returning the result. From a concurrency perspective, the interesting part is that each HTTP request runs in its own separate blocking process (green thread). So when you are doing the programming, you don't need to think about concurrency and async stuff. You just do your thing. This makes it easy to think about and debug.
- ducharmdev 6y agoThat Elixir part is pretty slick. But to be fair to JS, you could also write that JS function like this: let factorial = n => n === 0 ? 1 : factorial(n - 1) * n; But I do wish JavaScript had some more powerful pattern-matching syntax. For example, both Rust and C# both have nice switch/match expressions that can really simplify code like this.