[RFC] Namespace-scoped declares, again

  101323
December 11, 2017 13:43 nikita.ppv@gmail.com (Nikita Popov)
Hi internals!

Some time ago I introduced the following proposal for namespace-scoped
declares:

    https://wiki.php.net/rfc/namespace_scoped_declares

The idea is to allow specifying declare directives for a whole library or
project using:

    namespace_declare('Vendor\Lib', ['strict_types' => 1]);

I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.

The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.

Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.

Thanks,
Nikita
  101324
December 11, 2017 15:46 pollita@php.net (Sara Golemon)
On Mon, Dec 11, 2017 at 8:43 AM, Nikita Popov ppv@gmail.com> wrote:
> Some time ago I introduced the following proposal for namespace-scoped > declares: > > https://wiki.php.net/rfc/namespace_scoped_declares > > The idea is to allow specifying declare directives for a whole library or > project using: > > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > > I've finally gotten around to implementing this proposal ( > https://github.com/php/php-src/pull/2972) and would like to move forward > with it. > Being lazy here because I'm literally on my way out the door and don't
have a moment to parse through the implementation, but can you clarify how this impact compile-time declares?
  101326
December 11, 2017 15:56 nikita.ppv@gmail.com (Nikita Popov)
On Mon, Dec 11, 2017 at 4:46 PM, Sara Golemon <pollita@php.net> wrote:

> On Mon, Dec 11, 2017 at 8:43 AM, Nikita Popov ppv@gmail.com> > wrote: > > Some time ago I introduced the following proposal for namespace-scoped > > declares: > > > > https://wiki.php.net/rfc/namespace_scoped_declares > > > > The idea is to allow specifying declare directives for a whole library or > > project using: > > > > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > > > > I've finally gotten around to implementing this proposal ( > > https://github.com/php/php-src/pull/2972) and would like to move forward > > with it. > > > Being lazy here because I'm literally on my way out the door and don't > have a moment to parse through the implementation, but can you clarify > how this impact compile-time declares? > > > require('a.php"); > require('b.php"); // This file has a namespace declaration > require('c.php"); > > In this example, does a.php wind up getting compiled with a different > set of declares than b.php and c.php? > > -Sara >
Nope. The namespace_declare() call in this case will throw an Error, because code using that namespace has already been loaded. The implementation is careful to ensure that it's never possible to end up in a situation where the used declare directives are inconsistent. Nikita
  101325
December 11, 2017 15:55 markyr@gmail.com (Mark Randall)
On 11/12/2017 13:43, Nikita Popov wrote:
> Namespace-scoped declares are perfectly suited to resolve this problem. We > can introduce a require_explicit_send_by_ref declare directive to make the > call-site annotation required, and libraries/projects can easily opt-in to > it using namespace_declare().
Seems solid to me, I would definitely make use of this feature, as I found adding the declare to each file felt untidy and even a little clumsy. I certainly like the direction that PHP seems to be moving in terms of making the script structure more like a compiled application, rather than a set of independent scripts. If this doesn't pass, long term I think the main alternative would be to have a single statement that was like a quasi-include of declarations in another file, almost like a ".h" declare_import('/my/namespace/nsprefs.php'); -- Mark Randall
  101331
December 12, 2017 07:46 smalyshev@gmail.com (Stanislav Malyshev)
Hi!

> The idea is to allow specifying declare directives for a whole library or > project using: > > namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I am not sure I like this. Namespace is a prefix to a class name. Anybody can declare a class with any name, and the side-effect that they would inherit some context, which is completely invisible and would magically exist somewhere globally, does not seem like a good idea to me. Moreover, what if something - like older version of the same library or test or something like that - would have different idea about what that global state should be? How nice would it be if a piece of unrelated code could completely change how my code is interpreted? How nice would it be if whether it works or not would depend on in which order classes were loaded in this particular request? Hidden global context has the same smell as php.ini settings, and for the same reason - but this, as far as I can see, will also be hidden and depending on file loading order, class loading order, etc. which in big applications can lead to a lot of fun debugging why some code randomly produces fatal errors... Debugging PHP is fun enough without quantum entanglement-like effects :)
> The reason why I'm picking it up again is some feedback I received for the > explicit call-time send-by-ref proposal. The main objection seems to be > that the feature has limited usefulness if it's optional rather than > required, because you still can't be sure that something is a by-value > pass, just because no & is present. At the same time, we can't make this > required anytime soon due to the large BC impact.
Where "soon" means "for all practical purposes, forever, unless we stop calling that new thing PHP", IMO.
> Namespace-scoped declares are perfectly suited to resolve this problem. We
I don't think so. First of all, I don't think, of course, that this problem needs to be solved by adding more complexity to save a purely cosmetic feature. But second of all, I don't think global hidden context that could change at a distance how the code is interpreted is a good idea regardless of whether it solves the issues with send-by-ref. -- Stas Malyshev smalyshev@gmail.com
  101334
December 12, 2017 13:43 nikita.ppv@gmail.com (Nikita Popov)
On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev <smalyshev@gmail.com>
wrote:

> Hi! > > > The idea is to allow specifying declare directives for a whole library or > > project using: > > > > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > > I am not sure I like this. Namespace is a prefix to a class name. > Anybody can declare a class with any name, and the side-effect that they > would inherit some context, which is completely invisible and would > magically exist somewhere globally, does not seem like a good idea to > me. Moreover, what if something - like older version of the same library > or test or something like that - would have different idea about what > that global state should be? How nice would it be if a piece of > unrelated code could completely change how my code is interpreted? How > nice would it be if whether it works or not would depend on in which > order classes were loaded in this particular request? >
The way PHP works, it's not possible to have two versions of a library loaded at the same time. There are projects like https://github.com/humbug/php-scoper to allow loading a library multiple times, which work by prefixing all namespaces. Of course, in this case namespace_declares() would also be applied to different namespaces and there will be no interference. There is no dependence on loading order. The implementation is careful to ensure that the used declare state is consistent. It's not possible to call namespace_declare() twice on the same namespace. It's not possible to first load some files from a namespace, do the namespace_declare() call and then load some more files. If a namespace_declare() call succeeds without throwing an error, then that is the ground truth, without any dependence on order or other calls.
> Hidden global context has the same smell as php.ini settings, and for > the same reason - but this, as far as I can see, will also be hidden and > depending on file loading order, class loading order, etc. which in big > applications can lead to a lot of fun debugging why some code randomly > produces fatal errors... Debugging PHP is fun enough without quantum > entanglement-like effects :) >
As said above, the implementation makes sure that all quantum state is collapsed ;) The only possible mistake that can occur is that the namespace_declare() call doesn't happen at all, but anything depending on loading order or conflicting calls is not possible. The big issue with ini settings is (mostly) not the "hidden" part, it's the "global" part. Ini settings that change language behavior are tabu because they apply to everything, so no library can assume any particular ini configuration. Namespace-scoped declares explicitly avoid this. A library can namespace_declare() it's configuration and be sure that this is the configuration it's going to get, at the same time not interfering with any other library or code that uses a different configuration.
> The reason why I'm picking it up again is some feedback I received for the > > explicit call-time send-by-ref proposal. The main objection seems to be > > that the feature has limited usefulness if it's optional rather than > > required, because you still can't be sure that something is a by-value > > pass, just because no & is present. At the same time, we can't make this > > required anytime soon due to the large BC impact. > > Where "soon" means "for all practical purposes, forever, unless we stop > calling that new thing PHP", IMO. > > > Namespace-scoped declares are perfectly suited to resolve this problem. > We > > I don't think so. First of all, I don't think, of course, that this > problem needs to be solved by adding more complexity to save a purely > cosmetic feature. But second of all, I don't think global hidden context > that could change at a distance how the code is interpreted is a good > idea regardless of whether it solves the issues with send-by-ref. >
I haven't thought too carefully about whether having an option for the explicit-send-by-ref feature *specifically* would be beneficial, but I think it's very important to at least have the option on the table. Too many issues in PHP cannot be solved for reasons of backwards-compatibility. We need to have *some* way to evolve the language without BC breaks, and I think namespace-declares are an elegant way to do this. Regards, Nikita
  101340
December 12, 2017 23:14 smalyshev@gmail.com (Stanislav Malyshev)
Hi!

> There is no dependence on loading order. The implementation is careful > to ensure that the used declare state is consistent. It's not possible > to call namespace_declare() twice on the same namespace. It's not > possible to first load some files from a namespace, do the > namespace_declare() call and then load some more files. If a
This means that namespace_declare can be only in one file, and if any mention of any namespace class has been made before that file has been loaded, then the declare would fail. That is loading order dependency - if A.php contains namespace_declare and B.php contains another class of the same namespace, then order (A, B) works but order (B, A) does not.
> The big issue with ini settings is (mostly) not the "hidden" part, it's > the "global" part. Ini settings that change language behavior are tabu
Exactly. And this proposal adds another global state, which is also invisible, so figuring out what the state is when debugging is... fun. It's better than php.ini as it's "namespaced php.ini" but still suffers from the same problems within the namespace (and namespaces can be pretty big).
> this. A library can namespace_declare() it's configuration and be sure > that this is the configuration it's going to get, at the same time not > interfering with any other library or code that uses a different > configuration.
This assumes each namespace is homogeneous code always belonging to the same library and nothing is every added to that namespace. This is not always the case. -- Stas Malyshev smalyshev@gmail.com
  101342
December 13, 2017 00:16 andreas@dqxtech.net (Andreas Hennings)
I agree with all of Stanislav's emails in this thread so far.

On 12 December 2017 at 14:43, Nikita Popov ppv@gmail.com> wrote:
> On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev <smalyshev@gmail.com> > wrote: > >> Hi! >> >> > The idea is to allow specifying declare directives for a whole library or >> > project using: >> > >> > namespace_declare('Vendor\Lib', ['strict_types' => 1]); >> >> I am not sure I like this. Namespace is a prefix to a class name. >> Anybody can declare a class with any name, and the side-effect that they >> would inherit some context, which is completely invisible and would >> magically exist somewhere globally, does not seem like a good idea to >> me. Moreover, what if something - like older version of the same library >> or test or something like that - would have different idea about what >> that global state should be? How nice would it be if a piece of >> unrelated code could completely change how my code is interpreted? How >> nice would it be if whether it works or not would depend on in which >> order classes were loaded in this particular request? >> > > The way PHP works, it's not possible to have two versions of a library > loaded at the same time.
Really? PHP does not even know what a "library" is. PHP sees files, directories and namespaces. But it does not know how to conceptualize any of this as a "library". With Composer you get the notion of a "package". In general, Composer would prevent you from using different versions of the same package. But you could manually download two versions of a package, and wire up the class loader in a way that it would load some classes from one version, and some classes from another version. E.g. if a class does not exist in version 2, load the class from version 1 instead. PHP as a language should not assume that someone is using Composer correctly. And even if we avoid two package versions coexisting: There could easily be two distinct packages that use the same namespace. We could discuss if this is a good idea, but it should not be the job of PHP as a language to make this situation difficult.
> > There is no dependence on loading order. The implementation is careful to > ensure that the used declare state is consistent. It's not possible to call > namespace_declare() twice on the same namespace. It's not possible to first > load some files from a namespace, do the namespace_declare() call and then > load some more files. If a namespace_declare() call succeeds without > throwing an error, then that is the ground truth, without any dependence on > order or other calls.
So by "is not possible", in fact you mean "will trigger an error". I imagine with Composer we would have to agree on a canonical file name where a namespace_declare() would be found. Maybe something like in src/Acme/Animal.namespace.php. The class loader would then have to make sure that this file is included before the first class from that namespace is included. Or alternatively, Composer init script would have to include all such files at the beginning of the process. If Composer (or whichever tool one wants to use) would include class file src/Acme/Animal/Cat.php without prior inclusion of the Animal.namespace.php, the class file would be interpreted without the desired setting. If the process then continues without ever including Animal.namespace.php, it will silently misbehave. If, however, Animal.namespace.php is included some time later in the process, then it would notice that something went wrong, and trigger an error.
> I haven't thought too carefully about whether having an option for the > explicit-send-by-ref feature *specifically* would be beneficial, but I > think it's very important to at least have the option on the table. Too > many issues in PHP cannot be solved for reasons of backwards-compatibility. > We need to have *some* way to evolve the language without BC breaks, and I > think namespace-declares are an elegant way to do this.
So if you want a setting for explicit-send-by-ref, why not do this per file, as we already do for strict_types? If at some day in the future we find that the declares become too verbose, we could bundle multiple declares into a new setting. E.g. something like "declare(php=8.1);" to combine all the declares that would be considered default in PHP 8.1. Or introduce some other shortcut like "
  101343
December 13, 2017 04:04 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
2017-12-13 1:16 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>:

> I agree with all of Stanislav's emails in this thread so far. > > On 12 December 2017 at 14:43, Nikita Popov ppv@gmail.com> wrote: > > On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev <smalyshev@gmail.com > > > > wrote: > > > >> Hi! > >> > >> > The idea is to allow specifying declare directives for a whole > library or > >> > project using: > >> > > >> > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > >> > >> I am not sure I like this. Namespace is a prefix to a class name. > >> Anybody can declare a class with any name, and the side-effect that they > >> would inherit some context, which is completely invisible and would > >> magically exist somewhere globally, does not seem like a good idea to > >> me. Moreover, what if something - like older version of the same library > >> or test or something like that - would have different idea about what > >> that global state should be? How nice would it be if a piece of > >> unrelated code could completely change how my code is interpreted? How > >> nice would it be if whether it works or not would depend on in which > >> order classes were loaded in this particular request? > >> > > > > The way PHP works, it's not possible to have two versions of a library > > loaded at the same time. > > Really? > PHP does not even know what a "library" is. PHP sees files, > directories and namespaces. But it does not know how to conceptualize > any of this as a "library". > > With Composer you get the notion of a "package". > In general, Composer would prevent you from using different versions > of the same package. > But you could manually download two versions of a package, and wire up > the class loader in a way that it would load some classes from one > version, and some classes from another version. > E.g. if a class does not exist in version 2, load the class from > version 1 instead. > > PHP as a language should not assume that someone is using Composer > correctly. > > And even if we avoid two package versions coexisting: There could > easily be two distinct packages that use the same namespace. > We could discuss if this is a good idea, but it should not be the job > of PHP as a language to make this situation difficult. > > > > > There is no dependence on loading order. The implementation is careful to > > ensure that the used declare state is consistent. It's not possible to > call > > namespace_declare() twice on the same namespace. It's not possible to > first > > load some files from a namespace, do the namespace_declare() call and > then > > load some more files. If a namespace_declare() call succeeds without > > throwing an error, then that is the ground truth, without any dependence > on > > order or other calls. > > So by "is not possible", in fact you mean "will trigger an error". > > I imagine with Composer we would have to agree on a canonical file > name where a namespace_declare() would be found. > Maybe something like in src/Acme/Animal.namespace.php. > > The class loader would then have to make sure that this file is > included before the first class from that namespace is included. > Or alternatively, Composer init script would have to include all such > files at the beginning of the process. > > If Composer (or whichever tool one wants to use) would include class > file src/Acme/Animal/Cat.php without prior inclusion of the > Animal.namespace.php, the class file would be interpreted without the > desired setting. > If the process then continues without ever including > Animal.namespace.php, it will silently misbehave. > If, however, Animal.namespace.php is included some time later in the > process, then it would notice that something went wrong, and trigger > an error. > > If we're going to introduce someday a namespace file, then IMO it should
not be putted outside namespace folder. For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have namespace file in src/Acme/Aniimal/namespace.php or even more src/Acme/Animal/ns.php Why? Because users use PSR-4 so then they're src folder looks more like: src/Cat.php <-- class Acme\Animal\Cat src/ns.php <-- that should be then a place for namespace declare or even function and constants. Such namespace file can be a good place for namespace function and constants declaration. Also I think there is no need for another global function named `namespace_declare` if we had namespace file then we can utilise declare for that. Lets imagine such syntax: // src/Acme/Animal/ns.php > I haven't thought too carefully about whether having an option for the > > explicit-send-by-ref feature *specifically* would be beneficial, but I > > think it's very important to at least have the option on the table. Too > > many issues in PHP cannot be solved for reasons of > backwards-compatibility. > > We need to have *some* way to evolve the language without BC breaks, and > I > > think namespace-declares are an elegant way to do this. > > > So if you want a setting for explicit-send-by-ref, why not do this per > file, as we already do for strict_types? > > If at some day in the future we find that the declares become too > verbose, we could bundle multiple declares into a new setting. > E.g. something like "declare(php=8.1);" to combine all the declares > that would be considered default in PHP 8.1. > > Or introduce some other shortcut like " opening tag. > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com
  101344
December 13, 2017 04:24 andreas@dqxtech.net (Andreas Hennings)
On 13 December 2017 at 05:04, Michał Brzuchalski <michal@brzuchalski.com> wrote:
> > If we're going to introduce someday a namespace file, then IMO it should not > be putted outside namespace folder. > For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have > namespace file in src/Acme/Aniimal/namespace.php > or even more src/Acme/Animal/ns.php > Why? Because users use PSR-4 so then they're src folder looks more like: > src/Cat.php <-- class Acme\Animal\Cat > src/ns.php <-- that should be then a place for namespace declare or even > function and constants.
You are right, my previous proposal src/Acme/Animal.namespace.php would not work universally. But your proposal, src/Acme/Animal/ns.php clashes with the class file for class \Acme\Animal\ns. We would need something other than NAME.php. E.g. src/Acme/Animal/ns.inc.php But then Composer would still need to make sure that this file is always included before any class files from this directory. On language level we cannot assume that Composer is being used, and that it is being used correctly. So again this would be fragile.
> > Such namespace file can be a good place for namespace function and constants > declaration. > Also I think there is no need for another global function named > `namespace_declare` if we had namespace file > then we can utilise declare for that. > Lets imagine such syntax: > > // src/Acme/Animal/ns.php > > namespace Acme\Animal declare(strict_types=1,another_option=0); > const CAT = 1; > function createCat() : Cat {}
This means you are changing the meaning of existing declare() to apply to the entire namespace? Or to the entire directory? Or maybe the difference here is that there is no semicolon directly after the namespace declaration? I am not convinced by this syntax. But even if we would find a good syntax, the behavioral problems pointed out by Stanislav still apply.
  101345
December 13, 2017 04:38 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
2017-12-13 5:24 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>:

> On 13 December 2017 at 05:04, Michał Brzuchalski <michal@brzuchalski..com> > wrote: > > > > If we're going to introduce someday a namespace file, then IMO it should > not > > be putted outside namespace folder. > > For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have > > namespace file in src/Acme/Aniimal/namespace.php > > or even more src/Acme/Animal/ns.php > > Why? Because users use PSR-4 so then they're src folder looks more like: > > src/Cat.php <-- class Acme\Animal\Cat > > src/ns.php <-- that should be then a place for namespace declare or even > > function and constants. > > You are right, my previous proposal src/Acme/Animal.namespace.php > would not work universally. > > But your proposal, src/Acme/Animal/ns.php clashes with the class file > for class \Acme\Animal\ns. > > We would need something other than NAME.php. > E.g. src/Acme/Animal/ns.inc.php > > But then Composer would still need to make sure that this file is > always included before any class files from this directory. > On language level we cannot assume that Composer is being used, and > that it is being used correctly. > > So again this would be fragile. > > > > > Such namespace file can be a good place for namespace function and > constants > > declaration. > > Also I think there is no need for another global function named > > `namespace_declare` if we had namespace file > > then we can utilise declare for that. > > Lets imagine such syntax: > > > > // src/Acme/Animal/ns.php > > > > > namespace Acme\Animal declare(strict_types=1,another_option=0); > > const CAT = 1; > > function createCat() : Cat {} > > This means you are changing the meaning of existing declare() to apply > to the entire namespace? > Or to the entire directory? > > To entire namespace just like:
1, 'dynamic_object_properties' => 0, ... ]); namespace Acme\Animal declare( strict_types=1, dynamic_object_properties=0 ); // <-- this works same as namespace_declare call above namespace Acme\Machines { // here we have strict_types=0 turned off }
> Or maybe the difference here is that there is no semicolon directly > after the namespace declaration? > > I am not convinced by this syntax. > But even if we would find a good syntax, the behavioral problems > pointed out by Stanislav still apply. >
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com
  101347
December 13, 2017 05:04 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
2017-12-13 5:38 GMT+01:00 Michał Brzuchalski <michal@brzuchalski.com>:

> > > 2017-12-13 5:24 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>: > >> On 13 December 2017 at 05:04, Michał Brzuchalski <michal@brzuchalski.com> >> wrote: >> > >> > If we're going to introduce someday a namespace file, then IMO it >> should not >> > be putted outside namespace folder. >> > For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have >> > namespace file in src/Acme/Aniimal/namespace.php >> > or even more src/Acme/Animal/ns.php >> > Why? Because users use PSR-4 so then they're src folder looks more like: >> > src/Cat.php <-- class Acme\Animal\Cat >> > src/ns.php <-- that should be then a place for namespace declare or even >> > function and constants. >> >> You are right, my previous proposal src/Acme/Animal.namespace.php >> would not work universally. >> >> But your proposal, src/Acme/Animal/ns.php clashes with the class file >> for class \Acme\Animal\ns. >> >> We would need something other than NAME.php. >> E.g. src/Acme/Animal/ns.inc.php >> > Actually not true. `namespace` keyword is reserved and none class can have
such name. This means this example couses a syntax error: >> But then Composer would still need to make sure that this file is >> always included before any class files from this directory. >> On language level we cannot assume that Composer is being used, and >> that it is being used correctly. >> >> So again this would be fragile. >> >> > >> > Such namespace file can be a good place for namespace function and >> constants >> > declaration. >> > Also I think there is no need for another global function named >> > `namespace_declare` if we had namespace file >> > then we can utilise declare for that. >> > Lets imagine such syntax: >> > >> > // src/Acme/Animal/ns.php >> > > > >> > namespace Acme\Animal declare(strict_types=1,another_option=0); >> > const CAT = 1; >> > function createCat() : Cat {} >> >> This means you are changing the meaning of existing declare() to apply >> to the entire namespace? >> Or to the entire directory? >> >> > To entire namespace just like: > > > namespace_declare('Acme\Animal', [ > 'strict_types' => 1, > 'dynamic_object_properties' => 0, > ... > ]); > > namespace Acme\Animal declare( > strict_types=1, > dynamic_object_properties=0 > ); // <-- this works same as namespace_declare call above > > namespace Acme\Machines { > // here we have strict_types=0 turned off > } > > >> Or maybe the difference here is that there is no semicolon directly >> after the namespace declaration? >> >> I am not convinced by this syntax. >> But even if we would find a good syntax, the behavioral problems >> pointed out by Stanislav still apply. >> > > > > -- > regards / pozdrawiam, > -- > Michał Brzuchalski > about.me/brzuchal > brzuchalski.com >
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com
  101349
December 13, 2017 07:12 michal@brzuchalski.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
2017-12-13 6:04 GMT+01:00 Michał Brzuchalski <michal@brzuchalski.com>:

> > > 2017-12-13 5:38 GMT+01:00 Michał Brzuchalski <michal@brzuchalski.com>: > >> >> >> 2017-12-13 5:24 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>: >> >>> On 13 December 2017 at 05:04, Michał Brzuchalski <michal@brzuchalski.com> >>> wrote: >>> > >>> > If we're going to introduce someday a namespace file, then IMO it >>> should not >>> > be putted outside namespace folder. >>> > For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have >>> > namespace file in src/Acme/Aniimal/namespace.php >>> > or even more src/Acme/Animal/ns.php >>> > Why? Because users use PSR-4 so then they're src folder looks more >>> like: >>> > src/Cat.php <-- class Acme\Animal\Cat >>> > src/ns.php <-- that should be then a place for namespace declare or >>> even >>> > function and constants. >>> >>> You are right, my previous proposal src/Acme/Animal.namespace.php >>> would not work universally. >>> >>> But your proposal, src/Acme/Animal/ns.php clashes with the class file >>> for class \Acme\Animal\ns. >>> >>> We would need something other than NAME.php. >>> E.g. src/Acme/Animal/ns.inc.php >>> >> > Actually not true. `namespace` keyword is reserved and none class can have > such name. > This means this example couses a syntax error: > > namespace Acme\Animals; > class namespace {} > > That why we can assume we can utilise namespace.php file name. > And also why not trying to include it on autoload call? > For eg. > > new Acme\Animal\Cat(); // tries to load $file = "src/Acme/Animal/Cat.php" > > // but prevoiusly tries to load > require_once dirname($file) . DIRECTORY_SEPARATOR . 'namespace.php'; > > It's bad because it';s magic, but the `namespace.php` filename is still > available to use. > > Andreas, we're touching namespaces which is a hard subject, but if I could
fly away with my thoughts I'd propose to introduce something called for eg. a package and then divide it's name in class/function/const name with a single colon, for eg. Acme:Animal\Cat which gives additional information about package which then declares something and may be a good start for future scoped declarations. I've prepared a short gist to illustrate that https://gist.github.com/brzuchal/352ffce2717648f0d43f2d5a0c4bfb7b This solution doesn't require usage of Composer, but needs to pass an aotuloader function a type to load. There was a proposal on internal some time ago to pass additional parameter to load function.
> >>> But then Composer would still need to make sure that this file is >>> always included before any class files from this directory. >>> On language level we cannot assume that Composer is being used, and >>> that it is being used correctly. >>> >>> So again this would be fragile. >>> >>> > >>> > Such namespace file can be a good place for namespace function and >>> constants >>> > declaration. >>> > Also I think there is no need for another global function named >>> > `namespace_declare` if we had namespace file >>> > then we can utilise declare for that. >>> > Lets imagine such syntax: >>> > >>> > // src/Acme/Animal/ns.php >>> > >> > >>> > namespace Acme\Animal declare(strict_types=1,another_option=0); >>> > const CAT = 1; >>> > function createCat() : Cat {} >>> >>> This means you are changing the meaning of existing declare() to apply >>> to the entire namespace? >>> Or to the entire directory? >>> >>> >> To entire namespace just like: >> >> > >> namespace_declare('Acme\Animal', [ >> 'strict_types' => 1, >> 'dynamic_object_properties' => 0, >> ... >> ]); >> >> namespace Acme\Animal declare( >> strict_types=1, >> dynamic_object_properties=0 >> ); // <-- this works same as namespace_declare call above >> >> namespace Acme\Machines { >> // here we have strict_types=0 turned off >> } >> >> >>> Or maybe the difference here is that there is no semicolon directly >>> after the namespace declaration? >>> >>> I am not convinced by this syntax. >>> But even if we would find a good syntax, the behavioral problems >>> pointed out by Stanislav still apply. >>> >> >> >> >> -- >> regards / pozdrawiam, >> -- >> Michał Brzuchalski >> about.me/brzuchal >> brzuchalski.com >> > > > > -- > regards / pozdrawiam, > -- > Michał Brzuchalski > about.me/brzuchal > brzuchalski.com >
-- regards / pozdrawiam, -- Michał Brzuchalski about.me/brzuchal brzuchalski.com
  101390
December 16, 2017 23:18 rowan.collins@gmail.com (Rowan Collins)
On 13/12/2017 07:12, Michał Brzuchalski wrote:
> Andreas, we're touching namespaces which is a hard subject, but if I could > fly away with my thoughts > I'd propose to introduce something called for eg. a package
My thoughts were actually going along the same lines: basically, the current implementation of namespaces is, I think by design, very conservative in what a namespace represents. A namespace doesn't have any identity, and doesn't have any codified structure, it's just a shorthand for referring to similarly named classes (plus functions and constants). There are several things that I think would feel more natural with "packages" than namespaces as they exist today: - Declare directives, as discussed here - Visibility modifiers, e.g. a "private class", accessible only within its package - Per-package autoloaders, that only get called for classes in that package, rather than a global autoloader which parses out the prefixes it's interested in - An autoloader callback that fires once for each package, to setup these options Another difference is that namespaces tend to form deep hierarchies, but you're unlikely to set options at every level of the hierarchy. For instance, you probably don't want to set strict_types on for Acme\MyPackage\Input but off for Acme\MyPackage\Output. So a separate syntax to mark which level is the "package" would reduce the number of places a setting could be set, which would reduce the number of places you'd need to look - a bit like having Apache settings in a VirtualHost for the whole site, rather than .htaccess files in every directory. All that being said, I'm not 100% convinced this is solving a real problem. Yes, the option has to be set in every file, but that's because it effects the way that file is compiled, and the compiler sees one file at a time. The same applies to the "namespace" directive, which you might otherwise set against a particular directory. I don't see a pressing need to add the complexity. Regards, -- Rowan Collins [IMSoP]
  101351
December 13, 2017 10:43 TonyMarston@hotmail.com ("Tony Marston")
""Michal Brzuchalski""  wrote in message 
news:CABdc3WpomNLz+vX_m0B0wQ3uCiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com...
> >2017-12-13 1:16 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>: >
> >Why? Because users use PSR-4 so then they're src folder looks more like: ?
You are assuming that everybody is using PSR-4. That is a wrong assumption to make. -- Tony Marston
  101352
December 13, 2017 13:19 michal.brzuchalski@gmail.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=)
13.12.2017 11:44 "Tony Marston" <TonyMarston@hotmail.com> napisał(a):

""Michal Brzuchalski""  wrote in message news:CABdc3WpomNLz+vX_m0B0wQ3u
CiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com...


> 2017-12-13 1:16 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>: > >
> Why? Because users use PSR-4 so then they're src folder looks more like: > ?
You are assuming that everybody is using PSR-4. That is a wrong assumption to make. I didn't say everybody at all! Please read carefully. -- Tony Marston -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php
  101353
December 13, 2017 13:53 TonyMarston@hotmail.com ("Tony Marston")
""Michal Brzuchalski""  wrote in message 
news:CABdc3Wrz8qu_hGsBTjGbWwcT8YpLxgChONeE9NiJKWcDEruySw@mail.gmail.com...
> >13.12.2017 11:44 "Tony Marston" <TonyMarston@hotmail.com> napisal(a): > >""Michal Brzuchalski"" wrote in message news:CABdc3WpomNLz+vX_m0B0wQ3u >CiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com... > > >> 2017-12-13 1:16 GMT+01:00 Andreas Hennings <andreas@dqxtech.net>: >> >> > > >> Why? Because users use PSR-4 so then they're src folder looks more like: >> >? > > >You are assuming that everybody is using PSR-4. That is a wrong assumption >to make. > > >I didn't say everybody at all! Please read carefully. >
I DID read carefully. You wrote "users use PSR-4" and not "those users who use PSR-4". You did not specify a subset of users, so this implies all users. -- Tony Marston
  101350
December 13, 2017 10:37 TonyMarston@hotmail.com ("Tony Marston")
"Andreas Hennings"  wrote in message 
news:CAH0Uv3FnYf_c7in4_6AmDO5pUZHsgU0m5scjU5oRz2kTAJ=+bw@mail.gmail.com...
> >I agree with all of Stanislav's emails in this thread so far. > >On 12 December 2017 at 14:43, Nikita Popov ppv@gmail.com> wrote: >> On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev <smalyshev@gmail.com> >> wrote: >>
> >PHP as a language should not assume that someone is using Composer >correctly. >
Or even using Composer at all. -- Tony Marston
  101337
December 12, 2017 16:32 cmbecker69@gmx.de ("Christoph M. Becker")
On 11.12.2017 at 14:43, Nikita Popov wrote:

> Some time ago I introduced the following proposal for namespace-scoped > declares: > > https://wiki.php.net/rfc/namespace_scoped_declares > > The idea is to allow specifying declare directives for a whole library or > project using: > > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > > I've finally gotten around to implementing this proposal ( > https://github.com/php/php-src/pull/2972) and would like to move forward > with it.
Generally I'm not keen on letting the language diverge via whatever mechanism, but that has already happened and there seems to be some further need, and the namespace scoped declares appear to be preferable to per-file declares or even ini settings. What I don't like about the present proposal is that it introduces a proper function instead of a language construct. Is there a particular reason for this design decision? Couldn't we add the namespace scoped declares to the namespace declaration directly, e.g. namespace Foo declare strict_types=1; -- Christoph M. Becker
  101348
December 13, 2017 06:36 ivan.enderlin@hoa-project.net (Ivan Enderlin)
On 11.12.17 14:43, Nikita Popov wrote:
> Some time ago I introduced the following proposal for namespace-scoped > declares: > > https://wiki.php.net/rfc/namespace_scoped_declares > > The idea is to allow specifying declare directives for a whole library or > project using: > > namespace_declare('Vendor\Lib', ['strict_types' => 1]); > > I've finally gotten around to implementing this proposal ( > https://github.com/php/php-src/pull/2972) and would like to move forward > with it. > > The reason why I'm picking it up again is some feedback I received for the > explicit call-time send-by-ref proposal. The main objection seems to be > that the feature has limited usefulness if it's optional rather than > required, because you still can't be sure that something is a by-value > pass, just because no & is present. At the same time, we can't make this > required anytime soon due to the large BC impact. > > Namespace-scoped declares are perfectly suited to resolve this problem. We > can introduce a require_explicit_send_by_ref declare directive to make the > call-site annotation required, and libraries/projects can easily opt-in to > it using namespace_declare(). There would be no BC impact, while at the > same time projects could benefit from the additional clarity and > performance improvements immediately. Thanks for the proposal.
While it seems comfortable for the user, and I understand the point you're trying to solve somehow, it can be a nightmare for the VM, the developer, and the user. I've few remarks and/or questions: * When parsing a file, the way the VM has to interprete/execute the file depends on a _runtime_ configuration defined in _another_ file. It makes things more implicit, and that's not good. * It can also be a nightmare for the developer. The behavior of their library can be changed by another library because there is no restriction about the location or usage of `namespace_declare`. If at least `namespace_declare` would only apply to the _current_ namespace, it might be better. * If `namespace_declare` is called twice for the same namespace, an error is raised, OK. It's easy to break someone's code by registering a file in an autoloader to load first, and call `namespace_declare` for that file. What the error will look like? It's important to prompt the correct culprit to the user. Any strategy to find which one is the culprit? * As you said in the RFC in the Proliferation of declare directives Section, it's not a good thing for the language to introduce more and more directives. PHP is living a time where it makes good things easier to do, and bad things harder to do. Everything I can imagine with `namespace_declare` is definitively not good for the language, the VM, and the ecosystem. Introducing a `strict` mode for the language is definitively a good thing to progressively make PHP stricter, yes, but I don't see a real need or a real motiviation behind `namespace_declare`, I for one see only dangers. So I'm sorry to say that —right now— I'm totally oppose to this RFC :-). Cheers. -Ivan.