As a follow up to my last post on the "pain that is main", I want to offer a potential imporvement for Ruby 2.0. I approached the topic on ruby-talk this week and while Matz initially took some interest, we hasn't followed up since his last comment.
trans: Sure thing. It seems natural to me that "main" would a module of the form:
module Main extend self end
Such a module provides all the characteristics of the toplevel --def, include, etc.
matz: Why? If it is really required it's fairly easy to add toplevel methods like we did for #include.
But it isn't easy. In order get my Taskable module to work, for instance, I had to build in exceptions for the toplevel case, which is far from ideal and is fragile [Ed- in fact I'm still getting bugs that I haven't yet pinned down]. These subtile difficulties arise becuase main acts as a partial proxy for the Object class. Anyone who's developed proxies before knows the subtile issues that can come into play. In this case, only the bare minimal interface is even supported. Yet, even if we went to all the trouble to add the missing proxy methods, we still wouldn't get past all the woes. The Object class and main are still fundamentally two distinct objects --self is not the same, nor is their singleton classes.
So in effect Ruby is schizophrenic. You can't create a DSL for Object to be used in main and you can create a DSL in main to be used in Object. Hence the devolution to DRYless code.
There is a potentially elegant solution however, and I'd really like to understand others insights into this (esspecially Matz' of course). Instead of main being a special proxy object, just let it be a self extended module.
module Main extend self # programs are written as if in here end
This would provide all the facilities required of the toplevel without all the proxy troubles. Accordingly, I'm not so convinced of the merits of every toplevel method becoming a private method of all objects. And in this proposal that's easily prevented. OTOH, it has proven workable in practice so it's not a signifficant factor of consideration here. Main can simply be include in Object to achieve that effect.
class Object include Main end
But when we do that it becomes very clear what Main appears to be: Kernel. That strikes me as esspecially interesting. Of course, there may be good reasons to keep the Kernel as a separate module, in which case we'd just have a class hierachy:
Object.ancestors => [Object, Main, Kernel]
Nevertheless, it is clear the Kernel could just as well serve as the toplevel object, which, IMHO, makes this a very elegant proposition to consider. Perhaps I'll start a campaign as elections roll around: "Vote Kernel for Toplevel Object!"