Given:
sub abc(Int $n) { say $n }
If we pass a variable typed as Str
to abc
we get a compile-time error:
my Str $s = "123"; abc $s;
If we pass an untyped variable that holds a string, we get a runtime error:
my $s = "123"; abc $s;
C++ supports an auto
keyword which allows for type inference.
Is it possible to define something like auto
in Perl 6 such that:
auto $s = "123";
would result in $s
being typed as Str
?
I.e. then we could do the following:
auto $s = "123"; abc $s;
And get a compile-time error.
What you are looking for is probably what we call allomorphs in Perl6, types that can behave differently depending on the context. For the particular case you have posted, there's the IntStr allomorph:
sub abc(Int $n) { say $n }
my IntStr $s = <123>;
abc $s; # prints 123
(Please note that it needs the quote-words <> instead of the usual ""
). Allomorphs, in general, are subclassses of the classes they can be typecasted into; IntStr
subclasses Int
and Str
. This can be done in general for any types you want to auto
, as long as they are mutually convertible.
Another option, if you already know what you are going to get and what it is being turn into, is to use coercion:
sub bcd(Int(Str) $n) { say $n }
my $t = "123";
bcd $t; # prints 123
In this case, the string will be coerced to an Int
in the Capture before being used by the subroutine body.
Finally, you can use the number contextualizer, as long as you use when the variable is effectively going to be used.
sub efg($n) { say +$n }
my Int $u = 123;
my Str $v = "123";
efg $u;
efg $v;
+
puts a variable in a numeric context, automatically converting it to a number. You can even turn that into a signature constraint if you want to restrict it to either Int or Str
sub xyz($n where $_ ~~ Int | Str ) { say +$n }
xyz $u;
xyz $v;
xyz $t;
xyz $s;
(It's using the variables defined above) Here it will work no matter if the variable does not have a type assigned (like $t
, or has been defined as IntStr
, Int
or Str
). As long as it can be smartmatched to Int
or Str
, it will be fed into the sub body and turned into a number via contextualization.
Full program is here, just in case you want to download and check it.
Is it possible to define something like
auto
in Perl 6
I think it is, sort of. But I'm going to have to translate your question into three different ones to provide a more useful answer.
For my answers to the first two questions below, please reference a reddit comment I wrote about this. My comment was in four parts, separated by horizontal rules. The first and last parts are relevant to your question.
Yes.
You can more or less arbitrarily modify the Perl 6 language on the fly from userland code.
Quoting a bullet point from the first part of the comment I linked above:
Quoting a bit of the last part I wrote:
While slangs can be implemented ... they are not officially supported ... and are not as sugary as they need to be.
Yes.
Unfortunately you can't yet define statement macros, which is what you'd need for a new type of variable declaration. Quoting the last section in the comment I linked above:
"The intended design options for situations where you want an internal DSL but it's too syntactically in conflict with standard Perl 6 to just use user defined routines and operators are ... Write an is parsed
macro [or] Write a slang. Either of these can, in theory, parse any syntax you want. But is parsed
macros haven't landed and look like they're at least a year or three away -- they're still just a design concept being discussed in 007."
Yes.
Just implement your idea and lobby for its inclusion. Possibly start with a slang. Possibly just directly hack on the entire compiler.
I'm being serious about that last point.
The Rakudo Perl 6 compiler is of course open source.
Much more importantly, it's mostly written in Perl 6. (And most of what isn't Perl 6 is nqp which is basically a subset of full Perl 6.)
If you can write some basic Perl 6 code; are willing to ask loads of questions on the freenode IRC channel #perl6-dev; and are patient; then you should be able to implement just about any idea in Perl 6 and your auto
idea seems relatively simple.
(Where by "relatively" I'm imagining a knowledgeable core dev might be able to do a proof of concept in a few hours assuming I've correctly understood the problems they'd face. And one day, when slangs and/or macros are more polished perhaps it would take about an hour.)
I just want to mention Proxies. These work at the container level and only at run-time. But give some ability to control or track what's going into a variable.
sub auto($v?) is rw {
my $val = $v;
Proxy.new(
FETCH => -> $, { $val },
STORE => -> $, $new-val {
die "You canna change type from {$val.WHAT.^name} to {$new-val.WHAT.^name}"
unless $new-val.WHAT ~~ $val.WHAT;
$val = $new-val;
}
)
}
my $i := auto(11);
$i = 69;
say $i;
$i = 'blah'; # Boom
Proxys can be used to implement something like the auto
types, but only at run-time and only at the container level. They're also not quite as water-tight, as the container associated with a variable can change. For example, using the bind :=
operator
$i := 'he he'; # changed container
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With