I can see it possibly being useful in a situation like the
following(which may be completely off, as I'm still digging my way
through A6):
class Foo {
method bar is public is rw {
}
}
Becoming:
class Foo {
method bar is public & rw {
}
}
Guess it just reads a bit better to me.
And you might even be able to do some weird stuff like:
class Foo {
method bar is public | rw {
}
}
Whereby bar is only an lvalue subroutine/method internally.
I don't think that junctions make sense here. Besides, the "is" is
optional:
class Foo {
method bar is public rw const frob knob { ... }
}
-Scott
--
Jonathan Scott Duff
du...@cbi.tamucc.edu
What we do need is some way of bundling a bunch of traits together
under a simple name. This is especially useful for long involved
types. Some of the type name examples in A6 are very long and
if you needed to use the type several places, are not only a pain to
type but you run into the "is it real the same every where problem"
and the "did I change it every where" problem. As a general principle
any time you have a long complicated token string that need to be
use multiple places, you need a way to assign it a short hand name.
Yes, a string macro will do it, but has a couple of problems:
1) difficult to generate associated error messages
2) macros are very heavy weight for this
Defining a Class for this is also overkill.
Maybe something like
rule traitdef :w { trait <ident> <trait>* ; }
So instead of saying:
my %pet is Hash of Array of Array of Hash of Array of Cat;
sub feed (%cats is Hash of Array of Array of Hash
of Array of Cat) {...}
You could say
trait cat_table is Hash of Array of Array of Hash
of Array of Cat;
my cat_table %pet;
sub feed (cat_table %cats) {...}
--
Mark Biggar
ma...@biggar.org
mark.a...@attbi.com
That feature is still in Schroedinger's little box.
Larry
Yes, yes, yes.
> Defining a Class for this is also overkill.
Ye.. well, no. Why?
> So instead of saying:
>
> my %pet is Hash of Array of Array of Hash of Array of Cat;
> sub feed (%cats is Hash of Array of Array of Hash
> of Array of Cat) {...}
> You could say
>
> trait cat_table is Hash of Array of Array of Hash
> of Array of Cat;
> my cat_table %pet;
> sub feed (cat_table %cats) {...}
I think classes are not necessarily the heavyweights some people might
expect them to be... I think of them more as types, actually.
Basically, if you replaced the word 'trait' with 'class', I think the
current plan is that you can do exactly what you're suggesting:
class CatTable is Hash of Array of Array of Hash of Array of Cat;
my %pet is CatTable;
sub feed (%cats is CatTable);
(note I fixed the last lines to use the right syntax... before, you
were actually saying that %pet was a Hash of CatTables...)
MikeL
Unless you mean trait-classes, because I may want the same common set
of traits to apply to multiple distinct things (different classes,
objects, whatever).
So:
type cat_table is Hash of Array of Array of Hash is traits_only;
or
type cat_table is Hash of Array of Array of Hash;
More to the point:
type sigfunc is interrupt is reentrant;
sub sig_ign() is sigfunc {...}
sub sig_kill() is sigfunc {...}
sub sig_intr() is sigfunc {...}
type null but defined but false;
...
return undef but null;
=Austin
>> Defining a Class for this is also overkill.
> Ye.. well, no. Why?
class Foo is Bar; # normal inheritance
class Baz is Bar; # the thing that we are over-killing
Foo.isa("Baz") == FALSE;
A lightweight, typedef-like mechanism behaves differently:
class Foo is Bar;
typedef Baz is Bar;
Foo.isa("Baz") == TRUE;
The problem biols down to the fact that inheritance hierarchies are, um,
hierarchies -- trees. The lightwieght mechanism provides aliases for
nodes within the tree, thus all descendent nodes are also descendents of
the aliases.
Dave.
--
http://dave.whipp.name
> I don't think that junctions make sense here. Besides, the "is" is
> optional:
>
> class Foo {
> method bar is public rw const frob knob { ... }
> }
Ah yes, I'd forgotten about this. Thanks. Still I wonder a bit about
the idea of mutually exclusive properties, where one can take effect if
the other(s) doesn't make sense in the current context.
Getting mired in life can really detract from following the developments
in this community.
This is WAGging based on A6, but I guess I see things like this as
being implemented by making subs that inherit from subs:
class sigfunc is sub (...default signature...) is interrupt is
reentrant;
sub sig_ign(...alternate signature...) is sigfunc {...}
sub sig_kill is sigfunc {...}
sub sig_intr is sigfunc {...}
sigfunc sig_foo {...} # could you also say it like this, I wonder?
Since C<sub> is itself a class, you can subclass it. And since A6
indicates that the signature, traits, and even implementing body are
just properties of a given C<sub> "object", you should be able to
override them individually if you want, for example, an alternate
signature. At least, I'm hoping something like that works -- there's a
lot of guessing there.
> type null but defined but false;
>
> ...
> return undef but null;
Hmm... I'm not entirely sure how that works for runtime properties...
but what about
class null is void but defined but false;
return undef but null;
Would something like that that be OK? Essentially using 'void' as a
marker that you're defining a (heh) classless class? I'd really like
to avoid making a separate keyword for combining traits, I'd love for
it to just use the normal class inheritance mechanisms.
>> class CatTable is Hash of Array of Array of Hash of Array of Cat;
>>
>> my %pet is CatTable;
>> sub feed (%cats is CatTable);
MikeL
Ah, I get it. But why would you want that -- treating Foo and Baz as
synonymous? Shouldn't you always be using Baz instead of Foo, if you
really mean Baz and not Foo, and vice versa? Because later on, if you
changed it such that:
class Foo is Bar;
typedef Baz is Bar is blarpy;
Foo.isa("Baz") == FALSE; # BOOM!
...which would break anything that relied on the symmetry.
Mind you, I'm not really against the idea, I'm just devil's advocating
-- trying to think whether we really need the feature or whether we
just _think_ we need it because we're all used to it from C, when in
fact P6 will provide better ways of doing it. (?)
MikeL
Er, I'm not sure how that would actually be implemented.
: And you might even be able to do some weird stuff like:
:
: class Foo {
: method bar is public | rw {
:
: }
: }
:
: Whereby bar is only an lvalue subroutine/method internally.
You're already confusing "or" with "xor". This does not bode well...
Larry
You are a bad, evil man for reminding me of this. I have yet to
brainvomit about stack-streams. (I have found an interesting analogy
between subs/blocks and streaming video compression, but it is too
large to fit in the margin :-)
> And since A6 indicates that the signature, traits, and even
> implementing body are just properties of a given C<sub> "object",
> you should be able to override them individually if you want, for
> example, an alternate signature. At least, I'm hoping something
> like that works -- there's a lot of guessing there.
Which reminds me that sigfuncs aren't is reentrant. They're but
reentrant.
my sub &foo = &sig_kill; # &foo is "but interrupt reentrant", too.
Which points in the direction of "sticky value traits", and "sticky
value traits" is a synonym for "class".
So you're right -- this case is a class extension. But then the
question becomes "how easy is it to override a class like this"?
> sub sig_kill is sigfunc {...}
> sub sig_intr is sigfunc {...}
>
> sigfunc sig_foo {...} # could you also say it like this, I
> wonder?
Well, no. That's going to look like a function returning a sigfunc.
Obviously we're walking on an edge-case. (Lucky for me that you're Mr.
Edge-Case, eh?)
> > type null but defined but false;
> >
> > ...
> > return undef but null;
>
> Hmm... I'm not entirely sure how that works for runtime properties...
>
> but what about
>
> class null is void but defined but false;
>
> return undef but null;
>
> Would something like that that be OK? Essentially using 'void' as a
> marker that you're defining a (heh) classless class? I'd really like
> to avoid making a separate keyword for combining traits, I'd love for
> it to just use the normal class inheritance mechanisms.
Cool if you can get it. But I want to be able to handle all sorts of
trait-contexts:
my macro sucks() is parsed(/<null>/) { "is slurpificatious" }
class foo_arg is rw is copy is coerced is optional;
sub foo( $v is foo_arg, @x is foo_arg sucks) {...}
=Austin
Ahh, but I think it is important. When programming in C++ I use
typedefs all over the place for various reasons. A typedef is more
than a class that behaves exactly the same... it's more of a pointer.
To a data type. It allows you to do stuff like type-linked-lists
("typelists" Alexandrescu calls them), and without it, these things
would actually be impossible.
Of course, in the realm of Perl, things might not be so important.
Because of Perl's power, typelists and their siblings aren't all that
useful. You could, I imagine, get about the same effect with:
my $Baz is constant = Bar is blarpy;
With the psychological disadvantage of holding a type in a
dollar-variable.
[But then he remembers the := operator]
class Baz := Bar is blarpy;
I've seen the design team refer to things like this, so I think we've
got it.
Oh, on an off-topic note, "Modern C++ Design" is a super spiffy book.
People who wonder what C++ has on Java haven't read this book :).
Luke
Treating BAR and BAZ as synonymous. Coincidentally, Foo is Bar.
> Mind you, I'm not really against the idea, I'm just devil's
> advocating
> -- trying to think whether we really need the feature or whether we
> just _think_ we need it because we're all used to it from C, when in
> fact P6 will provide better ways of doing it. (?)
macro *defmacro($t1, @rest is variadic) is parsed(/<token> <token>+ ;/)
{
eval "macro *$t1 is parsed(/<null>/) { return @rest.join(' '); }";
}
defmacro Baz Bar;
m4, anyone?
=Austin