Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

packages vs. classes

0 views
Skip to first unread message

Chip Salzenberg

unread,
May 18, 2006, 6:17:36 PM5/18/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Thu, May 18, 2006 at 02:52:53PM -0700, Chip Salzenberg wrote:
> { copied to P6L for the "use case" question below }
Well, that message wasn't, but this one is...

What's the relationship in perl6 between namespaces and classes?
For example, given:

package Foo { sub bar {...} }
class Corge { method grault {...} }

Is the full name of foo "&Foo::foo"? What's the full name of grault?
Is there a common role that Foo and Corge both do?
--
Chip Salzenberg <ch...@pobox.com>

Larry Wall

unread,
May 19, 2006, 3:35:11 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Thu, May 18, 2006 at 03:17:36PM -0700, Chip Salzenberg wrote:
: What's the relationship in perl6 between namespaces and classes?

Hmm, well, that's hard to put one's finger on, but to the first
approximation namespaces are for declarational names, while classes
can really only name things operationally. So packages, modules,
classes, roles, subsets, enums, etc. all pretend they are packages
for purposes of naming from a global root. Any extra semantics are
defined by the objects that support each type of declarator. But
as container objects they all support the Package role, or some such.

The situation is analogous to the filesystem. We have a /proc
filesystem nowadays because it's convenient to name certain
abstractions in the OS as if they were ordinary files despite most
of the actual magic being defined elsewhere. It would be possible
to access classes et al. only via the mechanisms supplied by the
metaobject protocols, but that would be kind of like the bad old
days when ps(1) had to rummage around in /dev/kmem to figure out what
to say.

: For example, given:


:
: package Foo { sub bar {...} }
: class Corge { method grault {...} }
:
: Is the full name of foo "&Foo::foo"?

Yes, assuming that Foo is a top-level package name, and that you meant "bar".

: What's the full name of grault?

Just as if the class were a package:

&Corge::grault

Though nowadays for clarity we often write these as

Foo::<&bar>
Corge::<&grault>

instead.

: Is there a common role that Foo and Corge both do?

As bare names they can be taken in context to mean either the package
or the type. When necessary we can disambiguate these:

Foo.^{$x} call .{$x} on the type metaobject
Foo::{$x} call .{$x} on the package object

Contextually, though, a bare package name is generally taken to be a pun on
the type unless followed by ::. So

my Corge $foo;

is not really saying much about the Corge package except that there has
to be one, and to the extent that the Corge type supports certain methods
at declaration time, those names appear to be in the Corge package.
It's quite possible that the Corge type has metamethods that let us
get at unnameable behavior, but that would generally be construed as
violating encapsulation--hopefully for a good reason--but the public
interface of a type should generally be presented declarationally
via packages and the objects they contain.

A consequence of all this is that when you use any type declarator:

module M ...
class C ...
role R ...
subset S ...
enum E ...

the name is referring to both the package and the type simultaneously,
and the type is allowed to present whatever public interface it likes,
generally via the package. It also presents an internal declarational
interface to the innards of the declarator, so that metamethods like
"has" and "does" and "is" are given meaning in your class declaration.
The type also presumably controls which traits make sense on various
declarations.

Interestingly, even the tag groups of module exports are done with
the package interface currently. The "is export (:DEFAULT)" trait
merely pokes the current name down into the ::DEFAULT subpackage of
the module, and it hopefully can become very efficient to import a
prepackaged set of symbols as a lump.

If this isn't answering what you were asking, please ask s'more,
and I'll try to reply when I'm not busy having a grandbaby.

Larry

Larry Wall

unread,
May 19, 2006, 3:53:29 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org
'Course, I left out everything about prototype objects there...

The name Foo also (in context) represents an uninitialized object of
the class in question. Any object, initialized or not, can get at
its type handlers by saying

Foo.meta
$foo.meta

and, in fact, the Foo.^bar syntax is just short for Foo.meta.bar.

The Foo object maybe therefore be used to reason about objects of
a class, but the Foo object itself is not the class. Foo.meta is
the real class object. Foo itself is just a Foo that hasn't been
defined yet. Foo.isa(Class) is false, because there's no Class
type in Perl 6 as far as Perl 6 is concerned. The type of metaobject
Foo.meta might be called "Class" if that's what the metaobject protocol
decides it should be, but Perl the Language doesn't care. If so,
then Foo.meta.isa(Class) would be true. But Foo.isa(Class) is still
false.

The purpose of all this is to support prototype-based programming as
well as class-based programming. Assuming either one or the other
(in the absence of appropriate declaration) is a kind of encapsulation
violation of the .meta interface.

Larry

Chip Salzenberg

unread,
May 19, 2006, 5:45:40 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Fri, May 19, 2006 at 12:35:11PM -0700, Larry Wall wrote:
> If this isn't answering what you were asking, please ask s'more,
> and I'll try to reply when I'm not busy having a grandbaby.

adCONGRATULATIONSvance :-)

> Packages, modules, classes, roles, subsets, enums, etc. all pretend they


> are packages for purposes of naming from a global root. Any extra
> semantics are defined by the objects that support each type of declarator.
> But as container objects they all support the Package role, or some such.

The above paragraph is about half of what I was asking. It contains a bit
of bad news: it imples that Parrot can't assume that each HLL only has one
namespace-ish class. But I think that particular guilletine blade was
already on its way down.

The other half:

Your distinction between the type object and the class object is more than a


little disturbing to the current design issues I'm facing. You write:

> Foo.^{$x} call .{$x} on the type metaobject
> Foo::{$x} call .{$x} on the package object

Two and a half questions and a proposal on that.

Q1: How do you disambiguate type from package in the Perl 6 namespace?
Given a class Foo::Bar, is Foo::<Bar::> the package and Foo::<Bar> the
type? Or what?

Q1.5: If I asked why the circumflex is in there, would I regret it?

Q2: What is the object reference relationship among Foo::, Foo::Bar the
type, and Foo::Bar:: ? (Where are the object reference arrows?)

Proposal:

In Parrotland, it seems at the moment that Parrot type objects might be best
implemented as specializations of Parrot namespace objects. Consider:

Defining a new class creates exactly one named object.
Aliasing (e.g. importing) a class requires exactly one namespace operation.
Removing a class requires deleting exactly one namespace entry.
There is no confusion as to which object is "the" class object.
There is no confusion as to what should be looked up where.

As something of a probing attack -- to provoke informative rebuttal -- I'd
like to propose that type objects should do Package. What say?
--
Chip Salzenberg <ch...@pobox.com>

Chip Salzenberg

unread,
May 19, 2006, 5:51:55 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Fri, May 19, 2006 at 12:53:29PM -0700, Larry Wall wrote:
> and, in fact, the Foo.^bar syntax is just short for Foo.meta.bar.

So, you anticipated my half-question.

> The type of metaobject Foo.meta might be called "Class" if that's what the
> metaobject protocol decides it should be, but Perl the Language doesn't
> care. If so, then Foo.meta.isa(Class) would be true. But Foo.isa(Class)
> is still false.

OK, in my previous message, you should apparently read "metaobject" for
"type object". But I think the questions still apply, as does the proposal
that all _metaobjects_ that currently are correlated with packages should
instead just _do_ Package.
--
Chip Salzenberg <ch...@pobox.com>

Chip Salzenberg

unread,
May 19, 2006, 6:25:43 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org

And again I must correct myself, the above doesn't make sense.

Based on what I'm seeing, the Perl 6 "type object" is the thing that claims
the primary name associated with a class. Foo::<Bar> is the type object.
The metaobject seems to be anonymous. And the package seems to be fairly
questionable... given how generic you want to be, the Perl 6 implmentation
probably can't assume that there is exactly one package associated with a
given type object, either directly or indirectly.
--
Chip Salzenberg <ch...@pobox.com>

Larry Wall

unread,
May 19, 2006, 8:05:02 PM5/19/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Fri, May 19, 2006 at 03:25:43PM -0700, Chip Salzenberg wrote:
: Based on what I'm seeing, the Perl 6 "type object" is the thing that claims

: the primary name associated with a class. Foo::<Bar> is the type object.
: The metaobject seems to be anonymous. And the package seems to be fairly
: questionable... given how generic you want to be, the Perl 6 implmentation
: probably can't assume that there is exactly one package associated with a
: given type object, either directly or indirectly.

I think the only constraint on it is that Foo::<Bar>.meta can't
point to two different objects. But .meta isn't a real method--it's
more like a notation representing the "blessing", in P5 terms.
Certainly different packages could share the same .meta object if
the particular kind of metaobject it points to chooses to store all
the state in the package rather than the metaobject. In that sense
the package is just a handy place to put publicly named class state.

Going the other way, $object.meta makes no guarantees that the
metaobject it points to has any name. Could be completely anonymous,
or an eigenclass, or whatever. Presumably metaobjects that are
associated with a package can tell you that name somehow, perhaps
even by stringification. But which operations can succeed through
.meta will depend on what .meta.isa, as it were. In this, Perl is so
OO that it even encapsulates the OO, so Perl is agnostic even about
the extent to which Perl is an OO language.

In Perl 6, all objects are blessed equally, but some objects are
blessed more equally than others...

So what's in a name? One could say that .meta is functioning more like
a name sigil than like a method, and the Real Name of the metaobject is
Foo::<^Bar> or some such, if it needs a name. Then maybe Foo::<Bar>
is just a strange hash. Or maybe it has its own sigil. But from the
viewpoint of Dorothy the programmer, it's the package that presents the
public interface Oz::<Wizard>, and it's the metaobject that's trying
to hide behind the metacurtain. And as in the original, sometimes the
official story needs a bit of tweaking. But for now the Package of Oz
is great and glorious, and doubtless you should be quaking in fear. :)

All that and several bucks'll get you a Starbucks...

Larry

Chip Salzenberg

unread,
May 20, 2006, 4:22:21 PM5/20/06
to perl6-l...@perl.org, perl6-i...@perl.org
On Fri, May 19, 2006 at 05:05:02PM -0700, Larry Wall wrote:
> So what's in a name? One could say that .meta is functioning more like a
> name sigil than like a method, and the Real Name of the metaobject is
> Foo::<^Bar> or some such, if it needs a name.

Method, I like. Stealth sigil, I don't like.

Generally, dependence on names for proper functioning of any programming
construct -- variable, classe, whatever -- is in my experience almost
invariably a design flaw, which ends up being rectified eventually (unless
the enclosing system dies first), sometimes at significant cost to the
thematic coherence of the system. For example, Perl 5 acquired references,
and made anonymous subroutines, arrays, and hashes convenient. Where the
language did not make something anonymous, modules came to the rescue (e.g.
IO::Handle). I don't have to tell _you_ how much of Perl 4 became either
vestigial or embarrasing in the transition, and how frustrating a _partial_
adaptation to anonymity became.

Similarly, while it's taken decades, Unix variants are finally coming around
to making most filesystem operations available on file descriptors rather
than only on names. (fchown, fchmod, flink, etc.)

So, if you want <arbitrary_expression>.meta to work, I think you should bite
the bullet and admit that it actually *is* a method, or attribute, or
anything else that's value-derived ... as long as it's not name-derived.
You can't sigilize a name that isn't there.

> Then maybe Foo::<Bar> is just a strange hash. Or maybe it has its own
> sigil. But from the viewpoint of Dorothy the programmer, it's the package
> that presents the public interface Oz::<Wizard>, and it's the metaobject
> that's trying to hide behind the metacurtain.

I think I don't understand you.
However, if I do understand you, I disagree.

Think through the use case of the entirely anonymous class -- the class
which is not only nameless in the end, but which never had a name to begin
with.

(I'm not very familiar with prototype-based programming, but if I have the
right inkling, anonymous prototype objects might even be the norm. But at
this point I've begun speculating; so if that's wrong, ignore it.)

Such an anonymous class, and objects of such a class, respond to named
methods, to be sure; but the class *itself* has no name, and never did.
Where do its methods live? Perhaps in a package, but of necessity that
package has no name. (If the package name was merely obscure as opposed to
nonexistent, it could not be garbage-collected when it was no longer in use,
as its parent would continue to refer to it.)

Furthermore, and perhaps most persuasively, I can easily imagine meta
objects that have no use for a package at all, or that require several
packages to respresent the partitioning of various subfunctions. Parrot's
classes may be such metaobjects soon, as the HLL developers clamor to have
the names introduced by the Parrot implementation completely segregated from
their own work areas.

Thus, choosing a _package_ as the owner of the primary entry point to a
class's data structures -- that is, in the common case, it's name -- makes
little sense to me.

-------------------------------------------------

At the risk of plowing ground that has already been sold to developers:

I would suggest that the type object in Perl 6 might well be the point of
entry for the suite of (type,meta,package). The relationships would work
like so:

type object --> meta object {e.g. Class} --> package {optional}
\-------> more packages? {possible}

Note that the package(s) is (are) optional. Some metaobjects won't need
them. For example, in Parrot, the metaobject for "namespace" doesn't point
to a "namespace" object, for chicken-and-egg reasons. OTOH, it's possible
for some metaobjects to need more than one.

Getting back to the common case: the default behavior of Class creation will
include creating names for the type object and the package object, and
perhaps also for the metaobject, e.g.:


Oz::<Wizard::> -------------------+
|
Oz::<Wizard> |
| |
v v
type object --> Class --> package
^
|
Oz::<^Wizard>? -------+


Details of this second diagram are for illustration purposes only, to show
that I'm not suggesting that everything be anonymous. My point is that the
type system should (must!) still work even if no such names are ever assigned.

I don't know the p6 lexical magic required to make it happen, but if the
Wizard type object is anonymous, it should still be possible to say

my <arbitrary_expression_returning_Wizard> $gandalf;

and similarly it should be possible to use arbitrary expressions for all
other type/meta operations including introspection, modification,
subclassing, etc.
--
Chip Salzenberg <ch...@pobox.com>

0 new messages