From: jcb@... (MetalOne) Date: 2003-08-28T07:12:38+09:00 Subject: Re: Why would you abandon Ruby? (was) First off, I would like to say that Ruby is the simplest language to learn. Not just the language, but the libraries too. You could have learned Ruby in less time than has been spent debating it's merits on this forum. More to your question though. Ruby has some areas that it is extremely good at, and some it is not so good at. Ruby's execution speed is much slower than "C". Depending upon the task maybe 300 times slower. You can't do video processing at 30 fps in Ruby. It is more like 1 frame in 30 seconds. Ruby's speed though is about the same as other interpreted dynamically typed languages. Many tasks will be outside the scope of Ruby's built in library, and you will need bindings to "C" libraries. For example you might desire a binding to the Win32 API. There is a partial binding available, but it does not cover all 90,000 API calls. This is a problem with every language in existence except "C" and C++. I believe the lack of such bindings and the lack of documentation for such bindings is one of the main reasons "C" and C++ continue to live on. Plus "C" and C++ do not make many comprises when it comes to execution speed. I wanted to write a Publish & Subscribe server in Ruby. I discovered that Ruby does not have asyncronous socket support under Win32. So, I wrote it in Python. Python has a really great asyncronous socket interface. This turned out to be slower than I had hoped, however. After experimenting some in "C", I found it to be at least 300 times slower. I did not want a slow Pub/Sub server. I suspect most people do not want slow libraries. Thus, most libraries are going to be written in "C". Ruby will always require bindings to these libraries. I since discovered that cross platform socket libraries are not easy. Most of these use Win32s copy of the unix calls, select/read/write. This turns out not to be nearly the best method on Win32. On Win32 you want to use Overlapped I/O and Completion Ports. This is so different from the Unix way that I don't think a common interface can be created. All languages that I am aware of that have socket support built into them, attempt to have cross platform support, and they attempt to do it by mirroring the Unix API on Win32, which is just not efficient on Win32. The Win32 method is more efficient than the Unix method besides. Ruby does not have a binding yet to WxWindows (A cross platform GUI). One is in the works. Python has a binding to WxWindows. However, you have to read C++ documentation to know how to use it. A less than optimal solution. I believe the binding to be a partial one with no documentation stating where it is incomplete. Ruby has a partial binding to the Win32 GUIs, documented in Japanese. As it turns out, I am beginning to think the notion of a cross-platform GUI is flawed to begin with. At least it is not optimal. It may be satisfactory for some types of work. I want a language that is as fast as "C" or nearly so, that has a great GUI library and a great socket library that runs on Win32, Linux, FreeBSD, and OS/X. I want the language to be as easy to program in as Ruby. Such a language does not exist and I have looked hard. I think "C" and "C++" are used so much because every other language has flaws when it comes to speed or library support. Other possible alternatives are LISP/Haskell/Ocaml. Ocaml is one of the faster languages. It is sometimes only 2 times slower than "C". For me, that factor of 2 is enough to kill it for almost all tasks. And if the factor of 2 does not matter, then a factor of 300 might not either and Ruby comes back into play. Ocaml is hard to learn. Ocaml has a big sandbox of tools. It is on my list of things to learn better. Haskell has a cleaner syntax than Ocaml. Haskell implementations are not very fast yet. Haskell is maybe 4 to 20 times slower than "C". Haskell lacks library support. Haskell is hard to create "C" bindings for. Haskell has some really cool features though. I tried to use quick sort with HUGS to sort 20,000 elements. It overflowed the stack. Recursive quick sort implementations also blew Ruby and Python's stack. Java handled it. LISP. I know for many people LISP is the world's greatest language. LISP essentially has no syntax. Some people think this is one of LISPs greatest features. I personally despise it, for this reason. LISP/Haskell/Ocaml all make a person think recursively to solve all problems. I don't think this is natural. It is natural for some problems, but not all. Java, C#, and Visual Basic all fall into the same category for me. Slower than "C", faster than Perl/Python/Ruby. Actually, I am not sure about VBs speed, but it can be compiled to native instructions so I am guessing here. They have a sandbox of tools. If you have to go outside the sandbox, life gets hard. I don't recommend Java for GUIs. C# and VB are Windows specific. All of these are easier to get work done than "C", but not as easy as Perl/Python/Ruby. Most all other languages are too experimental at this point. Well, those are the choices in a nutshell. So, it depends upon what you need to get done and if that task is doable in the sandbox of tools available to the language and if the speed requirements can be handled by the language. The "D" language looks interesting. It is very new though. I fear that if Walter Bright gets hit by a car or something the language will disappear. I just thought of one other observations. Typed languages vs. Dynamically typed languages. This is a religious war of course, but I just the wrote the following today in C++: _cb = auto_ptr >(new FunctorCB(this, &SndRcv::output)); Here _cb holds a reference to an object and a member function to be invoked on that object. This allows me to make a function callback into an object. It allows me to save a closure that I can execute later. FunctorCB looks like this: /** * @param T The type of the callback class * @param DATA The type of the argument passed to the callback function */ template class FunctorCB : public ICallback { public: typedef int (CB_OBJ::*PMF)(const DATA &data); FunctorCB(CB_OBJ *obj, PMF pf) { _obj = obj; _pf = pf; } int operator()(const DATA &data) { return (_obj->*_pf)(data); } private: CB_OBJ *_obj; PMF _pf; }; The above is extemely nasty, although it is efficient. Dynamically typed languages just don't have that ugliness. I mention this because both C# and Java are getting template support.