I would say that there are real technical issues behind it. The Ruby implementation (at least ruby 1.8) is not designed for concurrency : ruby 1.8 has a global interpretor lock, and it uses green threads instead of OS native threads.
So, for a web application to scale, you have to run multiple ruby interpretors, and make them work together.
Note : I am not into web development, and It's been a long time I haven't used ruby. Maybe ruby 1.9 or JRuby don't have these issues. Maybe the global lock is not a real problem for scaling up.
"Single Entry, Single Exit" was written when most programming was done in assembly language, FORTRAN, or COBOL. It has been widely misinterpreted, because modern languages do not support the practices Dijkstra was warning against.
"Single Entry" meant "do not create alternate entry points for functions". In assembly language, of course, it is possible to enter a function at any instruction. FORTRAN supported multiple entries to functions with the ENTRY
statement:
SUBROUTINE S(X, Y)
R = SQRT(X*X + Y*Y)
C ALTERNATE ENTRY USED WHEN R IS ALREADY KNOWN
ENTRY S2(R)
...
RETURN
END
C USAGE
CALL S(3,4)
C ALTERNATE USAGE
CALL S2(5)
"Single Exit" meant that a function should only return to one place: the statement immediately following the call. It did not mean that a function should only return from one place. When Structured Programming was written, it was common practice for a function to indicate an error by returning to an alternate location. FORTRAN supported this via "alternate return":
C SUBROUTINE WITH ALTERNATE RETURN. THE '*' IS A PLACE HOLDER FOR THE ERROR RETURN
SUBROUTINE QSOLVE(A, B, C, X1, X2, *)
DISCR = B*B - 4*A*C
C NO SOLUTIONS, RETURN TO ERROR HANDLING LOCATION
IF DISCR .LT. 0 RETURN 1
SD = SQRT(DISCR)
DENOM = 2*A
X1 = (-B + SD) / DENOM
X2 = (-B - SD) / DENOM
RETURN
END
C USE OF ALTERNATE RETURN
CALL QSOLVE(1, 0, 1, X1, X2, *99)
C SOLUTION FOUND
...
C QSOLVE RETURNS HERE IF NO SOLUTIONS
99 PRINT 'NO SOLUTIONS'
Both these techniques were highly error prone. Use of alternate entries often left some variable uninitialized. Use of alternate returns had all the problems of a GOTO statement, with the additional complication that the branch condition was not adjacent to the branch, but somewhere in the subroutine.
Thanks to Alexey Romanov for finding the original paper. See http://www.cs.utexas.edu/users/EWD/ewd02xx/EWD249.PDF, page 28 (printed page number is 24). Not limited to functions.
Best Answer
In the old days (1970s and before) some computers did not have any MMU (and this is true today for very cheap microcontrollers).
On such systems, there is no memory protection so no read-only segment in the address space, and a buggy program could overwrite a constant (either in data memory, or even inside the machine code).
The Fortran compilers at that time passed formal arguments by reference. So if you did
CALL FUN(4)
and theSUBROUTINE FUN(I)
has its body changingI
- e.g. with an statementI = I + 1
in its body, you could have a disaster, changing 4 into 5 in the caller (or worse).This was also true on the first microcomputers like the original IBM PC AT from 1984, with MS-DOS
FWIW, I'm old enough to have used, as a teen ager in early 1970s, such computers: IBM1620 and CAB500 (in a museum: these are 1960s era computers!). The IBM1620 was quite fun: it used in memory tables for additions and multiplications (and if you overwrote these tables, chaos ensued). So not only you could overwrite a 4, but you could even overwrite every future 2+2 addition or 7*8 multiplications (but I really forgot these dirty details so could be wrong).
Today, you might overwrite the BIOS code in flash memory, if you are persevering enough. Sadly, I don't feel that fun any more, so I never tried. (I'm even afraid of installing some LinuxBios on my motherboard).
On current computers and operating systems passing a constant by reference and changing it inside the callee will just provoke a segmentation violation, which sounds familiar to many C or C++ developers.
BTW: to be nitpicking: overwriting 4 is not a matter of language, but of implementation.