The existing plan for "use v5.40" and the builtin functions has some problems.
builtin is intended to have version bundles similar to features, which
would include all of the stable builtin functions for that version.
And we wanted "use v5.40;" to import the builtin bundle for that
version. Currently, multiple "use vX.XX;" statements can be used, and
using an older version after a newer one will reset all features to
match that older version. This presents a problem for the builtin
functions.
Going to an older version would require removing the builtin
functions. In fact, going to a newer version could require removing
builtin functions as well (we've removed features from version bundles
before). But builtin functions are exported as lexical subs. We don't
currently have a well defined concept of removing a lexical. Paul has
implemented a version of this, but its behavior is rather confusing
and the semantics of it aren't obviously correct.
Removing a lexical is a weird feature and I'm not convinced we want it
to be part of the language. If it's something we really want, I think
it needs much more thought and needs to work generally (at least in
concept), not just be an implementation detail of builtin. I feel that
the current implementation is definitely wrong, but fixes to it would
conflict with things others have argued for.
If we can't remove lexicals, builtin::unimport isn't possible, and
importing builtin via use vX.XX can't work with the current semantics
of use vX.XX because they require the ability for changes to be
undone. Even if removing lexicals was possible, those semantics don't
cleanly allow the "reset to defaults" behavior of "use vX.XX".
I see a few possible solutions
1. Make removing lexicals make sense.
2. Don't use lexical exports for builtin. They would need a
different mechanism, likely a new type of visibility. This would end
up similar to how 'say' currently works.
3. Stop allowing "use vX.XX" to be used multiple times in the same
scope. If there is only ever a single transition from 5.8 semantics to
5.new semantics, we never have to remove builtins.
I've already explained that I don't think removing lexicals makes much
sense, and doesn't apply cleanly to "use vX.XX".
For solution #2, we would need to extend the experimental phase of
builtin exports. builtin itself can still become stable. This would
result in builtin being another special case internally, which is not
really in line with its original design goals. But there have been
some general concerns about lexical subs being confusing regarding
shadowing and redefinition. Problems that become worse with exporting
as it makes the lexical nature less obvious.
My preference is solution #3. I don't think there is actually a
valuable use case for using multiple version declarations in the same
file. And if there really is a need, they can be kept in entirely
separate scopes. Doing this would mean deprecating any use of "use
X.XX" in an overlapping scope. And if either version used was >= 5.40,
throw an error. I feel this would also allow simplifying the
documentation for use, which is currently rather long and confusing. I
would like to deprecate and eventually disallow this even if you are
going from an older to a newer version, as it would allow functions to
be removed from a builtin version bundle.
The next dev release is the cut off for contentious changes, on Feb
20. I think this needs to be resolved in some way before then. If not,
I think builtin exports would need to be returned to experimental
status.
builtin is intended to have version bundles similar to features, which
would include all of the stable builtin functions for that version.
And we wanted "use v5.40;" to import the builtin bundle for that
version. Currently, multiple "use vX.XX;" statements can be used, and
using an older version after a newer one will reset all features to
match that older version. This presents a problem for the builtin
functions.
Going to an older version would require removing the builtin
functions. In fact, going to a newer version could require removing
builtin functions as well (we've removed features from version bundles
before). But builtin functions are exported as lexical subs. We don't
currently have a well defined concept of removing a lexical. Paul has
implemented a version of this, but its behavior is rather confusing
and the semantics of it aren't obviously correct.
Removing a lexical is a weird feature and I'm not convinced we want it
to be part of the language. If it's something we really want, I think
it needs much more thought and needs to work generally (at least in
concept), not just be an implementation detail of builtin. I feel that
the current implementation is definitely wrong, but fixes to it would
conflict with things others have argued for.
If we can't remove lexicals, builtin::unimport isn't possible, and
importing builtin via use vX.XX can't work with the current semantics
of use vX.XX because they require the ability for changes to be
undone. Even if removing lexicals was possible, those semantics don't
cleanly allow the "reset to defaults" behavior of "use vX.XX".
I see a few possible solutions
1. Make removing lexicals make sense.
2. Don't use lexical exports for builtin. They would need a
different mechanism, likely a new type of visibility. This would end
up similar to how 'say' currently works.
3. Stop allowing "use vX.XX" to be used multiple times in the same
scope. If there is only ever a single transition from 5.8 semantics to
5.new semantics, we never have to remove builtins.
I've already explained that I don't think removing lexicals makes much
sense, and doesn't apply cleanly to "use vX.XX".
For solution #2, we would need to extend the experimental phase of
builtin exports. builtin itself can still become stable. This would
result in builtin being another special case internally, which is not
really in line with its original design goals. But there have been
some general concerns about lexical subs being confusing regarding
shadowing and redefinition. Problems that become worse with exporting
as it makes the lexical nature less obvious.
My preference is solution #3. I don't think there is actually a
valuable use case for using multiple version declarations in the same
file. And if there really is a need, they can be kept in entirely
separate scopes. Doing this would mean deprecating any use of "use
X.XX" in an overlapping scope. And if either version used was >= 5.40,
throw an error. I feel this would also allow simplifying the
documentation for use, which is currently rather long and confusing. I
would like to deprecate and eventually disallow this even if you are
going from an older to a newer version, as it would allow functions to
be removed from a builtin version bundle.
The next dev release is the cut off for contentious changes, on Feb
20. I think this needs to be resolved in some way before then. If not,
I think builtin exports would need to be returned to experimental
status.