1) Lacks variable declarations.
1a) It means that invalid variables are caught at runtime instead of compile-time
1b) Easy for unintentional overrides to occur as users may not be aware that a variable was already in existence.(especially in a group environment).
1c) If a developer misspells a variable, hard-to-find bugs may emerge. Eg:
alc = 1
a1c++
The letter l & the number 1 look the same in text editors.
2) No support for interfaces. Contracts are enforced through interfaces and regardless of underlying implementation.
(Mix-ins are comparable to interfaces, but mix-ins have common functionality already implemented in them )
3) Only one type of floating point supported. From Programming Ruby, First edition: "Float objects represent real numbers using the native architecture's double-precision floating point representation."
So:
- Ruby does not support single-precision float types that are suitable for fast calculations. (When one does not need the precision but needs the speed).
- Ruby does not support decimal types that are suitable for financial and monetary calculations that demand high precision/accurracy.
(In the case of real numbers, such as 1.333, the interprator/compiler can't possibly guess whether the user wanted to use single or double precision.
Of course for whole numbers this is NOT an issue since the interprator could store small numbers in an integer and if the numbers gets larger it could automatically store the larger numbers in a long).
4) Simulated threading issues
Newer versions of Ruby will support kernel threads. Earlier implementations support only simulated green threads. More issues here:
Ruby's multi-threading seems to be a misfeature from tip to toe. Ruby's multi-threading is simulated: it only runs on a single CPU and is fundamentally incapable of taking advantage of multiple CPUs or multiple cores within a CPU. Which is just as well, because Ruby doesn't define a memory model for coordinating data between CPUs or cores. Then there is the problem of global variables being changed as side effects and accessed implicitly. Writing multi-threaded code in Ruby looks like a good way to cause yourself immense non-deterministic grief.
5)
Describing Ruby's "somewhat cooperative" threading scheduler, the official Ruby wiki notes the language's limitations, most shockingly with regards to the 10ms timeout to guarantee atomicity and allow context switching. "On a high-end system, a 10ms timeslice can be an extremely long time; when running a thousand threads, as might be common in a large massively-concurrent application, it would take at least ten seconds for all threads to get a timeslice. Because of the issues associated with this 10ms timeslice and those associated with green threading in general, concurrency in Ruby is typically achieved by running or spawning additional Ruby processes."
Ruby also boasts some native-incompatible threading features such as the ability to kill threads from anywhere in the program, invoke infinite sleep states and enter critical sections at will.
Benjamin Gorlick has written an informative piece on the challenges of threading in Ruby and the hopes its aficionados have for concurrency support in the future. Rails, especially, "was not designed with multi-threading in mind. It was coded completely non-thread safe. There is no reentrancy in many code paths and there is no good locking on important data structures, especially during development mode. It appears rails core is assuming everyone is going to stuff their servers with as much RAM as possible. I recommend 8-16GB of RAM for applications over ten pages (That was a joke, sort of). The RAM solution works until you reach the point of running a huge installation. Assuming you are using mongrel to serve your rails applications, most developers are coming up with hacks to move logic out of rails so the mongrel processes will be lighter. This is done using basic message queues and partly helps this sort of operation. Small shared hosting applications and small projects really suffer from the rails lack
http://www.devx.com/go-parallel/Article/36235?trk=DXRSS_LATEST
6) I/O in Ruby and threading issues.
Per article Ruby 2.0 support kernel threads (in addition to existing user threads a.k.a. green threads)
While the lack of kernel threads (threads scheduled and handled by the OS) can be a problem, it is not an unsolvable. I/O is the big issue, particularly network access, since it can potentially block for long times. If this happens on the GUI event handling thread, it will leave the GUI unresponsive for the duration. That problem is solvable by using non-blocking I/O with the select call. select allows to specify timeouts for I/O operations, such as waiting for input from a socket. If no data has arrived before the timeout, the call returns and the code is free to yield to other threads, for instance the thread handling GUI events. Later on the I/O operation can be tried again. By using short timeouts, this acts like time slicing mechanisms that thread schedulers use.
http://www.infoq.com/news/2007/04/ruby-userspace-threads-roundup
7) Global variables.
http://creativekarma.com/ee.php/weblog/comments/ruby_better_than_perl_but_what_isnt/
Ruby exalts global side-effects. In a nominally multi-threaded language, this is unseemly to say the least. As an everyday example, the statement
x = getsreads a line and sticks it into x just like you'd probably expect, but it also has the side effect of sticking the line into the global variable $_. WTF???
Ruby seems to love the magical global variables carried over from Perl. There are dozens of them, all with nonintuitive names like $_, $!, $*, and $~. Yuck. These things get set as side effects, and often are used implicitly.
Ruby's exception mechanism combines the above failures into an astounding disaster. When an exception occurs, an exception object is created and stored into $! which is a global variable. Apparently you aren't supposed to get exceptions in more than one thread at a time. Updated 9 January 2005: It turns out that this isn't actually an issue; read the comments for details.
8)
Constants can be redefined. A warning will be generated, but no error.
Well maybe for some situations that is desirable. But in a team environment one needs to be aware of side effects
9) Constant look up problem:
Look up rules pretend to be static, but they are not.
http://www.rubyist.net/~matz/slides/rc2003/mgp00016.html
10)
-In Ruby, visibility is completely dynamic. You can change method visibility at runtime! you could dynamically make some method private at some point, and later - public.
http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes
I think this is likely to produce hard-to-find bugs.
11) Non-intuitive (sometimes)
11a) to get a character for s use the un-intuitive s[2,1]
s="abc"
=> "abc"
irb(main):010:0> s[2]
=> 99
irb(main):011:0> s[2,1]
=> "c"
11b) What does a[x,y] (when a is a two-dimensional array) mean in Ruby? Not what I first supposed it might mean from other languages
http://www.bitwisemag.com/2/What-s-Wrong-With-Ruby
11 c)
Pascal-style if is supported as well as C-style if:
if foo = nil then
end
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/51486
12)
Ruby doesn't enforce namespacing to be done. So if you just want to toss out some code, you don't worry about namespaces and you code and it ends up in a global namespace.
Proposal for ruby's global namespacing issue:
http://www.rubyist.net/~matz/slides/rc2003/mgp00029.html
13) Security features comparable to Java Policy files or .NET security features such as Code Access Security are missing.
(Security in interpretive version is questionable. Code injection in interpretive version is plausible.)
14)
This is NOT about the Ruby language itself. It is regarding systems that were built on top of Ruby:
Caching for web app. There are various caching options in .NET that I've not sure how Ruby will deal with. (Page caching, user control caching, the Cache object, etc).
15)
I tend to agree with these:
http://www.bitwisemag.com/2/What-s-Wrong-With-Ruby
Ruby's dynamic typing is put forward as more elegance. I can take it or leave it. Yes, it gives a superficially cleaner appearance to code by cutting out all the syntax required to maintain static types, and required for compile-time checks to ensure that methods are only called on objects that can accept them. But who really uses a variable or argument without some idea of its type? I see types as useful language-supported comments, a guide to clear thinking. My advice to novices is always to start by writing a method's header, with its argument and return types, that is the first step to understanding what it does. When I look at old code, the types are a good guide to start working it out. I'd hate to have to debug a large piece of typeless legacy code, that wouldn't be "fun" no matter how much fun it was when its original author picked up Ruby and threw away types.
Ruby's dynamic class modification also strikes me as something with the potential to produce hugely complex and non-understandable code. If I am tracking down the source of some buggy behaviour, I might start by looking for the class of the object whose method call led to the bug. The lack of types in Ruby would make that more difficult, but on top of that I have to face the possibility that the method may have been redefined somewhere else during code execution, maybe for the whole class, maybe for the individual object. There isn't one class definition I can reliably say completely defines an object's behaviour. There is a growing criticism of code inheritance in Java, with recommendations that we stick to interface inheritance and otherwise use composition and delegation for clearer and more reliable code. How very much worse this problem is with what can easily be done in Ruby. Sure, the ability to modify code dynamically can be valuable, but it should be done with caution and clearly flagged up. The casual nature by which it can be done in Ruby worries me - again, it may be "fun" now, but how about debugging code using it in a few years time?
16) Just Gotchas:
16a) -Names that begin with a capital letter are treated as constants, so local variables should begin with a lowercase letter.
16b) -Boolean evaluation of non-boolean data is strict: 0, "" and [] are all evaluated to true.
http://en.wikipedia.org/wiki/Ruby_Programming_Language
.
17)
Ruby still lacks a specification, the current C implementation being the de facto reference specification.
^ Ruby License (ruby-lang.org)
Example Ruby 2:
New local variable scope rules
http://www.rubyist.net/~matz/slides/rc2003/mgp00012.html
18) Not installed by default in IIS or other hosting services. (But who said we will use IIS !)
19) Performance was slower than other industrial strength products. With newer compilers and virtual machines this may not be as much an issue.
20) I trust that Ruby deals with immutable string literals such as a="abc" when concatenated with the + operator. Otherwise a StringBuilder() class is needed for similar reasons that .NET has one.
- I.L.
Monday, January 28, 2008
Subscribe to:
Posts (Atom)