Mailing List Archive

builtin: Is Lexical Export Idempotent?
TL;DR: If you `use builtin ...` multiple times in a row, do they count?
Or are they idempotent? This matters when you `no builtin ...` again.

-----

The `builtin` module performs exports lexically, not symbolically. This
means it inserts named functions in the lexical scope of its `use`
import, rather than just into the calling package. This is good for a
variety of reasons. E.g.

use builtin 'true';

We then added unimport, which removes them again, which is handy for a
few cornercases, and in particular useful if you want to remove *one*
awkward name from the overall version bundle, if you e.g. `use v5.40`.

use v5.40;
no builtin 'blessed';

All's good so far.

The implementation of hiding things in the pad again (the newly-added
"TOMBSTONE" flag) isn't currently very good, as it hides the names too
well. For example, most people would agree that combined, the two lines
like

use builtin 'true';
no builtin 'true';

should in effect do nothing, and in particular if a prior `true()`
function had been lexically visible, it should now remain so.

So, I've been working on a branch to make the implementation better. I
now have things like this working fine:

my sub true() { return "yes" }
use builtin 'true';
no builtin 'true';
is(true(), "yes");


But now I have hit a snag. There's a question around what it means to
import the same name multiple times in a row. For example:

use builtin 'true';
use builtin 'true';

What does this even mean? Has it been imported twice, or just once?

At this point, what would a single unimport operation do? Does it hide
both of the imports, or just one? What would people expect the
following to do?

my sub true() { return "yes" }
use builtin 'true';
use builtin 'true';
no builtin 'true';
say "TRUE is now " . true();

Does it print "yes", or "1"?

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
> At this point, what would a single unimport operation do? Does it hide
> both of the imports, or just one? What would people expect the
> following to do?
>
> my sub true() { return "yes" }
> use builtin 'true';
> use builtin 'true';
> no builtin 'true';
> say "TRUE is now " . true();
>

- get working "true" is overloaded - v5.38 shows:
"state" subroutine &true masks earlier declaration in same scope

- say should report undefined subroutine


> Does it print "yes", or "1"?
>
> --
> Paul "LeoNerd" Evans
>
> leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
> http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
>
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
On 25.01.24 19:30, Paul "LeoNerd" Evans wrote:
> TL;DR: If you `use builtin ...` multiple times in a row, do they count?
> Or are they idempotent? This matters when you `no builtin ...` again.

No counting. Idempotence only. Final Destination.

By analogy with other lexical pragmas:

use strict 'refs';
use strict 'refs';
no strict 'refs';
# strict refs should be off here

Or:

use warnings 'syntax';
use warnings 'syntax';
no warnings 'syntax';
# I don't want syntax warnings here

That's what I'd expect, at least.
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
On Thu, 25 Jan 2024 20:35:11 +0100
Lukas Mai <lukasmai.403+p5p@gmail.com> wrote:

> On 25.01.24 19:30, Paul "LeoNerd" Evans wrote:
> > TL;DR: If you `use builtin ...` multiple times in a row, do they
> > count? Or are they idempotent? This matters when you `no builtin
> > ...` again.
>
> No counting. Idempotence only. Final Destination.

Only ZUUL.

> By analogy with other lexical pragmas:
>
> use strict 'refs';
> use strict 'refs';
> no strict 'refs';
> # strict refs should be off here
>
> Or:
>
> use warnings 'syntax';
> use warnings 'syntax';
> no warnings 'syntax';
> # I don't want syntax warnings here
>
> That's what I'd expect, at least.

Righty. That makes sense I suppose.

In that case, since the version-bundle import has to check for symbols
the caller already has, I can just reuse that same logic here and
simplify the import time a bit.

That at least temporarily avoids the question earlier posed, so that's
good :)

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
On 25 Jan 2024, at 18:30, Paul LeoNerd Evans <leonerd@leonerd.org.uk> wrote:
[…]
> At this point, what would a single unimport operation do? Does it hide
> both of the imports, or just one? What would people expect the
> following to do?
>
> my sub true() { return "yes" }
> use builtin 'true';
> use builtin 'true';
> no builtin 'true';
> say "TRUE is now " . true();
>
> Does it print "yes", or "1”?

If I use Moose, which does a “use strict” for me, I still expect to be able to say

{
no strict "refs";
# Now do horrible things with the symbol table
...
}

Similarly, I would expect that saying both use builtin 'true' explicitly, and importing something that enabled it in my package, would just be belt and braces, rather than “I want true to be special so much that I have to disable it twice, just to be sure”.

Sam
--
Website: http://www.illuminated.co.uk/
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
On Thu, 25 Jan 2024 20:35:11 +0100, Lukas Mai <lukasmai.403+p5p@gmail.com> wrote:

> On 25.01.24 19:30, Paul "LeoNerd" Evans wrote:
> > TL;DR: If you `use builtin ...` multiple times in a row, do they count?
> > Or are they idempotent? This matters when you `no builtin ...` again.
>
> No counting. Idempotence only. Final Destination.
>
> By analogy with other lexical pragmas:
>
> use strict 'refs';
> use strict 'refs';
> no strict 'refs';
> # strict refs should be off here
>
> Or:
>
> use warnings 'syntax';
> use warnings 'syntax';
> no warnings 'syntax';
> # I don't want syntax warnings here
>
> That's what I'd expect, at least.


Me too
+n

--
H.Merijn Brand https://tux.nl Perl Monger http://amsterdam.pm.org/
using perl5.00307 .. 5.37 porting perl5 on HP-UX, AIX, and Linux
https://tux.nl/email.html http://qa.perl.org https://www.test-smoke.org
Re: builtin: Is Lexical Export Idempotent? [ In reply to ]
On Thu, 25 Jan 2024 18:30:58 +0000
"Paul \"LeoNerd\" Evans" <leonerd@leonerd.org.uk> wrote:

> TL;DR: If you `use builtin ...` multiple times in a row, do they
> count? Or are they idempotent? This matters when you `no builtin ...`
> again.

Thanks all for the many replies; universally everyone thinks it should
be idempotent and shouldn't count per call. This all seems reasonable,
and fits in well with other models.

To that end then, I have implemented some extra code and added some
more tests. Review comments welcome:

https://github.com/Perl/perl5/pull/21887

As a general reminder: I know not everyone will want to or be able to
review the C-level implementation parts, but if at least everyone who's
expressed an opinion on how it should behave could check that the
additional tests added here match up with their expectations of the
behaviour and comment as such on the PR, that'd be really handy.

--
Paul "LeoNerd" Evans

leonerd@leonerd.org.uk | https://metacpan.org/author/PEVANS
http://www.leonerd.org.uk/ | https://www.tindie.com/stores/leonerd/