[Draft Proposal: Declaring Classwide Attributes]
Within a class, "classwide attributes" are declared using the standard
"my" and "our".
Example:
class Zap {
my %zap_cache; # a private classwide attribute
our $zap_count = 0; # a public classwide attribute
attr $foo;
attr $bar;
}
[Discussion]
Many OO-based languages have the concept of "classwide" attributes;
that is, attributes that only exist once, for the class (and all
subclasses?), as opposed to existing one for each instance of a class.
You can use these attributes as counters, or caches, or any other
common ground for use by all instances of the class.
Within a class definition, Perl simply uses the my/our keywords for
this purpose.
If any value is to be assigned to a "classwide" attributes, that
assignment is done once, upon initialization of the class.
[PROS]
- Obvious utility. No new syntax introduced.
[CONS]
- ?
[Related Issues, Known Implications]
- This hinges on our definitions of "private" and "public". "my" vs.
"our" may in fact mean "private" vs. "protected", or perhaps
"protected" vs. "public".
- What the heck does "initialization of the class" really mean? That
needs to be clearer.
MikeL
: Date: Fri, 4 Oct 2002 16:40:04 -0700
: From: Michael Lazzaro <mlaz...@cognitivity.com>
: To: perl6-l...@perl.org
: Subject: Draft Proposal: Declaring Classwide Attributes
:
: (Disclaimer: My purpose in proposing this is not to recommend it, but
: to document whether the idea should be endorsed, or shot down, and any
: proposed canonical syntax. Note that the later implications of these
: choices are quite substantial. Please discuss!)
:
: [Draft Proposal: Declaring Classwide Attributes]
:
: Within a class, "classwide attributes" are declared using the standard
: "my" and "our".
:
: Example:
:
: class Zap {
: my %zap_cache; # a private classwide attribute
: our $zap_count = 0; # a public classwide attribute
:
: attr $foo;
: attr $bar;
: }
:
:
: [Discussion]
:
: Many OO-based languages have the concept of "classwide" attributes;
: that is, attributes that only exist once, for the class (and all
: subclasses?), as opposed to existing one for each instance of a class.
: You can use these attributes as counters, or caches, or any other
: common ground for use by all instances of the class.
:
: Within a class definition, Perl simply uses the my/our keywords for
: this purpose.
:
: If any value is to be assigned to a "classwide" attributes, that
: assignment is done once, upon initialization of the class.
If you want accessor methods, use the dot:
class Zap {
my %.zap_cache; # a private classwide attribute
our $.zap_count = 0; # a public classwide attribute
has $.foo;
has $.bar;
}
It may be that $.zap_count is public not so much because of the class definition
where it would default to private, but because $.zap_count's real global name is
$Zap::.zap_count. To get a public accessor method you might still need to declare
it public. And you could get a public accessor method to the "my" variable as well
the same way. (That means is that the {...} of the class definition is really just
a closure that executes once when the class is built.)
Larry
Anyhow, what was deemed wrong with using my/our?
And...
> class Zap {
> my %.zap_cache; # a private classwide attribute
> our $.zap_count = 0; # a public classwide attribute
>
> has $.foo;
> has $.bar;
> }
>
> It may be that $.zap_count is public not so much because of the class
definition
> where it would default to private, but because $.zap_count's real
global name is
> $Zap::.zap_count. To get a public accessor method you might still
need to declare
> it public. And you could get a public accessor method to the "my"
variable as well
> the same way.
So:
class Zap {
my %zap_cache; # var, lexical
my %.zap_cache; # class attr, lexical
my %.zap_cache is public; # class attr, lexical/public
our $zap_count = 0; # var, lexical/global
our $.zap_count = 0; # class attr, lexical/global
our $.zap_count = 0 is public; # class attr, lexical/public/global
has $.foo; # instance attr, lexical
has $.bar is public; # instance attr, lexical/public
}
Yes?
What about something like:
my $.foo; # private instance attr
our $.foo; # public instance attr
my $foo; # as p5
our $foo; # as p5
MY $.foo; # private class attr
OUR $.foo; # public class attr
MY $foo; # invalid?
OUR $foo; # invalid?
method bar; # public instance method
my method bar; # private instance method
our method bar; # public instance method
MY method bar; # private class method
OUR method bar; # public class method
--
ralph
Nothing the matter with "our" for class attributes since they're
already stored in the package if we follow Perl 5's lead. But using
"my" for instance attributes is problematic if we allow a class to
be reopened:
class Blurfl {
my $.foo;
}
...
class Blurfl is continued {
print $.foo;
}
This violates the Perl 6 rule that "my" is always limited to a block.
That's why we came up with "attr", which has since mutated to "has".
: And...
No "yes" till Apo 12. :-)
And probably not "yes" then. These are all provisional notions.
Note that "attr" only lasted a month...but then, I said when I made
it up in Zurich that it was a placeholder because I couldn't think of
anything better. And the whole public/private thing is a placeholder
for whatever we eventually come up with to deal with access control.
We're just as likely to end up with "is rw" or some such, especially
if we decide to allow you to declare attributes that are readable
but not writeable through the class interface.
: What about something like:
:
: my $.foo; # private instance attr
: our $.foo; # public instance attr
:
: my $foo; # as p5
: our $foo; # as p5
:
: MY $.foo; # private class attr
: OUR $.foo; # public class attr
:
: MY $foo; # invalid?
: OUR $foo; # invalid?
:
: method bar; # public instance method
: my method bar; # private instance method
: our method bar; # public instance method
: MY method bar; # private class method
: OUR method bar; # public class method
Doesn't do much for me. I think it's a mistake to overload my/our with
private/public distinctions because we might also want to distinguish
read/write. More subtly, it changes the "me" of my/our to mean the
current object or class rather than the current lexical scope, which
is going to be intrinsically confusing.
Plus it's not clear that class attributes are worth SHOUTING over.
It's my gut feeling that class variables are already pretty close to
"our" variables, so we only need a new word for instance variables,
which have a very different scope from any variables in Perl 5.
Plus I like emphasizing the has/is distinction to help keep people
from using inheritance when they should be using composition.
At least, that's what I like this week...
Larry
[snip]
> It's my gut feeling that class variables are already pretty close to
> "our" variables, so we only need a new word for instance variables,
> which have a very different scope from any variables in Perl 5.
Ok.
We also need a signifier for class methods (assuming
a distinction is made).
Perhaps one could use an initial cap to indicate a class
attribute/method:
class foo {
my $bar; # my is not used for attributes
our $baz; # neither is our
has qux; # instance attribute
has Waldo; # class attribute
method qwe; # instance method
method Rty; # class method
}
or similar.
--
ralph
I prefer to keep caps distinctions conventional rather than mandatory.
Maybe class methods could be indicated as in Ruby:
method qwe; # instance method
method foo.rty; # class method
But that wouldn't work as well for an anonymous class...
And Perl 5 certainly gets away without making the distinction.
And confusing the two does help if you want to write constructors
that can clone objects as well as create new ones. Perhaps they
could be distinguished by the type of the invocant, if declared.
Larry
I like that idea:
class SomeClass {
method class_method ( Class $class : ... ) { ... }
method instance_method ( SomeClass $self : ... ) { ... }
method dont_care_method ( $self : ... ) { ... }
}
Or will 'Class' actually be CLASS by analogy with HASH, ARRAY etc?
--
Piers
"It is a truth universally acknowledged that a language in
possession of a rich syntax must be in need of a rewrite."
-- Jane Austen?
I was going to say the same thing, but then I remembered that Perl 6
methods, unlike the sub 'methods' in Perl 5, won't get the invocant as the
first real argument--it will be the topic instead. And I don't think you
can do multiple-dispatch on topic, can you?
Trey
MD on topic could probably be easily allowed: sure, it's an invisible
argument, but it's still a parameter of the method invocation -- and
therefore internally could/should be a part of the method's full
signature. The syntax might get scary, tho.
My temporary hack while writing the proto-recipes was that we'd have a
property that would simply declare a method to be a class method, but
I'm having a hard time coming up with an acceptable name to suggest for it:
method foo is class_method { ... } # ???
It feels, conceptually, like something that should be a property. The
other possibility is to use a keyword other than "method" for class
methods, but that would also require us to think of a word (and would
probably just be shorthand for a named property anyway). So, I haven't
been able to come up with a single decent noun or adjective that means
"class method", so far. (classwide? static? blind? classmeth? cmethod? classorific?)
Regardless of how we declared it, my operating theory was that any
method declared as a class method would automatically be able to take
either a class or a class instance as it's invocant, and do the right
thing (i.e. when using an instance to invoke a class method, it would
automatically convert it to a class before assigning it as the topic, so
the implementing method wouldn't even notice, unless it went out of it's
way to look.)
This would DWIM, would mean we don't need multiple dispatch for it (at
least not in visible form) and would be in line with the common perl5 strategy:
$class = ref $class if ref $class;
If you *did* want a method that treated invoke-by-classname and
invoke-by-instance differently (i.e. a constructor), you simply wouldn't
declare it as a class method, and have the method check the topic itself.
MikeL
I'm not sure we're sticking with the all-uppercase built-in types.
They're kind of ugly, and we keep running into boundary cases.
So I think the built-in class types will start with an initial cap,
and the built-in primitive types will be all lowercase. So a general
polymorphic integer object is "Int", while a low-level, C-like integer
is "int". (An array of "int" is guaranteed to be stored compactly,
for instance.)
And I suspect it would make some people happy to turn class UNIVERSAL
into class Object.
Larry
The topic *is* the first real argument. It's just that you aren't
required to name the first argument. Whether an argument has a
name or not is somewhat independent of whether it can participate
in multiple dispatch. It might be convenient for the argument to
have a type, however.
The use of an implicit invocant should not be confused with out-of-band
topicalization. That's a mechanism for binding the outer topic to a
formal parameter that is not necessarily the inner topic.
Larry
Doesn't feel like a property to me. Feels to me like a type-coercion on
the invocant. Or if not a coercion exactly, a view of the desired type
of the invocant.
: Regardless of how we declared it, my operating theory was that any
: method declared as a class method would automatically be able to take
: either a class or a class instance as it's invocant, and do the right
: thing (i.e. when using an instance to invoke a class method, it would
: automatically convert it to a class before assigning it as the topic, so
: the implementing method wouldn't even notice, unless it went out of it's
: way to look.)
If every Object happens to implement the Class interface, merely
declaring the invocant as a Class would presumably have this effect,
whether or not MD was in effect. I don't know whether that's a good
idea or a bad idea. I'm sure there are people out there with opinions
on the subject, though.
: This would DWIM, would mean we don't need multiple dispatch for it (at
: least not in visible form) and would be in line with the common perl5 strategy:
: $class = ref $class if ref $class;
:
: If you *did* want a method that treated invoke-by-classname and
: invoke-by-instance differently (i.e. a constructor), you simply wouldn't
: declare it as a class method, and have the method check the topic itself.
We haven't solved the problem of instance methods that want to
reject class invocants at compile time. Though I suppose explicitly
declaring the type of the invocant would have that effect. I'm sure
there are some who would argue (and I might be one of them) that an
implicit invocant should default to only accepting an instance, and
you have to declare an untyped invocant to get class-or-instance.
(Or declare it with a class superposition like (Class|Dog), which
presumably lets you pass either a Class instance or a Dog instance).
Larry
An instance of class Class is wierd, because it defines two different
sets of things: internal bits, usually called "static", and
"interitable/delegatable" bits (both data and methods) which will be
present in all the instances of the type.
Javascript makes for a good thinking-about language here because the
constructors must explicitly attach each function and each member of
the new class.
Perl5 had some of this with bless'ing an anonymous, initialized hash --
the act of creating the data members was overt.
C++/Java, OTOH, fall into the trap of treating the class as a structure
definition -- once they've gone this route, there's the question of
"what secret word do we use to escape from the structure model" --
answer "static".
According to Java, there's four sets of "permissions" available for
members: private, package (no keyword), protected, public.
"Package" means anything in the same package, "Protected" is package
plus subclasses.
I wonder if there's actually another aspect here: That which is
accessible to instances. ("Particular"?)
Static members are usually considered "class-global, but uniformly
visible to the instances". Is it useful to talk about variables which
belong in the class object but which may or may not be visible to the
instances?
This may be more meaningful in the context of a tainted object, or in
conjunction with inheritance (we allow direct instances to access this
variable, but not instances of subclesses).
> : Regardless of how we declared it, my operating theory was that any
> : method declared as a class method would automatically be able to
> take
> : either a class or a class instance as it's invocant, and do the
> right
> : thing (i.e. when using an instance to invoke a class method, it
> would
> : automatically convert it to a class before assigning it as the
> topic, so
> : the implementing method wouldn't even notice, unless it went out of
> it's
> : way to look.)
>
> If every Object happens to implement the Class interface, merely
> declaring the invocant as a Class would presumably have this effect,
> whether or not MD was in effect. I don't know whether that's a good
> idea or a bad idea. I'm sure there are people out there with
> opinions
> on the subject, though.
That paragraph is a little counterintuitive? Wouldn't Class implement
the Object interface?
=Austin
__________________________________________________
Do you Yahoo!?
Faith Hill - Exclusive Performances, Videos & More
http://faith.yahoo.com
And I should point out that this approach would be good not just for
type purity, but because it optimizes for the common case. Class methods
are much rarer than instance methods. And the class-or-instance approach
seems to be even rarer than ordinary class methods, in practice.
Larry
Of course, in hindsight. So we have three cases to deal with:
- a method that can only take an instance (80% of the time?)
- a method that can take only a Class (15% of the time?)
- a method that can deal with both (< 5% of the time?)
The first two are well-understood and common behaviors, and probably
shouldn't force you to declare the invocant at all. The third form is
almost never what you mean (except in constructors and a few other
places) and should be discouraged compared to the other two.
In a message dated Sun, 13 Oct 2002, Piers Cawley writes:
> I like that idea:
>
> class SomeClass {
> method class_method ( Class $class : ... ) { ... }
> method instance_method ( SomeClass $self : ... ) { ... }
> method dont_care_method ( $self : ... ) { ... }
> }
So if the first two should be shorter than the third, one way to do
that would be something like:
class SomeClass {
cmethod class_method {...} # via a keyword
method instance_method {...} # via another keyword
sub dont_care_method {...} # check it yourself, as 1st arg
}
Except for the fact that the word 'cmethod' is not a terribly intuitive
choice.
In general, I'd vote for making the distinction through a keyword
rather than through more subtle hints: it seems the shortest way to say
what you mean, and the first two cases are certainly common enough to
justify them. Trying to put the distinction in the method name itself
makes me worry that other things are going on, like implicit
typecasting or something:
method SomeClass.class_method {...}
And putting it in the argument list makes me think at first glance that
it's an argument, but not necessarily an invocant:
method class_method ( Class $class : ... ) { ... }
.... (looks a lot like) ...
method class_method ( Class $class, ... ) { ... }
which, I assume, does something completely different.
MikeL
I would expect Class to inherit from Object (along with everything
else). It might be worth looking at a Smalltalk image or two at this
point...
I don't know about this precisely, but I will say that I have a strong
intuition that C<sub> within a class block I<should> mean something, and
be neither a syntax error nor a synonym for C<method>.
Trey
In this model, classes are objects, but they are not instances of
their superclass. The "subclass" relation is separate from the
"instance of" relation. The minimal environment is this:
Object is an instance of Class.
Class is also an instance of Class - that is, an instance of itself.
Class is a subclass of Object.
Ruby's small variation consists of a class called Module between
Class and Object: Module (also an instance of Class) is a
subclass of Object and the direct superclass of Class.
--
Mark REED | CNN Internet Technology
1 CNN Center Rm SW0831G | mark...@cnn.com
Atlanta, GA 30348 USA | +1 404 827 4754
Sorry, what I meant was that you would just use 'sub' when you don't
want the enforcement of invocant that either of the first two imply,
i.e. you'd use sub in the perl5 way:
sub dont_care_method {
my $self = shift;
if (ref $self) {
...
} else {
...
}
}
So sub is still just a perl5 sub, where the invocant is passed as the
first arg.
MikeL
In your superposition example (Class|Dog), am I'm assuming correctly that
you could invoke that method with an instance of any object that IS-A Dog?
--
Garrett Goebel
IS Development Specialist
ScriptPro Direct: 913.403.5261
5828 Reeds Road Main: 913.384.1008
Mission, KS 66202 Fax: 913.384.2180
www.scriptpro.com gar...@scriptpro.com