5 ms·
Reading an Erlang book, no offense, is not going to give you the insight necessary to do a competent comparison of Erlang and PHP (or any other language). I am
by defined 9y ago
Reading an Erlang book, no offense, is not going to give you the insight necessary to do a competent comparison of Erlang and PHP (or any other language). I am not sure if you have written any significant production systems using Erlang, and if you have, I apologize and withdraw the implication that insight is lacking.
Please let me explain why this makes me raise an eyebrow.
Let's take just one thing: hot code loading.
When Erlang does hot code loading, it loads it into the currently running process. This means that any socket opened by that process stays open, and the connection is uninterrupted. The process doesn't stop running, or restart. In fact, the process is, for a short time, running both the old and the new code at the same time. When the process gets to the point of completing the recursive loop within which the old function was called, the new one gets switched in seamlessly and is called from there onwards. I know of no other language that has such mutable late binding, but I can't say they don't exist.
This is, I believe, entirely different from an interpreter loading new code into a different process (or restarting the current one) on detecting a new file. If you can assert that after loading new code from a file,
1. The process pid is unchanged (it's literally the same process), and
2. The process data state is unchanged (it's literally the same process memory) and
3. The process file handles and sockets are unchanged
maybe I could agree with your point of view.
- vidarh 9y ago> When Erlang does hot code loading, it loads it into the currently running process. That is also usually true for PHP code using Fastcgi or mod_php or similar. It's not true for PHP code using PHP as a CGI, but nobody has done that since the 90's. It may depends on settings for opcode caching and the like. > This means that any socket opened by that process stays open, and the connection is uninterrupted. One of the earliest optimisations for PHP was the ability to make database connections persist across requests. See [1] for documentation of how to do this in current versions of PHP but it has been available pretty much from the start. > When the process gets to the point of completing the recursive loop within which the old function was called, the new one gets switched in seamlessly and is called from there onwards. I know of no other language that has such mutable late binding, but I can't say they don't exist. Plenty do. This is valid Ruby that replaces the method "foo" for each iteration of the currently running loop: (1..10).each do |i| eval(<<END) def foo puts #{i} end END foo end (the textual eval rather than simply inlining the method definition is necessary because "i" is a local variable not accessible from within the newly defined "foo" - if we used e.g. an instance variable instead it'd work, but then foo would effectively be static which would defeat the point of the demonstration) Ruby's and PHP's ability to do hot reloads is similar, but it needs the running script to cooperate in the loading unless you use a containing process that embeds the interpreter and does hot loading that way. But the PHP approach there is traditionally instead to throw away the code on each request. > 1. The process pid is unchanged (it's literally the same process), and 2. The process data state is unchanged (it's literally the same process memory) and 3. The process file handles and sockets are unchanged To me these are optimisations that are undesirable unless you need them. They're necessary for performance, but they make the system more vulnerable to working on corrupted data. As such I don't think it's a good distinction, but as mentioned depending on how you run PHP it can/will meet 1. and can meet 3. to some extent, and will meet 2. for session data, so it's up to you how much persists across requests. [1] http://php.net/manual/en/features.persistent-connections.php http://php.net/manual/en/features.persistent-connections.php
- defined 9y agoTo reiterate, I am saying only that it is unfair to Erlang to portray PHP's (or Ruby's) operational characteristics as "like Erlang". It may be true in the loosest possible interpretation, but the details differ radically. Your argument dismisses as optimizations things that are critical to systems for which Erlang was designed - telecoms. They are not optimizations for Erlang - they are necessary features that permit "write once, run forever" style operation. Keeping a connection open and available in a database pool is admirable, but not even remotely comparable to keeping a TCP socket open between two participants in a phone call, with RTP voice data flowing, and changing a function - at run time - in that very same process, without disrupting the voice data. The Erlang-style hot code loading doesn't make an Erlang system more vulnerable to working with corrupted data by not killing the process. That's just incorrect. In any case, well-written Erlang code will self-terminate if it detects anomalies. And it's harder to corrupt data in Erlang because of its immutability, absence of global data, and process isolation. Compare the rather ugly and unsafe Ruby code with the equivalent Erlang code (provided as a separate module): -module(demo). -export([run/0, foo/1]). run() -> lists:foreach(fun(N) -> foo(N) end, lists:seq(1, 10)). foo(I) -> io:format("~p\n", [I]). What the Ruby code does is in no stretch of the imagination "mutable late binding". It is evaluating (and hence interpreting) static text, which happens to redefine a Ruby function, every time through the loop. That's equivalent to recompiling a piece of code in a loop. Where does this load new code? You can eval code in practically any interpreter, from Perl to Python, and it's an unsafe and slow operation and not remotely the same as hot code loading in the Erlang sense. The Erlang code is compiled, usually on another system, and the compiled BEAM code is copied to a live server, and loaded into memory into every running process that uses that module, simultaneously, without crashing or restarting any of the processes. In fact, if there is a cluster of servers, and the replacement code (let's call the module "athana") is copied to the disks of all the servers in the cluster, it can be loaded into all processes running "athana" on all connected nodes of the cluster by entering this one line in the Erlang shell of any one of the production cluster nodes: > nl(athana). That's it. Please, let's stop this fruitless debate. It is obvious that we are not going to agree, and we are using the same phrases to mean completely different things.
- jeffdavis 9y ago"If you can assert that after loading new code from a file, ..." You are arguing about technical details, and I am arguing about architecture. The only way you will agree with me is if you zoom out a bit, and look at it from the developer's point of view: * To deploy a bugfix, did the developer have to take the system down for maintenance and/or interrupt service? The answer for both PHP and erlang is "no". * Does a runtime exception/crash bring down a large part of the system, or is it isolated as much as possible (often to a single request)? The answer for both PHP and erlang is the latter. Those are two of the biggest claims erlang can make, and PHP can make them, too. Either the erlang community has a lot of difficulty communicating the advantages, or they aren't quite as unique any more (though perhaps they were at one time). Now, erlang does have it's place. It's great for handling arbitrary protocols and getting a reliable, performant network daemon going quickly[1]. The binary pattern matching is awesome. The erlang shell allows you to have a point of entry to find out what's going on in a system while it's running. Really awesome stuff. [1] I wrote one such daemon, replacing a bunch of python and finding a lot of bugs in the original along the way. The erlang version was about 50% as many lines of code, even though I wrote out all the typespecs and had to reimplement some things that the python version got for free. But the service was tiny, so you're right, I'm not an erlang expert.