From: David Masover Date: 2011-01-15T13:26:15+09:00 Subject: Re: [poll] What are your ruby rough cuts ? On Friday, January 14, 2011 07:34:04 am Jonas Pfenniger (zimbatm) wrote: > 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.