Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid importing default symbols when using a module?

Tags:

raku

I am going to use Hash::Merge as an example. Consider:

use v6;
use Hash::Merge; # <-- imports all symbols marked with "is export" from Hash::Merge
my %hash1 = a1 => [1, 2, 3], b => "xxx", c => { ca => 1 }, e => 5;
my %hash2 = a1 => [1, 5, 3], b => "yyyy", c => { ca => 5, f => "a" }, d => 4;
my %res = merge-hash(%hash1, %hash2, :no-append-array);

Suppose I do not want to pollute my name space when using a module (here Hash::Merge is used as an example). I could achive this in Perl 5 by specifying an empty argument list to use:

use Hash::Merge ();   # <-- No symbols will be imported into the current namespace

Then I would call the sub routine merge-hash using its fully qualified name: Hash::Merge::merge-hash.

According to this bug report it seems like this is not possible in Perl 6. Is this correct?

like image 262
Håkon Hægland Avatar asked Mar 31 '19 11:03

Håkon Hægland


2 Answers

To load a module without importing, use need instead:

need Hash::Merge;

In the case of the module in question, it does not declare the things it exports with our, which unfortunately means that calling it as:

Hash::Merge::merge-hash(...)

Will not work, since it's not installed in the package. However, it is still possible to dig the symbol out of the exports manually:

need Hash::Merge;
say Hash::Merge::EXPORT::DEFAULT::merge-hash({ a => 1 }, { b => 2 })

And, for more convenience, it can be aliased:

need Hash::Merge;
my constant &merge-hash = &Hash::Merge::EXPORT::DEFAULT::merge-hash;
say merge-hash({ a => 1 }, { b => 2 });

There is a speculated syntax along the lines of use Hash::Merge :MY<&merge-hash>, which is not implemented in current Perl 6 versions, but would probably have the same semantics as the constant trick shown here.

like image 97
Jonathan Worthington Avatar answered Sep 25 '22 12:09

Jonathan Worthington


A simple way to deal with this is to just put the use of the module in a block.

{ use Hash::Merge }

Since the {} defines a scope, nothing escapes it.

You can get it so that something can escape by placing it in a do block.

do { use Hash::Merge }

What you can do then is have it so that the values you care about get stored in the correct places.

my &merge-hash = do { use Hash::Merge; &merge-hash }
my (&merge-hash,&merge-hashes) = do { use Hash::Merge; (&merge-hash, &merge-hashes) }

Another option is to just place it in as small a scope as possible.

my %a = a => 1;
my %b = b => 2;

my %c;
{
  use Hash::Merge;
  %c := merge-hash %a, %b
}

or

my %c := do {
  use Hash::Merge;
  merge-hash %a, %b
}

(The binding operator := was just used because the result of merge-hash is already a hash.)

like image 44
Brad Gilbert Avatar answered Sep 22 '22 12:09

Brad Gilbert