Skip to content

Instantly share code, notes, and snippets.

@lucs
Last active February 21, 2023 17:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lucs/cc60e0b0f6a34df09b5bf7bf704da061 to your computer and use it in GitHub Desktop.
Save lucs/cc60e0b0f6a34df09b5bf7bf704da061 to your computer and use it in GitHub Desktop.
Renaming an exported sub
# --------------------------------------------------------------------
#`(
I have 「A.rakumod」 which exports two multi variations of
subroutine 「orig」. I would like the user to be able to do for
example 「use A 'mine'」, so that they can invoke the exported subs
with some other arbitrary name instead.
)
# --------------------------------------------------------------------
# First, failing, attempt
# A.rakumod:
class A {
multi sub orig (Int $n) is export { $n * 2 }
multi sub orig (Str $s) is export { $s ~ $s }
}
sub EXPORT ($new-name?) {
Map.new: do "&$new-name" => &A::orig if $new-name;
}
# main.raku:
use lib '.';
# This would work, as expected:
# «42meepmeep».
#use A; say orig(21) ~ orig("meep");
# But this would print the wrong thing, not quite sure what's
# going on:
# «21meep».
#use A 'mine'; say mine(21) ~ mine("meep");
# --------------------------------------------------------------------
# Correct way
#`(
Nahita, in the #raku-irc channel of the Raku Discord server,
explains:
"only slight change is needed. problem is, A::orig is not
really accessing the &orig residing inside the class A because
subroutines are "my"-scoped, i.e., lexical by default. So to
attach that symbol to the class, you can "our"-declare it
instead. In multis, it wants an our-declared proto".
)
# They then show how to fix the module, as follows:
# A.rakumod:
class A {
our proto sub orig(|) is export {*}
multi sub orig (Int $n) { $n * 2 }
multi sub orig (Str $s) { $s ~ $s }
}
sub EXPORT ($new-name?) {
Map.new: do "&$new-name" => &A::orig if $new-name;
}
# We then have:
# main.raku:
use lib '.';
# This would keep on working:
# «42meepmeep».
#use A; say orig(21) ~ orig("meep");
# But this would of course trigger an "Undeclared
# routine" error.
#say mine(21) ~ mine("meep");
# But now this would also work:
# «42meepmeep».
#use A 'mine'; say mine(21) ~ mine("meep");
# And 'orig' would now be an "Undeclared routine".
#say orig(21) ~ orig("meep");
# But note that this is still in scope, «42meepmeep».
#say A::orig(21) ~ A::orig("meep");
# Interestingly, "use"ing 'A' in both variations, in any order
# would make both 'orig' and 'mine' visible. For example:
# «42meepmeep».
#say orig(21) ~ mine("meep");
#use A 'mine';
#use A;
# --------------------------------------------------------------------
# Another, perhaps simpler, approach was suggested by cfa in the raku
# channel on Libera. By not using 'our', it avoids making A::orig
# visible when a different name is wanted.
# A.rakumod:
my $orig;
class A {
proto sub orig(|) is export {*}
$orig = &orig;
multi sub orig (Int $n) { $n * 2 }
multi sub orig (Str $s) { $s ~ $s }
}
sub EXPORT ($new-name?) {
Map.new: do "&$new-name" => $orig if $new-name;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment