What makes a gem incompatible with JRuby? - ruby

I ran bundle install and to my surprise, most of the gems that ship with Rails 4 installed just fine. byebug was one that did not, but no big deal.
What makes a gem incompatible with JRuby exactly?

In this particular case, the gem is written as a C extension for YARV, so it works only with YARV, not any other Ruby implementation, including, but not limited to, JRuby, Rubinius, MagLev, MRuby, IronRuby, etc.
The sad part is: as far as I can see, it only uses public Ruby APIs, it doesn't actually use any private internal information of the YARV VM, so it could just as well have been written in portable Ruby.
In general, there are several reasons why a gem may work only on one particular Ruby implementation:
It uses some particular feature of the host platform that is not available to all Ruby implementations. For example, a gem written in Java which uses Java platform libraries, will most likely not work with YARV, only with JRuby.
It accesses private internal implementation details of a particular Ruby implementation. This is obvious, I think. What's not so obvious is that there is no portable C API even amongst C-based Ruby implementations. What is usually called the "Ruby C extension API" is really just YARV laying bare its internals. Both Rubinius and JRuby have put in an enormous amount of work developing emulation layers for YARV so that at least some C extensions work, but it's hard. For example: YARV's garbage collector is extremely simple, it never moves objects in memory. Many C extensions rely on that, but this is simply not true for modern GCs such as Rubinius's or the JVM's. YARV doesn't allow multiple Ruby threads to run at the same time, many C extensions rely on that, but this is not true for pretty much all other Ruby implementations. And so on … Plus, those emulation layers are slow. Really slow. It is perfectly possible for a gem that has been "re-written in C for performance" to run slower than its pure-Ruby counterpart on JRuby or Rubinius. (After all, Rubinius can, in some cases, already compete with C. E.g. the Hash class in Rubinius is written in Ruby, and performs comparable to YARV's Hash class which is written in C.)
It uses a Ruby feature that is missing from a particular implementation. For example, Refinements have been widely criticized for being un-implementable in implementations that perform aggressive optimization of method lookup (or more precisely: Refinements, the way they are currently specified, make it impossible to apply those optimizations). The designers of Refinements all happen to be YARV developers, where it doesn't matter, because YARV doesn't optimize method lookup anyway, but e.g. the JRuby developers have decided to simply not implement Refinements. (10 years ago, they did the same thing with continuations.) So, if a gem uses Refinements, it won't work on JRuby.
The Rubinius and JRuby developers have developed an FFI API that can be used to make C APIs available from Ruby in a manner that is portable across many Ruby implementations. Rubinius, JRuby, MacRuby, and (I believe) MagLev support FFI natively, and for YARV, there is a gem which adds FFI support to it. Gems that use the implementation-independent FFI API instead of the YARV API should work on pretty much all implementations. However, the FFI API doesn't give access to the implementation internals (obviously), so for some gems it is not usable. For example, there are gems which try to give you access to the source code of a Proc, that's highly implementation-specific (and may not even work, e.g. when you ahead-of-time compile to a Java .class file with jrubyc, the source code doesn't even exist at runtime), so there has to be a different version of that gem for every Ruby implementation.

Related

Why does truffleruby need C extensions?

Current status of truffleruby says:
TruffleRuby is progressing fast but is currently probably not ready for you to try running your full Ruby application on. Support for critical C extensions such as OpenSSL and Nokogiri is missing.
Why does truffleruby need C extensions? It's built on GraalVM which is built on top of the JVM, it is in fact a fork of JRuby:
TruffleRuby is a fork of JRuby, combining it with code from the Rubinius project, and also containing code from the standard implementation of Ruby, MRI.
Can't they use JRuby world gems instead of depending on their C variants?
EDIT link to the issue on github
Running C extensions is hard because the C extension API is just the entire internals of MRI exposed as a header file. You aren't programming against a clean API - you're programming against all the implementation details and internal design decisions of MRI.
JRuby's Java extensions have exactly the same problem! The JRuby Java extension API is just the entire internals of JRuby, and you aren't programming against an API, instead you're programming against all the implementations details and design decisions of JRuby.
We plan to eventually tackle both problems in the same way - which is to add another level of abstraction over the C or Java code using an interpreter which we can intercept and redirect when required, so that it believes it is running against MRI or JRuby internals, but really we redirect these to our internals.
We think C extensions are more important, so we're tackling those first. We haven't really started on Java extensions yet, but we have started the underlying interpreter for Java that we'll use.
This video explains all
https://youtu.be/YLtjkP9bD_U?t=1562
You have already gotten a good answer by the project lead himself, but I want to offer a different point of view:
Why does truffleruby need C extensions?
It doesn't need them. But they do exist and there is code out there which uses them, and it would sure be nice to be able to run that code.

Rubinius in RubySL

I use Ruby from a user level and really don't deal with the internals. I have know Rubinius as 'Ruby in Ruby' which I assumed was a generalization. Recently, I got an error with Rubinius in the RubySL (no, I don't have error msg).
I started looking at RubySL and was a little surprised to see Rubinius everywhere. I really like Ruby and was just curious why Rubinius is in most of the RubySL? It seems to be used with things like locks / unlocks (such as https://github.com/rubysl/rubysl-thread/blob/2.0/lib/rubysl/thread/thread.rb ). Definitely not questioning it, just curious.
RubySL is short for Ruby Standard Library. It is a basic part of the shipped code bundle which forms what is generally known as Ruby. The standards library provides rather basic stuff you often need but which doesn't need to be part of the core language.
For example, the implementation of the Hash or Array, the language keywords, how assignment works, ... are part of the core language. These are often implemented in a language other than Ruby. MRI (the common C-Ruby) implements this mostly in C, JRuby implements this in Java. Rubinius implements this patly in C++ but mostly in Ruby itself. It can do this by bootstrapping itself from a very simple base VM and gradually adding more stuff with Ruby.
The standards library however is mostly implemented in Ruby in all implementations (with some exceptions mostly for performance reasons). Now, all Ruby implementations right now have their own implementation of the Ruby standards library which can thus differ in minor details.
Rubinius' approach to implementing a standards library was to implement it as separate gems. The idea was to one day provide a common standards library which could be used by other implementations (including MRI). This is in line with the efforts of esp. the Rubinius community to drive the RubySpec project in order to provide a common language specification and test suite for all Ruby implementations.
The RubySpec project was eventually abandoned and right now, it doesn't seem as if other Ruby implementations seem to be moving to the RubySL gems for implementing their standards library.
Thus, (and this is the TL;DR), the RubySL gems implement the Ruby Standard Library for the Rubinius project. Thus, it is expected to see the Rubinius project all over the place there: it is their code which is generally not used by other Ruby implementations.

jRuby and Rubinius support parallel computing, but what about gems that don't support this?

What I'm trying to understand is, practically speaking, how much benefit do I get from the parallel computing support in jRuby / Rubinius? A lot of ruby libraries keep track of global internal state. Is there any way to deal with these libraries, or do they just become unusable if I decide to parallelize my Ruby script? Maybe Rubinius automatically puts a mutex in front of all usage of unsafe libraries?
Whenever you want to use jruby or rubinius, you'll be forced to use gems that are compatible.
Many gems has been implemented using C extensions and you can not use them along jruby e.g.
Regarding others, mostly they clearly states their thread safety status.
So choosing jruby or rubinius will narrow down your options regarding the gems.
but a huge opportunity will be exposed, you'd be able to use many mature Java Libraries(in jruby case).

Use JRuby for Ruby web applications? Is it worth it?

Background: I'm writing a 'standard' (nothing special) web application in Ruby (not Rails) and I need to start thinking about deployment.
So I've been hearing a lot of recommendations to use JRuby to deploy Ruby web applications, regardless of whether you actually need Java libraries or not. How true is this? Is it worth using the Java implementation just for speed? Would I gain anything else by doing so? Would I run into any issues?
PS: I don't know Java that well, so "you can write parts of it in Java" isn't very helpful.
JRuby is one of the most complete ruby implementations (there are a lot other ones out there such as IronRuby, Maglev, Rubinius, XRuby, YARV, MacRuby). It is very comprehensive, therefore, unless you use gems that use native C code, you will very very likely be just fine compatibility-wise.
JRuby is a bit faster than the actual C implementation, but it supports actual threads, whereas the official implementation is struggling a bit into getting it (it still uses Green Threads). Using Java threads from JRuby is quite trivial, even though it will require you to couple your code with Java (with a little DI, this coupling will only happen once, though).
Another benefit: runtime tools. Java, as a platform, instead of a language, has a lot of runtime tools to help you diagnose problems and check the state of the application (profilers, JConsole, and so on).
Twitter engineers also mentioned that the Ruby VM kinda has trouble being an environment for long lived processes, while the JVM is very good at that, because it’s been optimized for that over the last ten years.
Ruby also had a little security issue recently, which did not affect JRuby's implementation.
On the other hand, your project requires more artifacts (JVM, JRuby jars, etc). If you are using an application that will stay alive for long, and you want better runtime support, JRuby can be a great way to go. Otherwise, you can safely wait until you need these things to actually make the move (it is likely to go smoothly).
I use and love JRuby on daily basis, but I suggest you use MRI (a.k.a. C-Ruby) unless you have a actual need for JRuby.
Reasons for using JRuby:
Java integration
Restricted environment (your machine has Java installed by not ruby and you don't have root)
Restricted environment (you have ruby installed but don't have root so can't install gems you need)
You reached the limits of Ruby 1.8 performance and cannot use 1.9
From what you've described, you don't have any of the above reasons.
C-Ruby 1.9 has significant performance improvements over C-Ruby 1.8. I've yet to read (or find out for myself) how C-Ruby 1.9 compares with JRuby 1.8 or JRuby 1.9. In anycase, you don't have a performance problem (yet) so don't worry about it.
The good news is, you can start with either and convert later if needs be. It's all Ruby, and the Webrick and Mongrel gems work with both.
As mentioned above, ruby gems that have C extensions cannot be installed under JRuby. Hopefully this will change in the future if ruby C extensions utilize FFI.
http://kenai.com/projects/ruby-ffi/pages/Home
http://isitjruby.com/

Differences between Ruby VMs

What are the advantages/disadvantages of the major Ruby VMs (things like features, compatibility, performance, and quirks?) I know there are also some bonus features like being able to use Java interfaces through JRuby, too. Those would also be helpful to note. Does any VM have a clear advantage at this point, and in what contexts?
I've used both Matz's Ruby and JRuby, and they solve different tasks. If you are developing a straight Ruby or Rails app, then that will probably suffice, but if there are some powerful Java libraries that would help a lot, then JRuby might be worthwhile.
I haven't done anything overly complicated, but JRuby seemed to match up pretty well, at least as far as implementing the core language features (I haven't run into any differences yet, but they may exist).
One little anecdote I wish to share... I was writing a script to interact with a DB2 database. The DB2 support in Ruby is abysmal... you have to install the whole DB2 express version just to be able to compile the Ruby drivers, which didn't even work for me. I got fed up and switched to JRuby, using JDBC and a few small DB2 JDBC jars. It resolved my problem perfectly. The point? Well, if gaining access to some Java libraries will simplify the problem at hand, by all means go for it!
I hope this was helpful! Sorry I don't have any experience with other VMs....
One more caveat I have read about, but I don't know the details too well... JRuby I think supports threading via Java threads, instead of the "green" threads supported in Matz's implementation... so if you want multithreading on multicore systems, JRuby will probably serve you better... unless you want to do the threading in C.
Here's a bit of info I scrounged up on the main VMs: Ruby MRI, Ruby 1.9 (YARV), JRuby, XRuby, Rubinius, and IronRuby
There was a performance benchmark last year that compared the major VMs, but with how quickly VM development has been it probably is not as relevant today. Ruby 1.9 was generally the fastest, and still has the edge over JRuby for now, I believe.
Four VMs are currently capable of running Ruby on Rails: Ruby MRI, Ruby 1.9, JRuby, and Rubinius.
XRuby runs on the JVM, as does JRuby, and compiles the Ruby source files to a Java .class.
IronRuby runs on .NET, making use of their DLR, and allows you to integrate Ruby with the .NET libraries and infrastructure. It cannot yet run Ruby on Rails.
There is also a VM called HotRuby that lets you run Ruby source code in the browser or in Flash.

Resources