this is a general census to get developer feedback. Please post the
issues you encounter when developing in ruby. This can range from
syntax issues, to library support, documentation, or anything that is
a roadblock when developing in ruby.
In no particular order...
I wrote a long post because I don't have time to write a short one. To
summarize:
RubyGems:
- Play nice with other package managers
- Better installers for end-users
- gems/rvm/bundler confusion
Library management:
- Better namespacing
- Better handling of monkeypatching
Multithreading:
- Threads are too primitive
- Actors would be cool, but have issues
Wish list:
- Lisp-style Macros.
- Ruby-in-Javascript.
And now the rant:
Right now, Rubygems is both the biggest win and the biggest blocker for
newbies. I haven't been keeping track, so I find I now have to learn RVM and
Bundler just to keep up with the best practices for deploying a Rails app. And
how do these interact with the system Ruby? If I install a system package that
depends on a particular version of Ruby, will it get the version it expects,
or will it get my default RVM version?
Unfortunately, I don't have a good answer for this, and I don't really know
much about the solutions that do exist, but nearly every one I've tried has
been very messy in many ways. Installing gems to my home directory is just not
a good idea.
Another thing that I'd like to see more work on -- though I think alright
solutions exist, especially for JRuby -- is the ability to distribute Ruby
clients. It seems like there are two solutions, one for developers, and one
for end-users. The developer solution is to build it as a gem, but it's not
reasonable to ask an end-user to install Ruby, Rubygems, and then your gem.
The end-user solution is to build it as a giant monolithic file which includes
all relevant gems. Surely there's a middle ground -- a nice, intuitive
installer, but one which actually sets up a system Ruby and Rubygems for the
user, so that multiple programs don't have to separately download and install
the same libraries.
And Rubygems itself -- while it seems it's capable of understanding reverse
dependencies, I want to be able to automatically clean stuff that I don't need
anymore. Gemfiles are kind of a decent start, but I'm thinking something along
the lines of "manual" vs "automatic" in Debian, or even better, Gentoo's
/var/lib/portage/world. In particular, I want to be able to install a gem just
to see what it does, and if I don't like it, uninstall that gem and then clean
up every gem that was only installed because it was depended on.
RVM's gemsets are kind of cool, but they seem to be a workaround for not
having that functionality. The only other reason to have them seems to be when
developing a gem.
One more thing about gems: How do we know what a good gem is? I love how
decentralized it is now, at least in theory, but occasionally it means I need
to go through two or three gems and try each of them before I find either that
none of them does what I want, or some oddly named and maybe semi-obscure gem
is perfect.
Moving away from rubygems and installation, and to semantics...
A bit more namespacing would be awesome. The current practice of just dumping
something you hope is appropriate into the global namespace of constants is
bad enough. It's worse when we start monkey-patching other stuff.
I don't know how big a problem this actually is. It doesn't seem to actually
cause problems in practice, so maybe I'm overreacting. Still, I like how Perl
and Python handle this, where there's a difference between loading a library
and importing it into your namespace.
Namespacing constants aggressively shouldn't be too much of a burden, as Ruby
has the same shortcuts JavaScript does. Take JRuby. Sure, you can do this:
import java.util.PriorityQueue
But you can also do this:
pq = java.util.PriorityQueue
That's locally-scoped, which means you aren't polluting any namespace past the
end of the current block. Or you could do something like:
module MyMod
PQ = java.util.PriorityQueue
...
end
In both of these cases, you aren't affecting anything else in the same
runtime. But if you 'import' it globally, you've declared it, well, globally.
Point is, I don't think we should be afraid to do stuff like this, though we
could use just a bit of sugar to make it easier:
module FooCo
module LibFooVersion213
class Foo
...
end
end
end
Ok, yes, people will get sick of typing that, but again:
foo = FooCo::LibFooVersion213::Foo
Problem solved.
Monkey-patching is harder. Is there a way we can scope things like
Activesupport's hacks? Stuff like:
'bird'.pluralize
5.days.ago
foo.should be_valid
I love these things, but I wish there was a way I could declare them to be
only available in a certain context or scope. This seems like it needs some
language support to be really effective -- we could fake it now by mixing them
in and out of the core classes as needed, but that would affect any other
threads, so it kind of defeats the purpose if you're using multithreading.
Essentially, the idea here is that when multiple libraries inevitably end up
using the same name for something, we should be able to work around it. When
they don't, we don't want it to be a burden. (I think JQuery is a perfect
example of this done right.)
Let's get some proper multithreading, to start with. It's 2011. There is
really no excuse for a GIL. Either drop it or mainstream COW GC -- otherwise,
JRuby becomes the only real option for multicore on Ruby.
How about some higher-level threading constructs, too. There are a few gems
which add interesting ideas... However, there are limits to what you can do
with Ruby as it is, and these are partly due to the fact that it's not Erlang.
Again, I'm not sure of the best way to do this, but...
We have objects, and objects can, in principle, completely encapsulate their
state. We've actually got that implemented properly -- just look at send,
method_missing, the fact that we _need_ accessors, etc. This would be a
perfect fit for the actor model, and it's something I tried to do once, but
never really finished -- but essentially, why not "just" make all Ruby objects
actors?
Aside from performance issues, but I was going to do a proof-of-concept and
ignore those...
Well, I didn't quite finish it, but one problem I ran into in the design phase
is the fact that there's entirely too much Ruby code which wouldn't work at
all with this kind of design. For example:
foo.a += 1
Sure, you can override foo.a and foo.a= and either add a giant mutex, or push
them off to a separate thread. Either way, you're still going to have a race
condition between getting the value of a and setting it again. Something like
this might work:
foo.increment! :a
If you were to view each object as an actor, and each method call as a
message, stuff like that works very, very well. I still want to finish my
idea, because I think you could get a lot of mileage out of new objects which
were designed from the start to be actors. I think you could do that without a
lot of language overhead. I had a proof-of-concept partly done.
But that still doesn't change the fact that this will never work:
foo.some_hash[:a] += 1
Even after you make sure foo is an actor, and the some_hash it returns is some
sort of proxy object that serializes all access, you still have the race
condition between the call to [] and the call to []=.
I think that this kind of problem is exactly the kind of thing Ruby should be
concerned with. The typical Ruby battle cry has been "Hardware is cheaper than
programmers!" Well, alright, here's a machine with a few thousand cores. How
is Ruby going to handle that? Can the language itself be fixed, or does there
need to be a new one that combines the best of Ruby with the best of (say)
Erlang? (In other words, is something like Reia the way forward?)
I don't know, but while it's sort of workable now, it's probably _the_ single
language flaw that keeps me up at night.
There is one other that just annoys the purist in me...
Is there any way we can get anything like Lisp sexps? As I understand it, we
have a few Ruby parsers, but nothing standardized to the point where I can ask
the runtime itself to give me a parse tree for a given expression. The closest
I could find was various implementation-specific things and ruby_parser, which
is cool but buggy, missing a few of the 1.9 features.
But that I can live without. My rationale is, pretty much any syntactic
ugliness can be worked around with a preprocessor if it's _really_ bugging me
(see lazibi), and Ruby is pretty anyway. It's semantic ugliness that's tricky.
Ruby doesn't have GOTO, it doesn't have pointers or malloc, it's done away
with pretty much every bit of low-level nastiness associated with single-
threaded programming -- but the Thread system makes me feel like I'm in C
again, where the slightest mental mistake could lead to my entire program
screwing up in unimaginably arcane ways.
A final point: Browsers are getting fast enough that we should be able to do
Ruby in Javascript. And not a server-side implementation, either -- I want the
equivalent of JRuby. But this isn't really a limitation of Ruby, it's a
limitation of browsers that we'd be working around. The above rants are things
I actually feel are broken about Ruby as it is today.