Last active
February 21, 2023 17:07
-
-
Save lucs/cc60e0b0f6a34df09b5bf7bf704da061 to your computer and use it in GitHub Desktop.
Renaming an exported sub
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -------------------------------------------------------------------- | |
#`( | |
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