iner and its host application, but I think for *those* it is
safe to list individual items, because you're not trying to pull their
dependencies, just point to the right piece of code.
Rowan Tommins
[IMSoP]
D{ public function foo(): never {} }
That seems reasonable enough; I may have missed something important, though.
Regards,
--
Rowan Tommins
[IMSoP]
file system wrapper; you still have to include/require
the individual files inside the archive, and they're still compiled in
exactly the same way.
Whether we want to isolate "any definition you find in the directory
/var/www/wordpress/wp-plugins/foo/" or "any definition you find in the
Phar archive phar:///var/www/wordpress/wp-plugins/foo.phar", the tricky
part is how to do the actual isolating.
--
Rowan Tommins
[IMSoP]
kage ever written. Probably
some caveats where dynamic code can accidentally escape the container.
Completely separate from the kind of "module" you and Arnaud were experimenting
with.
Rowan Tommins
[IMSoP]
ses, but at this point every JS
module going back 15+ years (CommonJS was founded in 2009, to
standardise existing practices) is based on the "interact by export"
model; and every PHP package going back 25+ years (PEAR founded in 1999;
Composer in 2011) is based on the "interact by name" model.
--
Rowan Tommins
[IMSoP]
al" flag as they are if they use reflection or
code-rewriting to ignore/remove the "private" flag.
Rowan Tommins
[IMSoP]
quot;@internal" annotations, or
future "module private" declarations, and make whatever other changes are
needed to suit your use case.
Regards,
Rowan Tommins
[IMSoP]
his was suggested a couple of times on the previous thread. It
would be a useful feature, but probably not easy to implement efficiently and
integrate thoroughly into the language.
Regards,
Rowan Tommins
[IMSoP]
t;export", any reference to
any class name is prefixed in the same way, and loaded with the isolated
autoloader stack. To the host application, and any other plugins, the
code inside the "wp-plugins/AlicesCalendar/vendor" and
"wp-plugins/BobsDocs/vendor" directories is entirely hidden.
--
Rowan Tommins
[IMSoP]
r/www/wordpress/wp-plugins/AlicesCalendar/vendor/autoload.php';
// The plugin is registered to the application, which doesn't need to
know about the Container setup
wp_register_plugin('\AlicesCalendar\PluginDefinition');
// In a completely separate file, BobsDocs does al
portantly, all of this should happen on the *PHP symbol* level (classes,
interfaces, functions); the sandboxing mechanism doesn't need to know about
package managers - just as Docker, Kunernetes, etc, don't know about APT / Yum
/ whatever Apine calls it.
Rowan Tommins
[IMSoP]
isting code to change from one to the other, especially
since they won't be able to for several years if they support multiple PHP
versions.
As for other languages, they use all sorts of different keywords for the same
or similar features, e.g. "import" and "using", so
". All the classes
that are "inside" are completely sandboxed from the classes "outside", without
needing any interaction with a package manager.
As far as I know, this is how existing userland solutions work, and I haven't
yet spotted a reason why it needs to be any more complex than that.
Regards,
Rowan Tommins
[IMSoP]
wing, or whatever) we need some requirements of *what* we want to
rewrite. By suggesting an image of "containers" or "sandboxes" rather
than "packages" or "modules", I was trying to define the requirement
that "AlicesCalendar and BobsDocs are special, in a way that
monolog/monolog and google/apiclient are not".
--
Rowan Tommins
[IMSoP]
On 21 May 2025 13:26:27 BST, "Rowan Tommins [IMSoP]"
wrote:
>
>My understanding of the example is that there are two WordPress plugins, which
>want independent sets of Composer dependencies. There might be 20 different
>Composer packages used by each plugin, but tho
ged, and you can use whatever dependencies you want without waiting for
them to be changed to a new way of working, is that not a good thing?
I've tried several times to explain why I think Linux containers are a good
analogy; I'm not sure if you didn't understand, or just didn't ag
any de-duplication of files on disk
that a package manager might perform. It's a bit like the same C source file
being compiled into two different object files with different #defines in
effect.
I'm still not convinced that all this complexity actually leaves you better off
than building a Composer plugin that automatically applies the rewriting to a
whole directory at source code level.
Rowan Tommins
[IMSoP]
erty to
a new value
The question then is, how worried are we about that scenario?
--
Rowan Tommins
[IMSoP]
for Linux containers as an alternative
analogy, to think about the problem without jumping to the wrong solution.
Rowan Tommins
[IMSoP]
sses") but that's
a completely separate concept.
I wasn't saying the feature had to be called "containers", just that the
analogy might be useful.
Rowan Tommins
[IMSoP]
ot just plugin1 itself, but all the third-party code it calls, into
some kind of sandbox, as though it was running in a separate process. If you
can control what classes can go into and out of that sandbox, then in any piece
of code, you don't end up with conflicting meanings for the same name - just as
a Linux container can't open a network port directly on the host.
Regards,
Rowan Tommins
[IMSoP]
;containers", in the sense of Docker, Kubernetes, etc, where
different sections of code can be isolated, and declare classes with
conflicting fully-qualified names. I don't think it's what most applications
and libraries would want "modules" to be; it's probably best thought of as a
completely separate feature.
--
Rowan Tommins
[IMSoP]
On 7 May 2025 21:51:29 BST, Michael Morris wrote:
>On Wed, May 7, 2025 at 3:24 PM Rowan Tommins [IMSoP]
>wrote:
>
>Other libraries have the means to import into a namespace because their
>namespaces aren't just a quick and dirty string replacement. I've even
>pro
not* think that allowing multiple versions of the same
library should be a core requirement of any native module support;
enabling userland to achieve it efficiently would be a nice to have.
--
Rowan Tommins
[IMSoP]
adowing would instantly become
a conflict anyway; and I can't picture how "protected" would work.
--
Rowan Tommins
[IMSoP]
ed against the benefit, but not a blocker
in itself.
--
Rowan Tommins
[IMSoP]
x of the library.
Probably they will be currently marked "@internal" or highlighted in
documentation in some way, to indicate that they are not intended as part of
the public API; the only difference will be that now you'll get an error if you
ignore that documentation.
Rowan Tommins
[IMSoP]
class' class name that is
>marked `@internal`.
The value-add is 1) that they enforce the visibility at the language level, and
2) that they allow a concise syntax for declaring a set of closely related
classes.
I'm not wholly convinced that they do that better than "file private" or
"module private", but I don't agree that "class hiding" is essential, or even
particularly desirable.
Rowan Tommins
[IMSoP]
re
some use cases would be possible, and some would have easier work arounds than
today. Possibly we could slowly add places the syntax is allowed, where we can
make it make sense without tackling the tricky parts like variance/inheritance
and type inference.
Rowan Tommins
[IMSoP]
o a separate RFC" does not mean "released in a different
version of PHP", it just means "has more space to discuss details". There's so
much to decide here, that we should take any chance we can to break it into
smaller pieces.
Rowan Tommins
[IMSoP]
other comment at a very quick glance is that I see the Context section
is still included, and still has most of its complexity. As I said about the
previous drafts, this seems to be an optional extra that can and should be
proposed in a follow-up.
Thanks again for your hard work, but let's not rush this.
Rowan Tommins
[IMSoP]
e line
where Closure::getCurrent() is called.
--
Rowan Tommins
[IMSoP]
ture it into another closure
$bOutside = function() use ($aInside) {
// Get a self-reference in that one too
$bInside = Closure::getCurrent();
// Do whatever you like with $aInside and $bInside
};
};
Rowan Tommins
[IMSoP]
mance and
side-effects of capturing the original values. This wouldn't solve the
sensitive information problem, though, so I'm not sure how good an idea
it would be.
--
Rowan Tommins
[IMSoP]
s, or the state of opaque objects and resources like file/stream
handles.
Collecting arguments seems like a special case which could be handled by
debug or APM extensions, rather than something that most users will ever
need.
--
Rowan Tommins
[IMSoP]
ve never used
it or seen it used; normally, trim($foo)==='' (or trim($foo??'')==='') seems to
be good enough.
Rowan Tommins
[IMSoP]
le $fn, mixed ...$fixedArgs): callable {
return fn(mixed $firstArg) => $fn($firstArg, ...$fixedArgs);
}
// first-arg chaining
$someChain |> array_filter(fn($v, $k) => $k === $v, ARRAY_FILTER_USE_BOTH);
// native partial application
$someChain |> array_filter(?, fn($v, $k) => $k === $v,
ARRAY_FILTER_USE_BOTH);
// workaround
$someChain |> partial_first(array_filter(...), fn($v, $k) => $k === $v,
ARRAY_FILTER_USE_BOTH));
--
Rowan Tommins
[IMSoP]
h of
statements I want to run in a new Coroutine, but they're not worth putting in a
function". So to the user, having all the features of a function isn't
relevant. We don't allow specifying the return type of a match statement, for
example.
Do you have a different scenario in mind?
Rowan Tommins
[IMSoP]
ly implemented extension
methods instead of pipes, and then the new iterator API was
extension-method-only. It feels less like "one of the arguments is
missing" if that argument is *always* expressed as the left-hand side of
an arrow or some sort.
--
Rowan Tommins
[IMSoP]
ded up
how they did.
--
Rowan Tommins
[IMSoP]
he description of traits (they would no longer
just be copied and pasted code), and would lead to additional questions (e.g.
what happens when the target class changes the visibility with an "as" clause?).
Any inconsistent behaviour should have to clear a high bar.
Rowan Tommins
[IMSoP]
or a property.
I see no reason for inheritance to be involved at all. If we want an access
level that means "accessible from any code in this file, or any subclass of the
current type", we can make up a keyword for that as well - "fileprotected", or
"fileprivate_or_protected", or whatever.
Rowan Tommins
[IMSoP]
t.
A "fileprivate"/"samefile" keyword would be pasted into the file it was used
in, and mean accessible within that file; it wouldn't matter what file the
trait was defined in. It would probably be useless, but lots of useless code is
possible in any language.
Besides, all these questions have to be answered for nested classes as well.
Just because you've reused the keyword "private" rather than adding
"private_or_nested", you still have to define exactly what it does and doesn't
allow access from in these new scopes.
Rowan Tommins
[IMSoP]
On 25 March 2025 18:14:21 GMT, Daniel Scherzer
wrote:
>On Tue, Mar 25, 2025 at 11:01 AM Rowan Tommins [IMSoP]
>wrote:
>
>>
>> I don't think the language should pretend to support something that it
>> doesn't
>>
>
>I don't see what the pr
On 25 March 2025 16:42:45 GMT, Robert Chapin wrote:
>On 3/25/2025 4:45 AM, Rowan Tommins [IMSoP] wrote:
>> The implied default in the first is 'off', but in the second it's 'on'.
>I thought the implied default was null.
By "implied", I'm
coalesce($_POST['tick']) != 0) return;
But this doesn't:
if (coalesce($_POST['tick']) !== 0) return;
By specifying the default explicitly, we don't have to examine the expression
carefully to see what's implied.
I don't know if I'd go as far as banning a single-argument coalesce, but I
would definitely discourage its use.
Rowan Tommins
[IMSoP]
choice - { contains, contained by, neither }.
File scope gives us instead the dimension { same file, different file }; and
module scope gives us { same module, different module, no module }, and maybe
some additional relationships between modules.
Rowan Tommins
[IMSoP]
because it's mostly just
reminding you to include a pair of parentheses:
if (($_POST['input'] ?? null) === 'yes') echo 'success';
if (coalesce($_POST['input']) === 'yes') echo 'success';
if (coalesce($_POST['input'], null)
extend current
functions to handle IRIs?", I'd start from the point of "what functions do we
need for handling URI/URL/IRI parts, and what variations of each?"
Rowan Tommins
[IMSoP]
function signature because it used to directly overwrite variables by name.
As a comparison, we didn't extend the shuffle() function with an
algorithm parameter, we added a shuffleArray() method to the new
Randomizer class.
--
Rowan Tommins
[IMSoP]
the contract in a docblock:
/**
* @template T
* @method compareTo(T $other): int;
*/
interface Comparable {
}
/** @implements Comparable */
final class Number implements Comparable {
public function compareTo(Number $other): int { return $this
<=> $other; }
}
--
Rowan Tommins
[IMSoP]
n, though, this could easily be added later when a need becomes
visible, as long as we don't do something weird now that closes the door
on it.
I suggest we leave this sub-thread here; there's plenty of other things
to discuss. :)
--
Rowan Tommins
[IMSoP]
se: it will be used frequently.
Will it? By who, when? Honest question, and comes back to my point about
identifying the use case.
>For example, `spawn fn() => file_get_content()` won’t be, because it
>doesn’t make sense.
If return values end up somewhere, I don't think it would be hard to come up
with examples that were slightly more than one function call, but still fit in
a single-expression closure.
Rowan Tommins
[IMSoP]
f the aim is "a readable way to use a closure", rule #2 is fine.
Yes, it means some extra parentheses if you squeeze it all into one
statement, but it's probably more readable to assign the closure to a
temporary variable anyway:
// Legal under rule #2, but ugly
spawn (function() us
actoring like moving that
declaration into a variable.
If it's going to be a special case for an "inline coroutine", just use a
keyword other than "function", so it doesn't look like an expression when it's
not, like "spawn block { ... }"; or no keyword at all, just "spawn { ... }"
Rowan Tommins
[IMSoP]
eted as if `something` is a PHP constant rather than a
>function.
It's more fundamental than that: function_call and expr are overlapping
grammars, so having a rule that spawn can be followed by either of them, with
different meanings, leads to ambiguities. You can carefully tune the grammar to
avoid those, but then the user has to learn those rules; or you can just use
two keywords, which I don't remember you actually responding to as a suggestion.
Rowan Tommins
[IMSoP]
est("string");
Or forget callables, and anything that looks like it's trying to be one,
because creating a Closure isn't actually the user's aim:
spawn_this_function_call_without_creating_a_closure test("string");
spawn_these_statements_use_a_closure_if_you_like_i_dont_care {
do_something();
do_something_else();
}
--
Rowan Tommins
[IMSoP]
choosing between creating a child within a
narrow scope you've just opened, vs creating a sibling in the scope created
somewhere up the stack.
The "request handler" use case could easily benefit from a "pseudo-global"
scope for each request - i e. "tie this to the current request, but not to
anything else that's started a scope in between".
There were also some concrete examples given in the previous thread of
explicitly managing a context/scope/playpen in a library.
Rowan Tommins
[IMSoP]
expanding recursively to function_call, as in the add(1)(2) form beloved
of Function Programmers
Is there a reason to redefine all of this and make fresh decisions about
what to allow?
I would argue for "principle of least surprise": reuse or emulate as
much of the existing grammar as possible, even if you personally would
never use it.
--
Rowan Tommins
[IMSoP]
rsonally, I would be equally happy with either \ or :: and less happy with
anything that required us choosing yet another set of punctuation, for what is
otherwise quite a minor feature in its language impact.
Rowan Tommins
[IMSoP]
al
syntax might make more sense - there would be a very specific
relationship between the inner and outer classes. I don't think "has
special visibility of members, like a friend-class or file-private
feature" needs to be highlighted in the syntax that way.
--
Rowan Tommins
[IMSoP]
ead.
> So, maybe, it could be useful to use \ but in the long run, I’m not sure it
> makes sense.
I rather think the other way round: in the short term, a new separator would
save users a bit of pain with autoloading, but in the long run it will look
like a weird anomaly that no other language needs.
Rowan Tommins
[IMSoP]
e application malfunctions.
This and other special behaviours suggest that this should inherit from
Error rather than Exception, or possibly directly from Throwable
That's all for now. To reiterate: thank you so much for working on this,
and I really like the shape it's beginning to take :)
--
Rowan Tommins
[IMSoP]
\InnerClass" }
The quadrupled namespace separator is still just about readable, but
could you tell me at a glance if I have the right number of backslashes
for the proposed inner class separator?
If we can't use "::", I'm confident we can find one that's more
convenient to use than double-backslash.
--
Rowan Tommins
[IMSoP]
firewalls" in the application, where any accidentally orphaned
coroutines can be automatically awaited before declaring a particular task
"done". But Daniil is probably right to ask for concrete use cases, and I have
not used enough existing async code (in PHP or any other language) to answer
that confidently.
Rowan Tommins
[IMSoP]
des")->build();
The "User" class would have a "file private" or "namespace private"
constructor, callable from the "User\Builder" class but not elsewhere; the
build() method would return the "User" instance.
I think I'm coming to the conclusion that we should use backslash: nested types
can be viewed as a shorthand way of having a class and namespace with the same
name, plus applying some visibility rules to that namespace.
Rowan Tommins
[IMSoP]
mming-language/accesscontrol/
The example of a nested enum also demonstrates a nice shorthand syntax,
where the ".ace" in "BlackjackCard(rank: .ace, suit: .spades)" is short
for BlackjackCard.Rank.ace, inferred from the parameter type.
I don't have any specific conclusions, but I think with features like
this it's always worth examining other people's ideas, to see if we want
to include (or avoid) any of them.
--
Rowan Tommins
[IMSoP]
dered wrong here: https://externals.io/message/126589#126741 (compare
here: https://news-web.php.net/php.internals/126741)
The other thing I wonder is whether the original reason why `::` wasn't
used as the namespace separator still applies, and needs to be accounted
for here?
--
Rowan Tommins
[IMSoP]
t proposals complement rather
than blocking each other: iterator functions make pipes more efficient to use,
and pipes make iterator functions more pleasant to use. I'd like both please. :)
Rowan Tommins
[IMSoP]
, and give
every annual release equal status. This is the approach that PostgreSQL
has taken, I believe.
We'd probably still want some kind of deprecation policy - some changes
should be deprecated for X releases before removal/change. Which brings
us back to some kind of criteria for which changes need that, so doesn't
really solve the problem.
--
Rowan Tommins
[IMSoP]
letely new API to eliminate) and "this is bad, and there
are concrete plans to change it" (e.g. it will become an error, or start
doing something different, in the next major version).
--
Rowan Tommins
[IMSoP]
we should be very wary of how far we bend the difference between
"minor" and "major" releases.
For these changes, I'd like to hear the argument *against* starting with a
Warning. Is there any significant burden to waiting until 9.0 for these to
become errors?
Rowan Tommins
[IMSoP]
the currently running OS: they don't actually start a new
Scheduler, but they mark a namespace of related coroutines, that can be
treated specially in some way.
Alternatively, it could simply be an error, like trying to run the
kernel as a userland program.
--
Rowan Tommins
[IMSoP]
;spawn managed" and "spawn detached",
the "detached" mode would be overwhelmingly more common (i.e. users and
library authors would want to manage the lifecycle of their coroutines
manually), so the "spawn managed" mode isn't worth implementing.
Would that be a fair summary of your opinion?
--
Rowan Tommins
[IMSoP]
lso note that the concept of parent and child fibers is also useful
for other proposed features, such as cascading cancellations, and having
environment-variable style inherited context data. None of those is
*essential*, but unless there are major *implementation* concerns, they seem
like useful features to offer the user.
Rowan Tommins
[IMSoP]
isolation in userland, by marking a checkpoint in the code.
As I've said repeatedly, it doesn't necessarily need to be a mandatory
restriction, it can be a feature to help users write code without having to
worry about *accidentally* leaving a background fiber running.
Rowan Tommins
[IMSoP]
ge, we're not limited to expressing
things with functions and objects, and a block syntax makes it trivial for the
compiler to detect a mismatched start and end.
Regards,
Rowan Tommins
[IMSoP]
rder to use async facilities in its *body*.
If the body can say "get current nursery", it can be called even if its
*immediate* caller has no knowledge of async code, as long as we have
some reasonable definition of "current".
--
Rowan Tommins
[IMSoP]
{
$child = asyncChild foo();
$bgTask = asyncDetached bar();
}
// foo() guaranteed to be completed or cancelled, bar() continuing as an
independent fiber
(all names and syntax picked for fast illustration, not an exact proposal)
--
Rowan Tommins
[IMSoP]
hed colours. As a user,
I find it really hard to pick out what PHP code I'll actually write to
make use of this - or even whether I'm the target audience at all, or
whether this is all likely to be hidden by higher-level libraries.
--
Rowan Tommins
[IMSoP]
awn a fiber in the
currently active nursery, the child's lifetime guaranteed to be no longer than
its parent, and that lifetime is defined rigidly in the source code.
Rowan Tommins
[IMSoP]
Async\Context class should have, because that whole class can be added
later, or just implemented in userland.
If we strip down the solution initially, we can concentrate on the
fundamental design - things like "Fibers have parents", and what that
implies for how they're started and used.
--
Rowan Tommins
[IMSoP]
task into? Or would we prefer, at least in the minimum
implementation, to say "when you spawn a task, it spawns in the current
async context, and if there is no current async context, an error is
thrown"?
--
Rowan Tommins
[IMSoP]
On 05/03/2025 23:10, Rowan Tommins [IMSoP] wrote:
This is roughly what happened with Closures themselves in PHP: first,
decide that "$foo = function(){};" will be valid syntax, and define
Closure as the type of $foo; then over time, add additional behaviour
to the Closure class, the
to
the Closure class, the ability to add __invoke() hooks on other classes, etc
Regards,
--
Rowan Tommins
[IMSoP]
but every one of them deserves its own
discussion, and several can be left to userland or as future scope in an
initial implementation.
Rowan Tommins
[IMSoP]
l decisions which should be our focus first.
To re-iterate: this is really exciting, and thanks for getting it to
this stage!
--
Rowan Tommins
[IMSoP]
nough that you could
only have both if the language had multiple enum-like things which the
user could choose between.
--
Rowan Tommins
[IMSoP]
On 25 February 2025 23:31:25 GMT, tight.fork3...@fastmail.com wrote:
>On 2/25/25 4:51 PM, Rowan Tommins [IMSoP] wrote:
>> I actually started writing an RFC to rationalise some of this behaviour
>
>I'm glad I'm not the only one who considers this an issue worth pursuin
sounds simple when you look at a
single use case, but actually specify the behaviour in all cases is
going to be a lot of work.
--
Rowan Tommins
[IMSoP]
be clear:
$decision = Decision::createFromId($a, $b);
$decision = Decision::createFromMail($a, $b);
Even if someone were to come up with a working implementation of overloading in
PHP's type system, I would probably oppose it, because I think it makes code
harder to read and reason about.
Regards,
Rowan Tommins
[IMSoP]
ater be optimized and start warning could be very confusing, and given the
backwards compatibility issue, users will need something other than "(void)"
which is reliable.
My other thought reading the proposal is that if this can be done efficiently,
can we use the same approach to warn
bolishing it completely, or replacing it with some
form of *local* setting (maybe *only* on SplFileInfo). I would probably vote
against adding an ini setting.
Regards,
Rowan Tommins
[IMSoP]
rue);
do_something();
$after = new SplFileInfo($name, snapshot: true);
if ( $before->getSize() !== $after->getSize() ) { ... }
Inheritance of constructors isn't restricted, so that would not be a BC
break, and seems both more powerful and easier to understand than the
current feature.
Regards,
--
Rowan Tommins
[IMSoP]
nother" after what? Adding either an INI setting or an optional parameter is
not a BC break, unless and until the default is changed, at which point there
is exactly one BC break.
Regards,
Rowan Tommins
[IMSoP]
somehow, but it would make the behaviour much more explicit.
Regards,
Rowan Tommins
[IMSoP]
all the way back in 2004:
<https://bugs.php.net/bug.php?id=28790>
I have no doubt there are various other duplicates and discussions; clearly
this has always been a contentious topic.
Regards,
Rowan Tommins
[IMSoP]
lt;0, 0, >0, so no CPU time
is spent normalising the result to specific values.
The documentation is simply mistaken in saying "-1" instead of "a value
less than zero" and "1" instead of "a value more than zero".
Regards,
--
Rowan Tommins
[IMSoP]
overloading the operator to mean
"identity" rather than applying a strict value comparison.
Example: https://3v4l.org/udOoU
If we introduce some new "value type", it seems very reasonable to use
the same recursive definition of strict equality used for arrays.
--
Rowan Tommins
[IMSoP]
$this refers to the desired result of the mutation
In fact, it's a bit like __construct or __clone, where $this refers to
the newly created/copied object, before anything else points to it.
--
Rowan Tommins
[IMSoP]
1 - 100 of 1121 matches
Mail list logo