If regexes are methods, which class they correspond to? - oop

Regexes are actually Methods:
say rx/foo/.^mro # ((Regex) (Method) (Routine) (Block) (Code) (Any) (Mu))
In that case, it means that they can act on self and are part of a class. What would that class be? My hunch is that it's the Match class and that they are actually acting on $/ (which they actually are). Any other way of formulating this?

Ultimately, all regexes expect to receive an invocant of type Match or some subclass of Match. In Perl 6, an invocant is simply the first argument, and is not special in any other way.
Those regexes declared with rule, token or regex within a package will be installed as methods on that package. Most typically, they are declared in a grammar, which is nothing more than a class whose default parent is Grammar rather than Any. Grammar is a sub-type of Match.
grammar G {}.^mro.say # ((G) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))
It's thus quite natural to see these as just methods, but with a body written in a different language. In fact, that's precisely what they are.
It's a little harder to see how the anonymous regexes are methods, in so far as they don't get installed in the method table of any type. However, if we were to write:
class C {
method foo() { 42 }
}
my $m = anon method () { self.foo }
say C.$m()
Then we see that we can resolve symbols on the invocant through self, even though this method is not actually installed on the class C. It's the same with anonymous regexes. The reason this matters is that assertions like <ident>, <.ws>, <?before foo> and friends are actually compiled into method calls.
Thus, anonymous regexes being methods, and thus treating their first argument as an invocant, is what allows the various builtin rules, which are declared on Match, to be resolved.

A method does not have to correspond with any class:
my method bar () { say self, '!' }
bar 'Hello World'; # Hello World!
my regex baz { :ignorecase 'hello world' }
'Hello World' ~~ /<baz>/;
'Hello World' ~~ &baz;
&baz.ACCEPTS('Hello World'); # same as previous line
# baz 'Hello World';
By default methods, and by extension regexes have a has relationship with whatever class they are declared inside of.
class Foo {
method bar () { say self, '!' }
# has method bar () { say self, '!' }
regex baz { :ignorecase 'hello world' }
# has regex baz () { :ignorecase 'hello world' }
}
A regex does need some requirements fulfilled by whatever it's invocant is.
By just running it as a subroutine, it tells you the first one:
my regex baz { :ignorecase 'hello world' }
baz 'Hello World';
No such method '!cursor_start' for invocant of type 'Str'
in regex baz at <unknown file> line 1
in block <unit> at <unknown file> line 1
Usually a regex is declared inside of a class declared with grammar.
grammar Foo {
}
say Foo.^mro;
# ((Foo) (Grammar) (Match) (Capture) (Cool) (Any) (Mu))
So the requirements are likely fulfilled by Grammar, Match, or Capture in this case.
It could also be from a role that gets composed with it.
say Foo.^roles.map(*.^name);
# (NQPMatchRole)
There is even more reason to believe that it is Match or Capture
my regex baz {
^
{ say 'baz was called on: ', self.^name }
}
&baz.ACCEPTS(''); # baz was called on: Match
my regex baz ( $s ) {
:ignorecase
"$s"
}
baz Match.new(orig => 'Hello World'), 'hello';
# 「Hello」
I see no reason someone couldn't do that themselves in a normal class though.
Note that $/ is just a variable. So saying it is passed to a regex is a misunderstanding of the situation.
my regex baz ( $/ ) {
:ignorecase
"$/"
}
'Hello World' ~~ /<baz('hello')>/;
# 「Hello」
# baz => 「Hello」
It would be more accurate to say that when calling a regex from inside of another one, the current $/ is used as the invocant to the method/regex.
(I'm not entirely sure this is actually what happens.)
So the previous example would then be sort-of like this:
'Hello World' ~~ /{ $/.&baz('hello') }/;

This explanation combines what I think Brad++ and Jonathan++ just taught me, with what I thought I already knew, with what I discovered as I dug further.
(My original goal was to directly explain Brad's mysterious No such method '!cursor_start' message. I've failed for now, and have instead just filed a bug report, but here's what else I ended up with.)
Methods
Methods are designed to work naturally in classes. Indeed a method declaration without a scope declarator assumes has -- and a has declaration belongs inside a class:
method bar {} # Useless declaration of a has-scoped method in mainline
But in fact methods also work fine as either:
subs (i.e. not behaving as an object oriented method at all); or
methods for prototype-based programming (i.e. object orientation, but without classes).
What really makes methods methods is that they are routines with an "invocant". An invocant is a special status first parameter that:
Is implicitly inserted into the method's signature if not explicitly declared. If a method is declared inside a class, then the type constraint is that class, otherwise it's Mu:
class foo { my method bar {} .signature .say } # (foo: *%_)
my method bar {} .signature .say # (Mu: *%_)
Is a required positional. Thus:
my method bar {}
bar # Too few positionals passed; expected 1 argument but got 0
Is always aliased to self. Thus:
my method bar { say self }
bar 42 # 42
Is occasionally explicitly declared by specifying it as the first parameter in a signature and following it with a colon (:). Thus:
my method bar (Int \baz:) { say baz }
say &bar.signature; # (Int \baz: *%_)
bar 42; # 42
bar 'string'; # Type check failed in binding to parameter 'baz'
Regexes
Focusing just on the invocant perspective, regexes are methods that take/expect a match object as their invocant.
A regex is typically called in three somewhat different scenarios:
By direct use. For example my regex foo { . }; say 'a' ~~ &foo; # 「a」 (or just say 'a' ~~ / . /; # 「a」, but I'll only cover the essentially identical named example to simplify my explanation). This translates to say &foo.ACCEPTS: 'a'. This in turn is implemented by this code in Rakudo. As you can see, this calls the regex foo with the invocant Match.'!cursor_init'(...) -- which runs this code without :build. The upshot is that foo gets a new Match object as its invocant.
By way of the Grammar class's .parse method. The .parse method creates a new instance of the grammar and then calls the top "rule" (rule/token/regex/method) on that new grammar object. Note that a Grammar is a sub-class of Match; so, just as with the first scenario, the rule/regex is being passed an as-yet-empty match object. If the top rule matches, the new grammar/match object will be returned by the call to .parse. (Otherwise it'll return Nil.)
By way of one of the above. The top rule in a grammar will typically contain calls to lower level rules/tokens/regexes/methods. Likewise, a free standing rule/regex may contain calls to other rules/regexes. Each such call will involve creating another new grammar/match object that becomes the invocant for the nested call. If the nested call matches, and it's a capturing call, then the new grammar/match object is added to the higher level grammar/match object.

Related

Dynamically created class with invocant constraint

Official docs says that class can be built dynamically like so:
constant A := Metamodel::ClassHOW.new_type( name => 'A' );
A.^add_method('x', my method x(A:D:) { say 42 });
A.^compose;
A.new.x(); # x will be only called on instances
But what if I am building a class and don't assign it to a constant but rather store it in a var (for instance when I need to create a bunch of classes in loop) like so:
my $x = Metamodel::ClassHOW.new_type( name => 'some custom string' );
$x.^add_method('x', my method ($y:) { say $y });
$x.^compose;
But in this case I can call method x both on class ($x.x) and on instance ($x.new.x) though I want it to only be called on instances.
I tried to define method like so:
$x.^add_method('x', my method ($y:D:) { say $y });
but that produces an error:
Invalid typename 'D' in parameter declaration.
Of course I can check defindness of the value inside the method but I want some compile-time guarantees (I want to believe that type checking is done in compile time).
I tried to play with signatures and parameters but couldn't find a way to create an invocant parameter but what is more important I am not sure how to assign signature which I have in a variable to some method.
Change:
my $x = ...
to:
my constant x = my $ = ...
In full:
my constant x = my $ = Metamodel::ClassHOW.new_type( name => 'some custom string' );
x.^add_method('x', my method (x:D $y:) { say $y });
x.^compose;
x = Metamodel::ClassHOW.new_type( name => 'another custom string' );
...
I want some compile-time guarantees (I want to believe that type checking is done in compile time).
By making the constant's RHS be a variable declaration, you blend static compile-time aspects with dynamic run-time ones.
(BTW, the my before constant is just me being pedantic. A plain constant like you've used is equivalent to our constant which is less strict than my constant.)
I note the error message for a non-instance is different:
Type check failed in binding to parameter '$y';
expected type some custom string cannot be itself
At a guess that's because the usual message comes from Mu or Any and your class isn't inheriting from either of them.
I am not sure how to assign signature which I have in a variable to some method.
I'll leave that part unanswered.
The best way I can think of to produce a method with types substituted into a signature with Raku today is to use a parametric role to help out, like this:
my role Helper[::T] {
method foo(T $inv:) {}
}
my &meth = Helper.^parameterize(Int).^pun.^lookup("foo");
say &meth.signature;
Which outputs (Int $inv: *%_). Substitute Int with the type you are building.

Defining new infix operators in Raku

Please tell me how to define a new operator in Raku, for example, how would one implement an arrow operator defined something like this:
operator ▶ {my ($left, $right) = #_; $left->{$right}}
It's fairly simple:
sub infix:<▶> ($left, $right) {
$left."$right"()
}
# Example:
class Foo {
method bar { "hello" }
}
my $a = Foo.new;
say $a ▶ 'bar'
# hello
The sub infix:< > defines new infix operators (other options are prefix, postfix, circumfix, and postcircumfix, the latter two require an opening and closing part, like <( )> for open and close parentheses).
The ($left, $right), as the name suggests, handle the left and right side values.
To call a method based on an string, you use the structure ." "() with the method name in quotation marks and followed by parentheses — even if there are no arguments. In this case, we just insert the variable for basic interpolation, although more complex operations are possible.

Making a custom declarator

Let's say I use a certain set of boilerplate fairly regularly:
class Foo {
method abc($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
method xyz($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
method blarg($a: $b, $c, +#d) is pure {
use Slang::Bar;
…
}
}
I'd rather be able to just say:
class Foo is/does Bar {
bar abc { … }
bar xyz { … }
bar blarg { … }
}
And somewhere in Bar, set up the declaration for bar (or, since class Foo will itself ultimately use its own declarator, it could go somewhere else and doesn't have to be pulled out in a separate Type). How would I go about doing that?
-1. Limitations (only for packages)
The method EXPORTHOW calls .set_how on current $?LANG adding a slang to the latter.
Then it add_package_declarator to the MAIN $?LANG which adds a package_declarator method to its Actions and Grammar. It is, I think, the only "dynamic slang" (in World.nqp).
If what you want is to overwrite routine_declarator. Then you have to write a slang imitating the chain just cited.
If you accept to keep the method keyword and make the automatic signature in the class, say according to the method name, here is a way:
Note: A Package is a container (package, grammar, module, role, knowhow, enum, class, subset). If you put code inside like a method, this gets executed (I'v just tried):
0. Description (EXPORTHOW)
I would use undocumented EXPORTHOW and DECLARE in a module because I did not find a way with Phaser. Apparently it is too late even at BEGIN.
The example I give, is decorating every method in a class (even BUILDALL).
1. Lib (decorator.rakumod)
class DecoratedClassHOW is Metamodel::ClassHOW {
method add_method(Mu $obj, $name, $code_obj) {
sub wrapper ($obj, $a, $b) {
say "Before $name";
my $res = $code_obj($obj, $a, $b);
say "After $name";
return $res;
}
my $res = callwith($obj, $name, &wrapper);
return $res;
}
}
my module EXPORTHOW {
package DECLARE {
constant decorated = DecoratedClassHOW;
}
}
2. Executable
use lib '.';
use decorator-lib;
decorated Foo {
method abc($a, $b) {
say "In abc: $a:$b";
}
}
my $f = Foo.new;
$f.abc(1, 2);
3. Output
Before BUILDALL
After BUILDALL
Before abc
In abc: 1:2
After abc
4. Sources
Grammar::Debugger: exporting a symbol (grammar) overriding find_method and add_method
And npq's NQPTraceHOW::trace-on: Looping with for $_.HOW.method_table($_) creating a new hash overwriting the method cache with the (well-named) nqp::setmethcache.
To automatize the signature, play with .signature
Jnthn article on EXPORTHOW
So post on EXPORTHOW impossible with role

How to add a default method for an action class of a grammar?

Recently, I experimented with some grammars for modifying small parts of a
file. In those test cases, I would keep much
of the file as it was, only modifying small pieces here and there, see
this review question for an example.
So I needed one (or a few) action methods (i.e. methods in the action class of the
grammar) where I would attach the modified parts of the file to the
match object using its
make method. The problem was that the grammar itself would have many more
token/rules/regex with complicated
nesting. Hence, there was a need to propagate (by successively calling
make()) the small change (currently attached to
a token's match object) up to the TOP() method in the action class
such that everything
else (all other tokens/rules/regexes) in the file was kept untouched
in the result returned from the grammar's .parse() call.
So all methods in the action class except for one, was on the exact same form:
method make-data ($match-data) {
$match-data.make( [~] $match-data.chunks.map: {$_.value.?made // $_.value} );
}
Now, this explicit repetition of the same code for all action methods seems
to me very verbose, and also breaks with the DRY programming principle.
Is there a way to tell the grammar class that if an action method
(corresponding to a token in the grammar) is
not specified , it will default to the make-data method above (or a similar one)?
So in this case, I envision a DEFAULT() method in the action class:
method DEFAULT ($match-data) {
$match-data.make( [~] $match-data.chunks.map: {$_.value.?made // $_.value} );
}
that is called if a token in the grammar class does not have a
corresponding method in the action class.
Perl 6's Type system will call a FALLBACK method, if it's present in a class and an unknown method call is made.
The following solution adds default construction methods to the Calculations actions class.
grammar Calculator {
token TOP { [ <add> | <sub> ] }
rule add { <num> '+' <num> }
rule sub { <num> '-' <num> }
token num { \d+ }
}
class Calculations {
method ws($) {}
method FALLBACK($token, $match-data) {
$match-data.make( [~] $match-data.chunks.map: {
$_.value.?made // $_.value;
} );
}
}
say Calculator.parse('2 + 3', actions => Calculations).made;

Class slots vs. initialize signature mismatch

Consider the following S4 class:
setClass('Foo', representation(model='data.frame'))
setMethod('initialize', 'Foo',
function(.Object, a, b) {
.Object#model <- data.frame(a, b)
.Object
})
It can be instantiated with:
new('Foo', a=1:4, b=4:7)
So far so good. However, when I try to subclass Foo I get an error.
setClass('Bar', contains='Foo')
>>> Error in data.frame(a, b) : argument "a" is missing, with no default
Personally, I would prefer to instantiate class Foo with explicit arguments because the code is more... well, explicit. However, this does not seem possible, does it? It looks like the signature of initialize must match the slots that the class has, otherwise it's a problem waiting to happen. Am I wrong?
The requirement is that new called with no arguments, new("Foo"), must work. Also, it's probably better practice for your initialize method to take ..., to callNextMethod, and to have arguments after the ... (because initialize is documented to use unnamed arguments for initializing contained classes). So
setMethod(initialize, "Foo", function(.Object, ..., a=integer(), b=integer()) {
callNextMethod(.Object, ..., model=data.frame(a, b))
})
Normally one wants to insulate the user from calling new, and will instead use a constructor Foo. Typically the constructor does whatever coercion you might have instead put in the initialize method, so the initialize method is just not specified.
Foo <- function(a=integer(), b=integer(), ...) {
model <- data.frame(a, b)
new("Foo", model=model, ...)
}