I have just started to write a large amount of Perl 6 code, partly to
help with testing the Pugs (and later Parrot) implementation of the
language. During this process, I discovered a few details about Perl
6 that I don't yet understand, and haven't yet been able to get
answers to in my reading of the Synopsis. So I'll ask about them
here.
For some of these points, I just wanted clarification on something I
think I already know, and for others its just a "how do I" matter:
0. As I understand it, the current state of being says that all Perl
6 code will by default "use strict" and "use warnings" (y/n), unless
it's a one-liner?
1. What is the behaviour of require() in regards to what it does when
a module or class was previously defined in a file that was already
loaded, but that file didn't have a file name that corresponded to
the module or class? Eg, say a program determines at runtime that it
wants to use module Foo, and that module is defined in a file named
Bar that declares both the Bar and the Foo module. If the program
had already loaded file Bar sometime earlier, then will "require Foo"
use the existing declaration, or try to load a file named "Foo" but
fail? Or will something else happen. Essentially, I want users of
my module to be able to declare a data-containing module using either
method, its own file or shared in another file, and my module to just
see and use it.
For reference, this is what I currently have to do in Perl 5:
no strict 'refs';
my $package_is_loaded = defined %{$template_module_name~'::'};
use strict 'refs';
unless( $package_is_loaded ) {
require $template_module_name;
}
$text = $template_module_name->get_text_by_key( $message.msg_key );
I do that because Perl 5 require() always attempts to load a matching
file name.
2. Related to the above, if the require() of Perl 6 will indeed try
to load a file with the matching name, then what is the proper way to
test if a module was already loaded? Hopefully this is elegant,
rather than the Perl 5 "no strict 'refs'" cludge. ('cludge' means
anything I need to un-strict to accomplish.)
3. Does my explicit new() method get a "$self:" argument that is
already instantiated like other methods, or do I have to do something
like a bless() on my own declared variable of the class type and
explicitly return that?
4. Is it possible to create a 'class' that sub-classes a 'module' or
can one only subclass a 'class'. The reason I'm declaring the parent
as a module is because it doesn't have any attributes, but it does
have utility functions that I wish for users of multiple sub-classes
to be able to invoke off of them.
5. If I have a class property defined using "has Str %.foo;", and an
object of the class is named "$bar", then is it correct syntax to
refer to the property as a whole using "$bar.foo" and an element
using "$bar.foo{'abc'}"?
6. I understand that sub/method arguments are passed in read-only by
default. However, if (see #2) I do a "return( $bar.foo );" when will
the caller getting that return value have received a reference to or
a copy of the attribute?
7. Say I have 2 arrays of arrays, @foo and @bar. What is the most
concise Perl 6 syntax for each of these operations in Perl 5? The
Perl 5 equivalent is expressed where each is an array having array
refs that are unalike in size.
@foo = @bar # a shallow copy
@foo = map { [@{$_}] } @bar # a deep copy
8. Is it possible with a sub or method argument signiture to specify
that the arguments must have defined values? Or are specced
non-optional arguments only guaranteed to have the correct container
passed to them?
9. What does the as() method on built-in types do on a hash that has
undefined values? Does it raise a "use of undefined value in string"
warning, or just substitute the empty string?
10. When using as(), can I specify that the results get sorted? Or
alternately, will hashes always serialize in the same order on all
platforms, unlike in Perl 5 where its pairs come out in an apparently
random order? If not, I will have to continue to do manually what
as() does.
Okay, that's it for my initial set of questions.
Thanks in advance for any feedback, whether they are plain answers or
pointers to where *exactly* in the Perl 6 spec I should successfully
find the answer.
-- Darren Duncan
Yes.
: 1. What is the behaviour of require() in regards to what it does when
: a module or class was previously defined in a file that was already
: loaded, but that file didn't have a file name that corresponded to
: the module or class? Eg, say a program determines at runtime that it
: wants to use module Foo, and that module is defined in a file named
: Bar that declares both the Bar and the Foo module. If the program
: had already loaded file Bar sometime earlier, then will "require Foo"
: use the existing declaration, or try to load a file named "Foo" but
: fail? Or will something else happen. Essentially, I want users of
: my module to be able to declare a data-containing module using either
: method, its own file or shared in another file, and my module to just
: see and use it.
:
: For reference, this is what I currently have to do in Perl 5:
:
: no strict 'refs';
: my $package_is_loaded = defined %{$template_module_name~'::'};
: use strict 'refs';
: unless( $package_is_loaded ) {
: require $template_module_name;
: }
: $text = $template_module_name->get_text_by_key( $message.msg_key );
:
: I do that because Perl 5 require() always attempts to load a matching
: file name.
I think Perl 6 will probably try to do the same. I suspect it's better
to keep the require/use interface as a simple mapping to filename
space, and let you provide a different interface that documents that
you're doing something non-standard, rather than complicating the
standard interface.
Of course, I speak with forked tongue here, because we're already
complicating the whole module system with the shortname/longname
distinction in order to get control of versioning, so there probably
has to be a database somewhere of mappings of each short name to all
corresponding long names, and for each of those, to their compilation
state and actual location. You could in principle subvert that
mechanism. But I still think it'd be a mistake, unless we can make
it fall out of the design naturally.
: 2. Related to the above, if the require() of Perl 6 will indeed try
: to load a file with the matching name, then what is the proper way to
: test if a module was already loaded? Hopefully this is elegant,
: rather than the Perl 5 "no strict 'refs'" cludge. ('cludge' means
: anything I need to un-strict to accomplish.)
There is no need for "strict refs" in Perl 6, since we distinguish
symbolic naming from referential naming syntactically in most cases.
But as for whether a module is loaded or not, what do you mean by
"module"? I think the interface should allow you to ask, "If I
did this particular use or require, what would it actually do."
Part of the return information on that would be not only whether
it would load a file, but which version of the file would be loaded
(or is already loaded), if you've wildcarded the version and/or author.
: 3. Does my explicit new() method get a "$self:" argument that is
: already instantiated like other methods, or do I have to do something
: like a bless() on my own declared variable of the class type and
: explicitly return that?
Er, the invocant on a constructor is generally not $self, but $class.
But anything that is declared "method" rather than "sub" gets an implicit
invocant if the first arg doesn't end with ':'.
You do have to do a $class.bless(%args) at some point in the constructor.
A12 discusses this. (Note there are Updates since the syntax has changed
over time.) The new $self is not mentioned as an argument, just returned,
at least for objects of the standard opaque class. Objects emulating
Perl 5 hashes and such can specify an input hash to bless--the details
are delegated to the CREATE and BUILD submethods, which .bless calls
implicitly.
: 4. Is it possible to create a 'class' that sub-classes a 'module' or
: can one only subclass a 'class'. The reason I'm declaring the parent
: as a module is because it doesn't have any attributes, but it does
: have utility functions that I wish for users of multiple sub-classes
: to be able to invoke off of them.
That sounds more like a role than a class or module. You can compose
a role into a class and its methods may be inherited by subclasses.
It's probably illegal to declare a method in an ordinary module, however.
: 5. If I have a class property defined using "has Str %.foo;", and an
: object of the class is named "$bar", then is it correct syntax to
: refer to the property as a whole using "$bar.foo" and an element
: using "$bar.foo{'abc'}"?
Yes, except that "has" always declares instance attributes, not class
attributes. You'd want "our" or "my" instead. But as long as you
declare the name with %.foo, it'll generate the accessor. However,
it might be wiser to go ahead and wrap your own accessor around it
that takes the subscripting out of the hands of the user, in case
you want to change the representation from hash to something else.
(Though, of course, you can always return a tied hash that proxies
for the real data. But sometimes it's better not to box yourself
into that corner. In particular, with a method interface you can
add in options, which would be harder with a hash interface--you'd
have to emulate a multi-dimensional hash to get extra "keys" in.)
: 6. I understand that sub/method arguments are passed in read-only by
: default. However, if (see #2) I do a "return( $bar.foo );" when will
: the caller getting that return value have received a reference to or
: a copy of the attribute?
Reference. If you pass a reference out of your method, even if the
method itself is not rw, you're letting the user do whatever they
want through the reference. To do otherwise sends us down the tunnel
of C++ const madness.
: 7. Say I have 2 arrays of arrays, @foo and @bar. What is the most
: concise Perl 6 syntax for each of these operations in Perl 5? The
: Perl 5 equivalent is expressed where each is an array having array
: refs that are unalike in size.
:
: @foo = @bar # a shallow copy
: @foo = map { [@{$_}] } @bar # a deep copy
Works the same in Perl 6, if you've got arrays of arrays. But if
you're just trying to do two-dimension arrays, then you can use
something like shape(Inf,Inf) to effectively bring the second dimension
up to the status of the first dimension, in which case
@foo = @bar
would do the deep copy, or more accurately, the shallow copy includes
the second dimension. See S9 for info about shape(). Note that a
two dimensional array would be subscripted @foo[1;2] rather than
@foo[1][2].
: 8. Is it possible with a sub or method argument signiture to specify
: that the arguments must have defined values? Or are specced
: non-optional arguments only guaranteed to have the correct container
: passed to them?
I think you can place that constraint on a formal parameter with
$arg of Any where { .defined }
or some such. The MMD engine will simply ignore that particular
signature if the constraint isn't satisfied.
: 9. What does the as() method on built-in types do on a hash that has
: undefined values? Does it raise a "use of undefined value in string"
: warning, or just substitute the empty string?
Warnings are on by default, so I expect you get a warning and it substitutes
the empty string, just like Perl 5. We still trying to be failsoft here.
: 10. When using as(), can I specify that the results get sorted? Or
: alternately, will hashes always serialize in the same order on all
: platforms, unlike in Perl 5 where its pairs come out in an apparently
: random order? If not, I will have to continue to do manually what
: as() does.
The default will probably be random, but whether there's an easy switch
to sort it, or we rely on a subsequent .sort, depends on how we define
sort to work on things like lists of pairs, I suppose, and whether .as
is return a list of pairs or just alternating keys and values like .kv.
And that probably depends on what you're converting to, which is context
dependant. Just saying "as" is not enough information to decide. You
have to specify "as what".
: Okay, that's it for my initial set of questions.
:
: Thanks in advance for any feedback, whether they are plain answers or
: pointers to where *exactly* in the Perl 6 spec I should successfully
: find the answer.
Hope this helps. Thanks for your efforts. We're gonna get there, folks!
Larry
A few more interesting things happened since then, which can be seen
in the current version of Locale::KeyedText in the Pugs version
control.
At 5:35 PM -0800 3/8/05, Larry Wall wrote:
>: 8. Is it possible with a sub or method argument signiture to specify
>: that the arguments must have defined values? Or are specced
>: non-optional arguments only guaranteed to have the correct container
>: passed to them?
>
>I think you can place that constraint on a formal parameter with
>
> $arg of Any where { .defined }
>
>or some such. The MMD engine will simply ignore that particular
>signature if the constraint isn't satisfied.
The biggest change is that, upon a re-reading Synopsis 12 (and 9)
that was inspired by your above comment, I created some subtypes
which I now use everywhere; the declarations and some examples of use
are:
subtype KeyName of Str where { $_.defined and $_ ne '' and $_ !~ m/\W/ }
subtype KeyNameHash of Hash is shape(KeyName) of Str; # keys are of
type KeyName, values of type Str
subtype PkgName of Str where { $_.defined and $_ ne '' and $_ !~
m/<-[a-zA-Z0-9_:]>/ }
subtype PkgNameArray of Array of PkgName;
...
class Locale::KeyedText::Message {
has KeyName $.msg_key; # str - the machine-readable key that
uniquely identifies this message
has KeyNameHash %.msg_vars; # hash (str,str) - named variables
for messages, if any, go here
method new( $class: KeyName $msg_key, KeyNameHash ?%msg_vars )
returns Locale::KeyedText::Message {
my $message = $class.bless( {} );
$message.msg_key = $msg_key;
$message.msg_vars = %msg_vars; # copy list values
return( $message );
}
...
class Locale::KeyedText::Translator {
has PkgNameArray @.tmpl_set_nms; # array of str - list of
Template module Set Names to search
has PkgNameArray @.tmpl_mem_nms; # array of str - list of
Template module Member Names to search
method new( $class: PkgNameArray @set_names, PkgNameArray
@member_names ) returns Locale::KeyedText::Translator {
my $translator = $class.bless( {} );
$translator.tmpl_set_nms = @set_names; # copy list values
$translator.tmpl_mem_nms = @member_names; # copy list values
return( $translator );
}
...
By using subtypes in this way, I could remove a lot of explicit input
checking code from my methods, which is great. Also, the "where
clause" is not being repeated for every argument or attribute or
variable declaration. (I like SQL domains for the same reasons.)
So how does that code sample look? Anything that looks like invalid
Perl 6. Anything no one thought of doing before but that looks like
a good idea?
A question: Would "has PkgNameArray @.tmpl_set_nms;" do what I
expect, where the array as a whole is the sub-type, or would it make
an array where each element is the sub-type?
>: 5. If I have a class property defined using "has Str %.foo;", and an
>: object of the class is named "$bar", then is it correct syntax to
>: refer to the property as a whole using "$bar.foo" and an element
>: using "$bar.foo{'abc'}"?
>
>Yes, except that "has" always declares instance attributes, not class
>attributes. You'd want "our" or "my" instead. But as long as you
>declare the name with %.foo, it'll generate the accessor. However,
>it might be wiser to go ahead and wrap your own accessor around it
>that takes the subscripting out of the hands of the user, in case
>you want to change the representation from hash to something else.
I meant to say "attributes", sorry.
I have my own accessors, with different names, and don't expect
anyone to use the autogenerated ones. But I
made the attributes public for now so that one of my classes could
access the attributes of one of my other ones directly; both of these
are defined in the same file.
Maybe that's a bad idea, and if so I can change it.
New question: Is there a way to say that two classes have a
privileged relationship, sort of like a marriage, such that each can
see and/or change otherwise private attributes in objects of the
other class, and yet the attribute list of each class is completely
different from the other? Neither of the two objects is a subclass
of the other, nor fulfills a role defined by the other.
For example, say that there are two closely related classes,
Container and Node, where conceptually a Container object is an
environment in which Node objects live. I would like to declare the
attributes of both classes private from the viewpoint of all other
classes, but I want Container and Node objects to be able to read or
set each others' attributes directly as if they were public. Both
classes have their own set of methods that outside code can invoke
directly, and each kind of object can be held by external code.
Also, does my request sound like something that would be reasonable
to do, or a bad practice to avoid?
Thank you for all the hard work you have been doing.
-- Darren Duncan
I think this declares an array of PkgNameArrays, but "has
@.tmpl_set_nms is PkgNameArray;" will do what you want.
> New question: Is there a way to say that two classes have a
> privileged relationship, sort of like a marriage, such that each can
> see and/or change otherwise private attributes in objects of the
> other class, and yet the attribute list of each class is completely
> different from the other? Neither of the two objects is a subclass
> of the other, nor fulfills a role defined by the other.
S12:
Attributes are never visible outside a class definition, so a multi
method can only directly access the attributes of a class it's defined
within. However, it may call the private attribute accessors from a
different class if that other class has indicated that it trusts the
class the multi method is defined in:
class MyClass {
trusts Yourclass;
...
}
(end quote)
So for the relationship to work both ways, each class would have to
mark the other as trusted.
--
Brent 'Dax' Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker
"I used to have a life, but I liked mail-reading so much better."
That's very cool. I start to see the appeal of AOP.
> New question: Is there a way to say that two classes have a
> privileged relationship, sort of like a marriage, such that each can
> see and/or change otherwise private attributes in objects of the
> other class, and yet the attribute list of each class is completely
> different from the other? Neither of the two objects is a subclass
> of the other, nor fulfills a role defined by the other.
>[...]
> Also, does my request sound like something that would be reasonable
> to do, or a bad practice to avoid?
FYI, in C++, the keyword 'friend' precisely describes the relationship
you are discussing (and appears to be homologus to P6 'trusts').
There are good and bad things to be said about these relations but,
IME, they are usually used because they have to be in order to achieve
certain behavior, not because it is the cleanest or most appropriate
way to build the model.
Therefore, I would be very cautious about using 'trusts'. YMMV.
--Dks
Those seem to by syntactically correct. What they don't allow you to
distinguish is whether you're using the constraints for MMD pattern matching
or validation--the practical difference being that you want to give
good error feedback if you're doing validation, and you want to silently
fail if you're doing MMD, and let the default routine spit out error
messages. I'm not sure how to solve that problem offhand. Using
different subtypes for ordinary methods vs multi methods seems like
about twice as many subtypes as you need. Hmm, perhaps it's just another
failure context dependency. So you write
subtype Foo of Bar where { .defined or fail "Undefined Foo" }
and then the ordinary method dispatch can report the error, while
the MMD can suppress it and keep going.
My other quibble is that you seem to be prone to stating things in the
negative for at least two of your three tests here:
subtype KeyName of Str where { $_.defined and $_ ne '' and $_ !~ m/\W/ }
and it seems to me that you could simplify all that to just
subtype KeyName of Str where { m/^\w+$/ }
If that succeeds, you know it's defined and non-null. You might argue that
the m/\W/ short-circuits, but I would counter-argue that failure is
supposed to be the exceptional case, and in every successful call you have
to scan the whole string anyway. Plus it's just easier to understand.
And it lets you write the constraint without explicit reference to $_,
which I will admit was my first motivation in wanting to rewrite your
constraint. The negatives and redundancies I only noticed later.
: class Locale::KeyedText::Message {
:
: has KeyName $.msg_key; # str - the machine-readable key that
: uniquely identifies this message
That's fine.
: has KeyNameHash %.msg_vars; # hash (str,str) - named variables
: for messages, if any, go here
That's not. As pointed out in another message want
has %.msg_vars is KeyNameHash; # hash (str,str) - named variables
or maybe just
has Str %.msg_vars is shape(KeyName); # hash (str,str) - named variables
and avoid cluttering up the symbol table.
: method new( $class: KeyName $msg_key, KeyNameHash ?%msg_vars )
: returns Locale::KeyedText::Message {
: my $message = $class.bless( {} );
: $message.msg_key = $msg_key;
: $message.msg_vars = %msg_vars; # copy list values
: return( $message );
: }
I'd write
return $message;
but that's just stylistic. C<return> is actually a list operator (at
least syntactically), so the parens are optional. But I personally
prefer to view return as more of a keyword than a function.
: ...
:
: class Locale::KeyedText::Translator {
:
: has PkgNameArray @.tmpl_set_nms; # array of str - list of
: Template module Set Names to search
:
: has PkgNameArray @.tmpl_mem_nms; # array of str - list of
: Template module Member Names to search
Here too, I'd probably just write
has PkgName @.tmpl_set_nms;
has PkgName @.tmpl_mem_nms;
: method new( $class: PkgNameArray @set_names, PkgNameArray
: @member_names ) returns Locale::KeyedText::Translator {
method new( $class: PkgName @set_names, PkgName @member_names )
returns Locale::KeyedText::Translator {
or maybe even just
method new( $class: @set_names, @member_names )
returns Locale::KeyedText::Translator {
and rely on the assignment to do the validation. (But having the type
names will work better under MMD.)
And yes, "trusts" bestows trust on another class. I have no opinion
on its suitability for any particular task. I'm just the language
designer--my job is to shoot you in the foot and make you think
you did it to yourself. :-)
Larry
My view is that typing strings by means of patterns should always
exhaust the string as the above pattern does. I can imagine some
magic that lets
my KeyName @a = "First Second";
allow to actually have two entries @a[0] eq "First"
and @a[1] eq "Second" by somehow morphing the pattern into
continued matching mode where the next index continues where
the previous left off---and skipping whitespace.
Just an idea...
--
TSa (Thomas Sandlaß)
That's...sick... I love it. *Please* don't tell Damian.
Larry
However, with my particular use I wouldn't want
that to happen; I would want the assignment to
just fail with an error.
If we're going to do what you want, we should
have some way of specifying which of the
behaviours we want using different syntax around
the rule definition.
Incidentally, I noticed that '@a = "First
Second"' looked a lot like the reverse of what
'$b = "@a"' did in Perl 5.
-- Darren Duncan
Okay, I have gone and replaced the "$_ ne '' and $_ !~ m/\W/" with a
"m/^\w+$/".
However, unless Perl 6 is different than Perl 5 in its treatment of
undefined values, I still need the ".defined" part, meaning I end up
with:
subtype KeyName of Str where { .defined and m/^\w+$/ }
In Perl 5, running something like the un-gated "$msg_key =~ m/^\w+$/"
gives this warning:
Use of uninitialized value in pattern match (m//) at
Locale/KeyedText.pm line 85.
To avoid that, I do "defined( $msg_key ) and $msg_key =~ m/^\w+$/" in Perl 5.
You have mentioned before that Perl 6 still treats the use of
undefined values other than in boolean context as an error. So would
applying a Rule against an undefined value produce a warning in Perl
6 or not? (A quick scan of S12 didn't say.)
-- Darren Duncan
<whisper>
Well there are some people who consider it quite sane :)
http://www.cduce.org/papers/icalp04.pdf
Abstract:
This paper studies the problem of matching sequences against
regular expressions in order to produce structured values.
To me handling XML data is an area where Perl 6 could|should|will excel!
I think Perl 5 already does.
</whisper>
MfG
--
TSa (Thomas Sandlaß)