Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symbols that start with core namespaces always get exported #1458

Open
zoffixznet opened this issue Jan 31, 2018 · 11 comments
Open

Symbols that start with core namespaces always get exported #1458

zoffixznet opened this issue Jan 31, 2018 · 11 comments

Comments

@zoffixznet
Copy link
Contributor

If I name my subset IO::Path::Foo, the export tag is basically ignored and the subset always gets exported:

<Zoffix__> m: BEGIN with '/tmp/subz'.IO.mkdir { .add('ZS.pm6').spurt: 「my subset IO::Path::Foo is export(:e) where 42」 }; use lib </tmp/subz/>; use ZS; say 42 ~~ IO::Path::Foo
<camelia> rakudo-moar ed9b287c9: OUTPUT: «True␤»

It works as expected for paths that don't match anything core:

<Zoffix__> m: BEGIN with '/tmp/subz'.IO.mkdir { .add('ZS.pm6').spurt: 「my subset Foo is export(:e) where 42」 }; use lib </tmp/subz/>; use ZS; say 42 ~~ Foo
<camelia> rakudo-moar ed9b287c9: OUTPUT: «===SORRY!=== Error while compiling <tmp>␤Undeclared name:␤    Foo used at line 1␤␤»

<Zoffix__> m: BEGIN with '/tmp/subz'.IO.mkdir { .add('ZS.pm6').spurt: 「my subset Foo is export(:e) where 42」 }; use lib </tmp/subz/>; use ZS :e; say 42 ~~ Foo
<camelia> rakudo-moar ed9b287c9: OUTPUT: «True␤»
@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

Note that this isn't anything to do with export really, it's about how symbol tables work. A declaration like my subset Foo::Bar will first look for an existing Foo package to install under. If it finds it, it will then take it's stash (.WHO) and install Bar into there (checking there's not a re-decl). The my only applies (and can only possibly apply) to the first component, which will be created and installed in the current lexical scope the attempt to resolve it in the first place fails. With IO however, it finds the existing package in CORE and installs it under that.

What if we decided to do differently and insist that even if an outer Foo exists, we will simply install a fresh my package Foo {} into the current lexical scope? In that case, we'd end up hiding the Foo from the outer scope (or, in your specific example, hiding the CORE IO package and forcing everyone to write CORE::IO::Path afterwards).

@zoffixznet
Copy link
Contributor Author

So this is all By Design?

Spamming all private symbols into the user's namespace the second the user uses some module we also happen to use is a serious flaw in the language IMO 😨

Somehow we managed to allow multiple authors to publish modules with the same name, yet using a namespace another module might be using causes a conflict. I was gonna release a module that provides IO::Path::* subsets, but this bug prevents its proper use. I could rename them all to Path::*, but that will all blow up the second someone decides to add a Path:: namespace to core.

Not to mention all X:: for exceptions is now messed up too.

$ cat Foo.pm6 
my subset Foo is export where *;

$ cat Foo/Two.pm6 
use Foo;
my subset Foo::Two where *;

$ perl6 -I. -MFoo::Two -e 'say 42 ~~ Foo::Two'
Could not find symbol '&Two'
  in block <unit> at -e line 1

$ perl6 -I. -MFoo -MFoo::Two -e 'say 42 ~~ Foo::Two'
True

@lizmat
Copy link
Contributor

lizmat commented Jan 31, 2018 via email

@vendethiel
Copy link
Contributor

Spamming all private symbols into the user's namespace the second the user uses some module we also happen to use is a serious flaw in the language IMO 😨

Rather, isn't it just that you're reopening IO::Path and adding a subset to it? Extending a package doesn't change its visibility/export rules.

[11:56] <Ven``> m: my package UserPkg {}; BEGIN with '/tmp/subz'.IO.mkdir { .add('ZS.pm6').spurt: package UserPkg {}; my subset UserPkg::Foo is export(:e) where 42 }; use lib </tmp/subz/>; use ZS; say 42 ~~ UserPkg::Foo
[11:56] <camelia> rakudo-moar ed9b287c9: OUTPUT: «True␤»

@cuonglm
Copy link
Contributor

cuonglm commented Jan 31, 2018

IIRC, this also affects multi sub is exported by default even only one of them is marked as is export. There's a RT for it, though.

@niner
Copy link
Collaborator

niner commented Jan 31, 2018 via email

@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

But that would only be applicable in the lexical scope where this new IO is installed, no?

Yes.

Still not ideal, but not as “global” as you appear you claim it to be?

I never claimed it was global, just that it'd be a decided impact.

@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

Rather, isn't it just that you're reopening IO::Path and adding a subset to it?

Yes, except there's no explicit re-opening because stashes are always open to poke symbols in to.

@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

There's a third option: install a fresh package Foo lexically but give it a
reference to the outer Foo for fallback symbol lookup. Kinda like the already
existing global_fallback in Stash's AT-KEY.

I've pondered that before, and we could indeed do that, yes. It would complicate lookup some, but since most of those take place at compile time, it's not a big issue.

@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

So this is all By Design?

Well, The Design was more a wish list of things that should work, and what's implemented today is the best realization of it that we have so far. There's certainly room for refinement.

In general, there's long been a tension between our-scope and GLOBAL versus the heavy reliance on lexical scoping elsewhere in the language. The is export mechanism is all about lexical stuff. The setting's symbols are resolved lexically. But modules, classes, etc. by default install with our scope. At the top level, they install into GLOBALish which is then merged at need-time (note how this is a distinct step from import, and use is need + import). And the point of GLOBAL is that it's, well, global.

@jnthn
Copy link
Member

jnthn commented Jan 31, 2018

IIRC, this also affects multi sub is exported by default even only one of them is marked as is export.

This one, thankfully, should be a separate, and much more easily resolved, issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants