1,140 karma · joined November 30, 2010
This shows a significantly different story between the two with at least similar code. Note I am not trying to optimize for the fastest factorial here as both can be made much quicker but roughly equivalent code seems to tell a different story for me.
(NOTE: I put the code in a module as iex interpreted expressions on the top level are always slower than compiled modules, even when pasting them into iex. Doing the same for Ruby didn't show any difference for me.)
It looks like their test includes plenty of ad heavy sites like news articles which seems to confirm that the results are cherry picked.
Before I came out I felt very awkward with regards to my own pronoun display. I wasn’t ready on one hand and on the other I felt terrible seeing other pronouns even if it was attached to my deadname only.
I’d encourage people to do it if they’re comfortable with it on a personal level as it can be a very personal thing. I also want to thank all of those who do add it. It’s a big deal for many of us and can make a real difference in exchange for very little effort.
It depends on what you'd like to accomplish, but given that powerful FPGAs are now more affordable and plenty of great FPGA friendly libraries are emerging which work with open source tools, the barrier for Soft-CPU implementations has lowered significantly. This sort of project looks great for cases where trusting blackbox chips was questionable.
I also spend time on Windows and nothing seems to come close to this convenient (win-. has a few useful things like the character picker panel in macOS but to get more, tools like autohotkey feel really cumbersome).
The article makes it look trivial but if you note the ASCII diagram starts by labeling each byte-row with 7 not 0. Without some way to switch bit numbering (kind of like bit endianness) of the entire expression, we can't make something that looks like continuous bits in one view look continuous in the other.
A reduced example:
7 6 5 4 3 2 1 0
------------------------+-------+
0 5 X 0 | Y |
------------------------+-------+
1 13 X 6
Here we can't say <<Y:2/little, X:14/little>> (Y is bits [0,1], X is bits [2,15]) because we need to read <<X1:6/little, Y:2/little, X2:8/little>> (X1 is bits [0,5], Y is bits [6,7], X2 is bits [8,15]).The interpretation of the contents of those bits will be done in "little endian order" (odd term since endianness is a byte order not bit numbering concern) as the expression says but because Erlang or similar syntax has no knowledge of the bit numbering we have in this diagram, it can't automatically assume that the first bit is numbered 7 not 0.
Laying the bytes out on a line makes the notational problem more obvious:
7 6 5 4 3 2 1 0 | 15 14 13 12 11 10 9 8
------------------------+-------+---------------------------------
5 X1 0 | Y | 13 X2 6
------------------------+-------+---------------------------------
Even if we know that we interpret each number with a given endianness, the bit stream numbering here needs to be expressed separately at the top level. Generally, this is why serialized protocols prefer to start bit numbering at 0 like the written in the IPv4 header example.To get an idea of the instruction stream of the BEAM (not the same as .beam asm), you can use the erts_debug module:
iex> :erts_debug.df(String)
This will dump a BEAM machine instruction stream to a file named Elixir.String.dis in your current working directory. You'll see things like: 000000001B81AFB0: i_func_info_IaaI 0 `'Elixir.String'` `at` 2
000000001B81AFD8: is_integer_fx f(000000001B81AFB0) x(1)
000000001B81AFE8: is_ge_literal_fxc f(000000001B81B008) x(1) `0`
000000001B81B000: i_call_only_f loc(`'Elixir.String'`:`do_at`/2)
000000001B81B008: allocate_tt 2 2
000000001B81B010: move_window2_xxy x(1) x(0) y(0)
000000001B81B018: i_call_f loc(`'Elixir.String'`:`length`/1)
000000001B81B020: i_plus_xyjd x(0) y(0) j(0) x(0)
000000001B81B030: is_ge_literal_fxc f(000000001B81B060) x(0) `0`
000000001B81B048: move_shift_yxx y(1) x(0) x(1)
000000001B81B050: i_call_last_fQ loc(`'Elixir.String'`:`do_at`/2) 2
000000001B81B060: move_deallocate_return_cQ `nil` 2
Each of those instructions are what the .beam file loader currently generates. With the JIT, these will be replaced by machine code.When the news of the acquisition hit, everyone wanted to see the WhatsApp talk. The organizers knew this so we swapped rooms. So, I started my talk by asking if anyone in the room was here for the WhatsApp talk and told them they could quietly leave and I wouldn't mind and a bunch of people got up.
Heheh. I don't blame them. I didn't really like my talk and Rick Reed is very good at what he does and the talk is no exception.
That was many years ago as well. The distributed erlang story has improved with more recent releases (better performance on remote monitors for example) which might push the number a little higher than 300 if you are careful. Keep in mind the default style of clustering is fully connected so there is some danger in managing that many network connections (quadratically scaling for each node added) during network partitions which can be a problem if you're not tuning things like TCP's TIME_WAIT for local networking conditions.
Even better, these days there are great libraries like partisan (https://github.com/lasp-lang/partisan) which can scale to much larger cluster sizes and can be dropped in for most distributed erlang uses cases w/o much effort.
erl_interface itself is not going away but it is evolving with the BEAM VM. Deprecation warnings should be checked when compiling code on each major release to avoid surprises as features are usually deprecated for one release and then removed in the next release each year. The erl_interface documentation should be up to date with regards to new APIs and might be worth browsing again to get an idea of the what changes look like.
Likewise, links and monitors are used for lifetime concerns instead of reference counting actors like Pony or using a global tracing collector. This has some advantages and disadvantages but for the most part I personally find it far more practical than other models which are more like the classic actor model.
Badfun errors are a great example of something tricky if you're not used to thinking about how the compiler translates these to private functions via lambda lifting. It's the same reason funs are not something you should rush to pass around over a disterl cluster. Recursive functions which keep fun's around in a loop also become a problem if they're long lived.
I usually point out that first class modules or MFA tuples are more idiomatic in Erlang than opaque first class functions as values but we're off into the weeds here. It's a good example of where effort and gotchas become a barrier for many.
Keep in mind that we rolled out the patch incrementally to one or two machines and then to more. If it looked good we’d roll it out to the rest of the cluster. From there we’d make note of the result and get the change ported into a proper release.
Each time I hear stories that both clustering and hot upgrades, module loading, etc are hard or rarely used I wonder if the person is just repeating someone else’s rumor. They’re great features and work fine if you do a little homework (just like learning anything, don’t treat it like magic).
This was from my time at Cloudant/IBM, though its far from the only case I’ve seen. We ran over 1000 machines this way with some clusters growing to more than 200 nodes using distributed Erlang (something I keep hearing is hard or impossible, it’s not).
It’s not clear if the lanes themselves can be multiplexed with packets from many devices but they can change the number of assigned lanes after initialization so a clever chipset could probably dynamically allocate lanes as used.
I also glossed over the I/O system and back pressure support which make the above discussion a bit more nuanced but my goal was to lay down some form of intuition around thinking in terms of progress in a system as a guarantee of the concurrency model.
Empirically speaking, there are real limits to what hardware will hide and plenty of room for leveraging knowledge of the system as a whole (esp. the memory model) rather than sticking to one set of abstractions. Pony is no exception here, though the co-design of various features might make that less necessary than it might be in other systems with similar properties as it matures.
My only problem with this solution is that it changes the mix configuration itself (which is version controlled) which is fine if others are in need of similar overrides when working on the project. For one-off/local things, it can be a bit heavy for temporary overrides.
Still, it's a fair trade-off since it's a lot easier to code up logic like this with mix compared to rebar3.
I think both languages have issues with Syntax but in the cleaner department, I am baffled at the insistence that Erlang is hard. Inconvenient, maybe but most of the features in Erlang are so primitive that there is little to no ambiguity of what something can mean.
Verbosity strikes both (records and binaries in Erlang vs the sigil and keyword heavy Elixir code) and certainly some folks prefer rebinding variables and colon syntax on atoms but it's certainly not without real trade-offs in common idioms (tagged tuples, special casing required for atoms like true, false, nil, interop with Erlang becomes uglier, etc).