On Wed, Jul 06, 2005 at 11:47:47PM +0100, Piers Cawley wrote: : Or you could use a global, but globals are bad...
Globals are bad only if you use them to hold non-global values. In this case it seems as though you're just going through contortions to hide the fact that you're trying to do something naturally global. You might argue that a singleton object lets you hide the implementation of the delegation from the world, but there's really not much to implement if you just want to tell the world that whenever the world says "LOGGER" the world is really delegating to "LOGGER::DBI". Plus if you really need to reimplement you just vector the world through "LOGGER::SELECTOR" or some such. One nice thing about a variable is that you're guaranteed to be able to temporize it: temp $*LOGGER = pick_a_logger(); On the other hand, there's no reason a role can't play with a global variable, and arbitrate the use of the global among all the classes that want to delegate through the global. But a role is not allowed to function as its own singleton object, because roles don't define objects. On the gripping hand, the package holding the role's namespace is a perfectly fine spot for such singular information. Every named package/module/class/role/subtype is a kind of global singleton hash of the symbol table persuasion. But if globals are inherently bad, we should remove them from Perl 6. Hmm, this raises the question of whether a role-private "class" variable actually belongs in the class's or in the role's namespace: role Baz { our $:x; } FooBar does Baz; BarFoo does Baz; Does $:x end up being a "private" global in the Baz package or a global shared between the FooBar and BarFoo packages? That kinda goes along with the question of whether attributes in general belong more to the role or the class into which the role is composed. It seems like all those cases can be useful, so maybe we need a syntax to distinguish role attributes from class attributes. To think of it another way, which delarations are to be taken literally, and which generically? And which way should be the default? For this particular use, you want some semantics resembling: role LOGGER { role:our $:logger handles Any; role:submethod BUILD ($logger) { fail "Logger already set" if defined $:logger; $:logger = $logger; } ... Not necessarily recommending that syntax, of course. Could just default declarators to class semantics and force role declaratoins to be explicit: role LOGGER { our $:LOGGER::logger handles Any; submethod LOGGER::BUILD ($logger) { fail "Logger already set" if defined $:logger; $:logger = $logger; } ... But that seems a bit klunky, especially given the way package names and twigils interact. And don't even think about using $?ROLE there. Plus we've never let you use "our" on a qualified name before. This really seems to be somewhat orthogonal to everything else, so maybe we need some orthogonal syntax: role LOGGER { mumble our $:logger handles Any; mumble submethod BUILD ($logger) { fail "Logger already set" if defined $:logger; $:logger = $logger; } ... for some value of "mumble" that implies "non-generic". Need to think about this some more. I *don't* think it's viable to make non-generic the default unless we do it only for variables. But then you'd be forced to write our &BUILD ::= submethod ($logger) {...} to get a non-generic BUILD submethod, and that's more than a bit ugly. So I'm still mumbling... Larry