Re: Globals and singletons

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Re: Globals and singletons

Rob Lanphier
Hi Tim,

I wholeheartedly endorse the idea of removing gratuitous globals, even
if I'm only agreeing from the peanut gallery.  Hopefully my response
will spur some conversation from folks that you were probably hoping to
hear from more than me.

It's probably not worth doing in one swell foop, but an agreement on a
direction combined with an incremental approach where cleanup is done as
a part of fixing issues (like you are doing now with $wgLinkCache) seems
like the smart way to go.

More inline:

On Thu, 2006-01-05 at 12:20 +1100, Tim Starling wrote:
> In many cases, use of globals obscures data flow and makes classes less
> flexible, inhibiting reuse. This is patently true in the case of $wgTitle
> and $wgArticle, the existence of which encourage lazy programmers to write
> code which fails in the common case where more than one of these objects
> exist.  At present, these two objects are almost exclusively used in the
> output phase, so it would make sense to make them members of OutputPage or
> Skin instead of globals.

I'm not sure much reuse is gained by replacing $wgTitle with
$wgSkin->mTitle or even $wgSkin->getTitle().  It's just a global with a
bigger name.

That said, I agree with the sentiment. The more that developers can be
encouraged to write code that relies on "a Title object" as opposed to
"the Title object", the better.

> The most extreme anti-global architecture would be one involving application
> objects:
> $mw = new MediaWiki;
> $mw->executeWebRequest();
> The application object could theoretically be passed to most class
> constructors, providing a form of global context. That, however, would make
> writing new classes a bit tedious. In my experience, it turns out to be
> easier to make the application object a global, and pull it in wherever it
> is needed. This would have advantages when MediaWiki needs to be embedded as
> a library, since it keeps the global scope cleaner, but it's not really more
> flexible than what we're doing now.

I disagree.  If that level of embedding were possible, I think a lot of
unanticipated reuse would fall out from it.  A good example of where
(possibly) unanticipated reuse happened on a big scale is when Gtk
became an independent project from the Gimp.  There are chunks of the
MediaWiki codebase that probably don't need to be married to MediaWiki.

I started thinking about these issues in building Electowidget.  In the
end, I created a light abstraction layer around some MediaWiki services
(the "HostApplicationObject") which made it possible for me to port my
app to other frameworks.

It hasn't proven itself yet.  I've created a minimal standalone object,
and there's a developer who is working on a version for Drupal, so we'll
see how it goes.

The ideal situation for me and other plugin writers would be that
MediaWiki uses a type of hostapp object in its "native" code, such that
other apps could share that same hostapp implementation (or at least
share an API).

> After some thinking, I was forced to admit that there are some cases where
> globals make sense, from a data flow perspective. The clearest example is
> caching. A cache should have the widest possible scope. If you have two
> application objects, you would want them to share the same caches if
> possible. Indeed, it's better if different threads, processes and even
> servers can share their caches.
> There are, however, disadvantages to using global variables for this or any
> other similar purpose. The problem is that the use of global variables
> inhibit lazy initialisation. The familiar solution is to use an accessor
> function, and indeed this approach has already been implemented in several
> places in MediaWiki. I would like to make such accessor functions more
> pervasive.
> There is also the problem that the global namespace is somewhat crowded.
> Using a global function for an accessor just moves this problem to somewhere
> else.

>  The alternative [to global accessor functions] is to use a static
> class member as an accessor. This concept is well known, and where the
> static object is the only one ever needed, the object is called a
> singleton.

> The disadvantage to the singleton pattern is that it requires the class name
> to be hard-coded throughout the code base, removing some flexibility. We
> could get around that by having base classes construct derived classes, if
> you don't mind the dependency implications.

This may be a good reason to use a global accessor function, like
wfGetDB to get the Database object.  The db code is effectively used as
a singleton (well, perhaps a "poolington" ;-), and seems to work alright
as an approach.

The nice thing about a global function is that you get slightly more
flexibility to rename/redesign the base class.  You can still use a
static variable rather than a global to actually store the object
instance.  The downside is that it's a little less standard; it's nice
for a programmer new to the codebase to see "singleton" right off the
bat rather than need to figure out that they're dealing with something
that's roughly like a singleton.  As far as the global function
namespace being too crowded, one could easily create a generic class
factory if a hierarchy is absolutely required.

> We need to be guided by our applications, and choose the simplest
> architecture which supports all of them. Are we interested in:
> * Embedding? Need to avoid namespace pollution.
> * Per-wiki daemons to do background tasks? Need a means for periodically
> refreshing configuration and caches.
> * A daemon that responds to requests for multiple wikis? Needs multiple
> language objects, and a caching system which discriminates between different
> wikis.

These all seem like interesting apps, and I don't think the needs of any
of them are mutually exclusive.  Of course, this conversation is always
amusing, and seems apropos: I also agree that any grand generalization work needs to be app
driven.  My 2c would be prioritize and order the work based on immediate
demand (e.g. sounds like the daemon for multiple wikis is what you're
most interested in), but at least think about all of the apps above as
you/we/others are doing the work.


Wikitech-l mailing list
[hidden email]