7

I want to use Raku Modules to group some functions, I often use. Because these functions are all loosely coupled, I don't like to add them in a class.

I like the idea of use, where you can select, which functions should be imported, but I don't like it, that the functions, which are imported are then stored in the global namespace.

For example if I have a file my_util.pm6:

#content of my_util.pm6
unit module my_util;
our sub greet($who) is export(:greet) {
    say $who;
}
sub greet2($who) is export(:greet2) {
    say $who;
}
sub greet3($who) is export(:greet3) {
    say $who;
}

and a file test.p6:

#!/usr/bin/perl6
#content of test.p6
use v6.c;
use lib '.';
use my_util :greet2;

greet("Bob");    #should not work (because no namespace given) and also doesn't work
greet2("Bob");   #should not work (because no namespace given) but actually works
greet3("Bob");   #should not work (because no namespace given) and also doesn't work
my_util::greet("Alice");     #works, but should not work (because it is not imported)
my_util::greet2("Alice");    #should work, but doesn't work
my_util::greet3("Alice");    #should not work (because it is not imported) and also doesn't work

I would like to call all functions via my_util::greet() and not via greet() only.

The function greet() defined in my_util.pm6 comes very close to my requirements, but because it is defined as our, it is always imported. What I like is the possibility, to select which functions should be imported and it should be possible to leave it in the namespace defined by the module (i.e. it doesn't pollute the global namespace)

Does anyone know, how I can achieve this?

Braiam
  • 4,345
  • 11
  • 47
  • 69
byteunit
  • 961
  • 4
  • 13

1 Answers1

7

To clear up some potential confusion...

Lexical scopes and package symbol tables are different things.

  1. my adds a symbol to the current lexical scope.

  2. our adds a symbol to the current lexical scope, and to the public symbol table of the current package.

  3. use copies the requested symbols into the current lexical scope.
    That's called "importing".

  4. The :: separator does a package lookup – i.e. foo::greet looks up the symbol greet in the public symbol table of package foo.
    This doesn't involve any "importing".

As for what you want to achieve...

The public symbol table of a package is the same no matter where it is referenced from... There is no mechanism for making individual symbols in it visible from different scopes.

You could make the colons part of the actual names of the subroutines...

sub foo::greet($who) is export(:greet) { say "Hello, $who!" }
# This subroutine is now literally called "foo::greet".

...but then you can't call it in the normal way anymore (because the parser would interpret that as rule 4 above), so you would have to use the clunky "indirect lexical lookup" syntax, which is obviously not what you want:

foo::greet "Sam";          # Could not find symbol '&greet'
::<&foo::greet>( "Sam" );  # Hello, Sam!

So, your best bet would be to either...

  • Declare the subroutines with our, and live with the fact that all of them can be accessed from all scopes that use the module.
    Or:
  • Add the common prefix directly to the subroutine names, but using an unproblematic separator (such as the dash), and then import them normally:
unit module foo;
sub foo-greet($who)  is export(:greet)  { ... }
sub foo-greet2($who) is export(:greet2) { ... }
sub foo-greet3($who) is export(:greet3) { ... }
smls
  • 5,478
  • 21
  • 27
  • 1
    Thank you very much for your detailed answer, now I know, tat it is not directly possible. I' coming from the C++ world where we don't like it much, if all is the current scope, but I can't imagine that I'm the only one, who adresses this problem. Do you know if it is planned in the future or where I can suggest this feature? – byteunit Aug 19 '17 at 12:36
  • 1
    @byteunit: "Importing without namespace prefix" (i.e. `using namespace`) is shunned in C++ because it causes big problems there, due to the way symbol lookup works there. But it's not really a problem in Perl 6, especially if you use fine-grained export tags. I guess you'll just have to unlearn C++ best practices and learn Perl 6 best practices... :) – smls Aug 19 '17 at 13:38
  • @byteunit: Also, as my answer says, defining your subroutines with `our` and using the `foo::greet` (package lookup) syntax, doesn't cause any symbol imports at all. Since package names are guaranteed to be unique in any given scope in Perl 6, that too is perfectly safe. What downsides do you see? – smls Aug 19 '17 at 13:43
  • @byteunit: You can always send a feature request to the Rakudo Perl 6 [bug tracker](http://rakudo.org/tickets/), but AFAIK these things work as intended by the Perl 6 language designers, and I doubt a feature to make lexical imports look like package lookups will be implemented. – smls Aug 19 '17 at 13:51
  • What if you don't `is export`? What would be the name of foo::greet? – jjmerelo May 01 '19 at 09:12