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

Reply via email to