Re: [PHP-DEV] [RFC] Exception type hint

2022-06-30 Thread Michał Marcin Brzuchalski
Hi Jeffrey,

czw., 30 cze 2022 o 17:41 Jeffrey Dafoe  napisał(a):

> > -Original Message-
> > From: Larry Garfield 
> > Sent: Wednesday, June 29, 2022 12:39 PM
> > To: php internals 
> > Subject: Re: [PHP-DEV] [RFC] Exception type hint
> >
> > On Wed, Jun 29, 2022, at 10:42 AM, Guilliam Xavier wrote:
> > > Hi (note: your message was flagged as spam),
> > >
> > >> https://github.com/php/php-src/issues/8843
> > >
> > > So I understand it as having a "true code" equivalent for the
> > > `@throws` phpDoc comment (similar to type declarations for `@param`
> > > and `@return`)? which would also be checked at run-time?
> > >
> > > Just my 2 cents on that (let's call it "exception specification"):
> > >
> > >   1. IMHO, it shouldn't be mixed in the return type declaration (with
> > > a union-like syntax) but separated and independent (e.g. with a
> > > `throws` keyword, and pipes [or commas] between multiple exception
> > > classes)
> > >   2. AFAIK, Java has it (mandatory to compile for "checked
> > > exceptions", sometimes controversial), C++ used to have it
> > > (runtime-checked) but dropped it (and introduced `noexcept` instead);
> > > I don't know of any dynamic language that has it
> > >
> > > You would also need to define how it plays with inheritance (and
> > > reflection), and what exactly should happen when a function throws an
> > > exception it didn't "declare"...
> > >
> > > PS: I also found some old feature requests:
> > >   - https://externals.io/message/4424
> > >   - https://bugs.php.net/bug.php?id=42251
> > >   - https://bugs.php.net/bug.php?id=62404
> > >   - https://bugs.php.net/bug.php?id=67312
> > >
> > > Regards,
> >
> > Side Note: Please don't top post.
> >
> > On the subject of checked exceptions, I *highly* recommend this writeup
> > from the lead of the Midori language[1].  It's long, but there's a
> section
> > specifically on exceptions (no deep link, just search the page for it)
> that goes
> > into a lot of detail about exceptions, checked exceptions, and the ways
> in
> > which both fail.  It's absolutely worth everyone's time.
> >
> > The summary for the short-timed is that the only way exceptions work,
> from
> > a reliability standpoint, is if they are 1) Rare and 2) Strictly checked
> and 3)
> > Have really good syntactic shorthand support.  And checked exceptions
> > without the other two are a recipe for hell.  Basically, it only works if
> > exceptions become an alternate syntax for an Either monad or Go's multi-
> > return.
> >
> > Since PHP is a long, long way from there, I don't believe checked
> exceptions
> > would be wise, or even slightly a good idea.  Not until/unless it's done
> as part
> > of a global rethink of error handling that reimagines how exceptions and
> > errors work at a fundamental level.  And that couldn't be done in a BC
> way
> > with the current practice of "I dunno, throw, YOLO" in PHP exceptions, so
> > they'd have to be some other, different channel.  We are definitely not
> > ready for that kind of fundamental rethink of how error handling works in
> > PHP.
> >
> > [1] http://joeduffyblog.com/2016/02/07/the-error-model/
> >
> > --
> > PHP Internals - PHP Runtime Development Mailing List To unsubscribe,
> visit:
> > https://www.php.net/unsub.php
>
> There's also a decent article here
> https://www.artima.com/articles/the-trouble-with-checked-exceptions where
> Anders Hejlsberg discusses the problems he sees with checked exceptions.
>

Thanks for the link it was really interesting to see issues with checked
exceptions based on someone's experiences.

Cheers,
Michał Marcin Brzuchalski


Re: [PHP-DEV] [RFC] [Under Discussion] New Curl URL API

2022-06-30 Thread Levi Morrison via internals
On Thu, Jun 30, 2022 at 10:48 AM Pierrick Charron  wrote:
>
> Hi all,
>
>
> > - The new CurlUrl class should probably be immutable from the start. It
> > was my biggest mistake not to do that with DateTime.
> >
> >
> After thinking about it and some discussions, I followed Derick's
> recommendation and therefore changed the RFC to make the CurlUrl class
> immutable. All the setters were replaced by new `with*` methods.
> For example setHost is now withHost and will return a new object with the
> host modified. This will prevent confusing behavior where the CurlUrl
> object would be unintentionally modified after being attached to a
> CurlHandle.
>
> Pierrick

It's clear people do not agree on how we should be designing the APIs
for 3rd party extensions. However, let me redraw attention to the
introduction of the RFC:

> One of the goal of this API is to tighten a problematic vulnerable area
> for applications where the URL parser library would believe one thing
> and libcurl another. This could and has sometimes led to security
> problems.

Designing another API on top of what libcurl provides _could make the
problem worse_. I am fine with these kinds of adjustments:

 1. Using exceptions instead of return codes.
 2. Using enums instead of constants if it makes sense (it may not if
they are bitwise-or'd together, which is pretty common for C libs).
 3. Renaming things that have keyword or reserved word conflicts.

I am not fine with designing an immutable, with* style API that
doesn't mirror the underlying library at all. At least, not by itself;
I'd be okay with having both, where the nicer API is built on top of
the lower level, but what is nicer is subjective. As this thread
shows, designing a nicer API will have quite a bit more discussion and
disagreement than "exposing" or "porting" libcurl's API.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Rowan Tommins

On 30/06/2022 18:37, Arnaud Le Blanc wrote:

On jeudi 30 juin 2022 18:29:44 CEST Guilliam Xavier wrote:

Ah? Sorry, I had interpreted
https://github.com/php/php-src/pull/8330/files#diff-85701127596aca0e597bd796
1b5d59cdde4f6bb3e2a109a22be859ab7568b4d2R7318-R7320 as "capture the
*minimal* set of variables for *both* arrow functions and short closures",
but I was wrong?

No, you are right, the PR changes arrow functions too. But in the RFC we
decided to not touch the arrow functions for now.



Personally, I would be in favour of leaving the change in for arrow 
functions as well. The fact that a variable of the same name, whose 
value is never actually used, is captured by the closure, is to me a 
bug, not a feature.


It's hard to even contrive an example where this is observable, so I 
highly doubt anyone is relying on it.


Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Arnaud Le Blanc
On jeudi 30 juin 2022 18:29:44 CEST Guilliam Xavier wrote:
> Ah? Sorry, I had interpreted
> https://github.com/php/php-src/pull/8330/files#diff-85701127596aca0e597bd796
> 1b5d59cdde4f6bb3e2a109a22be859ab7568b4d2R7318-R7320 as "capture the
> *minimal* set of variables for *both* arrow functions and short closures",
> but I was wrong?

No, you are right, the PR changes arrow functions too. But in the RFC we 
decided to not touch the arrow functions for now.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] [Under Discussion] New Curl URL API

2022-06-30 Thread Pierrick Charron
Hi all,


> - The new CurlUrl class should probably be immutable from the start. It
> was my biggest mistake not to do that with DateTime.
>
>
After thinking about it and some discussions, I followed Derick's
recommendation and therefore changed the RFC to make the CurlUrl class
immutable. All the setters were replaced by new `with*` methods.
For example setHost is now withHost and will return a new object with the
host modified. This will prevent confusing behavior where the CurlUrl
object would be unintentionally modified after being attached to a
CurlHandle.

Pierrick


Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Guilliam Xavier
On Thu, Jun 30, 2022 at 5:57 PM Arnaud Le Blanc  wrote:
>
> Hi,
>
> On jeudi 30 juin 2022 16:18:44 CEST Robert Landers wrote:
> > Are
> > optimizations going to be applied to single-line arrow functions (I
> > didn't see that in the RFC, but I admittedly didn't look that hard and
> > I vaguely remember reading something about it in one of these
> > threads)? If so, it will probably change some behaviors in existing
> > applications if they were relying on it. Perhaps static analysis tools
> > can detect this and inform the developer.
>
> It is not planned to change the behavior of arrow functions in this RFC. This
> optimization is less important for arrow functions because they don't usually
> assign variables.

Ah? Sorry, I had interpreted
https://github.com/php/php-src/pull/8330/files#diff-85701127596aca0e597bd7961b5d59cdde4f6bb3e2a109a22be859ab7568b4d2R7318-R7320
as "capture the *minimal* set of variables for *both* arrow functions
and short closures", but I was wrong?

I don't see a test like this:

```php
class C {
public function __destruct() { echo 'destructed', PHP_EOL; }
}
$x = new C();
$fn = fn ($a, $b) => (($x = $a ** 2) + ($y = $b ** 2)) * ($x - $y);
echo '- unsetting $x', PHP_EOL;
unset($x);
echo '- calling $fn', PHP_EOL;
var_dump($fn(3, 2));
echo '- unsetting $fn', PHP_EOL;
unset($fn);
echo '- DONE.', PHP_EOL;
```

with current output (https://3v4l.org/ve3BL#v8.1.7):

```
- unsetting $x
- calling $fn
int(65)
- unsetting $fn
destructed
- DONE.
```

where the optimization would make the "destructed" line move up to
just after "- unsetting $x"

-- 
Guilliam Xavier

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Robert Landers
On Thu, Jun 30, 2022 at 5:47 PM Guilliam Xavier
 wrote:
>
> On Thu, Jun 30, 2022 at 3:26 PM Dan Ackroyd  wrote:
> >
> > Hi Rowan,
> >
> > Rowan wrote:
> > > For that to work, it would require the variable to be captured by
> > > reference, not value.
> > > ...
> > > The only way for it to work would be using capture by reference (not
> > > supported by the proposed short syntax):
> >
> > I wrote about this before. Some of the words in the RFC are, in my
> > opinion, quite inaccurate:
> >
> > Danack wrote in https://news-web.php.net/php.internals/117938 :
> > > Those statements are true for scalar values. They are not true for 
> > > objects:
>
> But the RFC has been updated since (notably the DateTime example); do
> you find the current wording still inaccurate?
>
> > With automatic capturing of variables, for the code example I gave the
> > user would want the variable to be captured, and to them it looks like
> > it should be, but because of an optimization it is not.
>
> Am I missing something here? To me, it has been explained (and shown)
> by Rowan (and me) that the code example you gave would *not* work as
> expected *even without the optimization* (for it to work it would need
> to either capture by *reference*, or use e.g.
> `$some_resource->close();` [or `close($some_resource);`] instead of a
> destructor); but maybe we don't "expect" the same behavior in the
> first place?
>
> > When the code doesn't work as they expect it to, the programmer is
> > likely to add a var_dump to try to see what is happening. Which makes
> > it look like their code 'should' work, as their resource object is
> > still alive.
>
> This indeed seems a valid point (that adding a
> `var_dump($some_resource);` before the `$some_resource = null;`
> changes it from "not captured" to "captured", with an effect on its
> lifetime). But are there "real" cases where it would *actually*
> matter?
>
> > > In fact, the "optimisation" is in my opinion a critical part of the
> > > semantics, to avoid the opposite problem:
> >
> > As I said, I think that problem is a lot easier to explain "either use
> > long closures or change your variable name if you don't want it
> > captured." than trying to explain "yes, the variable is referenced
> > inside the closure, but it's not captured because you aren't reading
> > from it".
>
> Same as above.
>
>
> On Thu, Jun 30, 2022 at 4:19 PM Robert Landers  
> wrote:
> >
> > Rowan wrote:
> > > No, the captured value is tied to the lifetime of the closure itself,
> > not the variable inside the closure.
> >
> > With the "optimization," it won't be captured at all by the closure,
> > possibly causing some resources to go out of scope early.
>
> And it has been explained that conversely, capturing it would possible
> cause some resources to "remain in scope" late.
>
> > Are
> > optimizations going to be applied to single-line arrow functions (I
> > didn't see that in the RFC, but I admittedly didn't look that hard and
> > I vaguely remember reading something about it in one of these
> > threads)?
>
> Seems so: 
> https://github.com/php/php-src/pull/8330/files#diff-85701127596aca0e597bd7961b5d59cdde4f6bb3e2a109a22be859ab7568b4d2R7318-R7320
>
> > If so, it will probably change some behaviors in existing
> > applications if they were relying on it. Perhaps static analysis tools
> > can detect this and inform the developer.
>
> Here too, do you have a "real" case where it would *actually* matter?
>
> > Here's Dan's code: https://3v4l.org/99XUN#v8.1.7 that he just sent,
> > modified to not capture the $some_resource and you can see that it is
> > indeed released earlier than if it were captured.
>
> And here it is "un-modified": https://3v4l.org/gZai2 where you see
> that calling $fn() (which internally nullifies *its local copy of*
> $some_resource) does *not* release; is it really what you expect? are
> you creating the closure only to extend the lifetime of
> $some_resource?
>
>
> Regards,
>
> --
> Guilliam Xavier
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

> And here it is "un-modified": https://3v4l.org/gZai2 where you see
that calling $fn() (which internally nullifies *its local copy of*
$some_resource) does *not* release; is it really what you expect? are
you creating the closure only to extend the lifetime of $some_resource?

Personally, not that I'm aware of, which is the point. This may subtly
change code that works just fine today and it will be hard to track it
down. Though perhaps static analysis/IDE's will help track it down by
pointing out automatically captured vs. non-captured variables.

Ah, I see Arnaud just confirmed that it won't be applied to existing
arrow functions. Perhaps this is a moot point and it will be just
another quirk to be aware of when writing PHP. I was just worried
about it being applied to any existing code.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: 

Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Arnaud Le Blanc
Hi,

On jeudi 30 juin 2022 16:18:44 CEST Robert Landers wrote:
> Are
> optimizations going to be applied to single-line arrow functions (I
> didn't see that in the RFC, but I admittedly didn't look that hard and
> I vaguely remember reading something about it in one of these
> threads)? If so, it will probably change some behaviors in existing
> applications if they were relying on it. Perhaps static analysis tools
> can detect this and inform the developer.

It is not planned to change the behavior of arrow functions in this RFC. This 
optimization is less important for arrow functions because they don't usually 
assign variables.

This could be a follow up RFC though.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Guilliam Xavier
On Thu, Jun 30, 2022 at 3:26 PM Dan Ackroyd  wrote:
>
> Hi Rowan,
>
> Rowan wrote:
> > For that to work, it would require the variable to be captured by
> > reference, not value.
> > ...
> > The only way for it to work would be using capture by reference (not
> > supported by the proposed short syntax):
>
> I wrote about this before. Some of the words in the RFC are, in my
> opinion, quite inaccurate:
>
> Danack wrote in https://news-web.php.net/php.internals/117938 :
> > Those statements are true for scalar values. They are not true for objects:

But the RFC has been updated since (notably the DateTime example); do
you find the current wording still inaccurate?

> With automatic capturing of variables, for the code example I gave the
> user would want the variable to be captured, and to them it looks like
> it should be, but because of an optimization it is not.

Am I missing something here? To me, it has been explained (and shown)
by Rowan (and me) that the code example you gave would *not* work as
expected *even without the optimization* (for it to work it would need
to either capture by *reference*, or use e.g.
`$some_resource->close();` [or `close($some_resource);`] instead of a
destructor); but maybe we don't "expect" the same behavior in the
first place?

> When the code doesn't work as they expect it to, the programmer is
> likely to add a var_dump to try to see what is happening. Which makes
> it look like their code 'should' work, as their resource object is
> still alive.

This indeed seems a valid point (that adding a
`var_dump($some_resource);` before the `$some_resource = null;`
changes it from "not captured" to "captured", with an effect on its
lifetime). But are there "real" cases where it would *actually*
matter?

> > In fact, the "optimisation" is in my opinion a critical part of the
> > semantics, to avoid the opposite problem:
>
> As I said, I think that problem is a lot easier to explain "either use
> long closures or change your variable name if you don't want it
> captured." than trying to explain "yes, the variable is referenced
> inside the closure, but it's not captured because you aren't reading
> from it".

Same as above.


On Thu, Jun 30, 2022 at 4:19 PM Robert Landers  wrote:
>
> Rowan wrote:
> > No, the captured value is tied to the lifetime of the closure itself,
> not the variable inside the closure.
>
> With the "optimization," it won't be captured at all by the closure,
> possibly causing some resources to go out of scope early.

And it has been explained that conversely, capturing it would possible
cause some resources to "remain in scope" late.

> Are
> optimizations going to be applied to single-line arrow functions (I
> didn't see that in the RFC, but I admittedly didn't look that hard and
> I vaguely remember reading something about it in one of these
> threads)?

Seems so: 
https://github.com/php/php-src/pull/8330/files#diff-85701127596aca0e597bd7961b5d59cdde4f6bb3e2a109a22be859ab7568b4d2R7318-R7320

> If so, it will probably change some behaviors in existing
> applications if they were relying on it. Perhaps static analysis tools
> can detect this and inform the developer.

Here too, do you have a "real" case where it would *actually* matter?

> Here's Dan's code: https://3v4l.org/99XUN#v8.1.7 that he just sent,
> modified to not capture the $some_resource and you can see that it is
> indeed released earlier than if it were captured.

And here it is "un-modified": https://3v4l.org/gZai2 where you see
that calling $fn() (which internally nullifies *its local copy of*
$some_resource) does *not* release; is it really what you expect? are
you creating the closure only to extend the lifetime of
$some_resource?


Regards,

-- 
Guilliam Xavier

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



RE: [PHP-DEV] [RFC] Exception type hint

2022-06-30 Thread Jeffrey Dafoe
> -Original Message-
> From: Larry Garfield 
> Sent: Wednesday, June 29, 2022 12:39 PM
> To: php internals 
> Subject: Re: [PHP-DEV] [RFC] Exception type hint
> 
> On Wed, Jun 29, 2022, at 10:42 AM, Guilliam Xavier wrote:
> > Hi (note: your message was flagged as spam),
> >
> >> https://github.com/php/php-src/issues/8843
> >
> > So I understand it as having a "true code" equivalent for the
> > `@throws` phpDoc comment (similar to type declarations for `@param`
> > and `@return`)? which would also be checked at run-time?
> >
> > Just my 2 cents on that (let's call it "exception specification"):
> >
> >   1. IMHO, it shouldn't be mixed in the return type declaration (with
> > a union-like syntax) but separated and independent (e.g. with a
> > `throws` keyword, and pipes [or commas] between multiple exception
> > classes)
> >   2. AFAIK, Java has it (mandatory to compile for "checked
> > exceptions", sometimes controversial), C++ used to have it
> > (runtime-checked) but dropped it (and introduced `noexcept` instead);
> > I don't know of any dynamic language that has it
> >
> > You would also need to define how it plays with inheritance (and
> > reflection), and what exactly should happen when a function throws an
> > exception it didn't "declare"...
> >
> > PS: I also found some old feature requests:
> >   - https://externals.io/message/4424
> >   - https://bugs.php.net/bug.php?id=42251
> >   - https://bugs.php.net/bug.php?id=62404
> >   - https://bugs.php.net/bug.php?id=67312
> >
> > Regards,
> 
> Side Note: Please don't top post.
> 
> On the subject of checked exceptions, I *highly* recommend this writeup
> from the lead of the Midori language[1].  It's long, but there's a section
> specifically on exceptions (no deep link, just search the page for it) that 
> goes
> into a lot of detail about exceptions, checked exceptions, and the ways in
> which both fail.  It's absolutely worth everyone's time.
> 
> The summary for the short-timed is that the only way exceptions work, from
> a reliability standpoint, is if they are 1) Rare and 2) Strictly checked and 
> 3)
> Have really good syntactic shorthand support.  And checked exceptions
> without the other two are a recipe for hell.  Basically, it only works if
> exceptions become an alternate syntax for an Either monad or Go's multi-
> return.
> 
> Since PHP is a long, long way from there, I don't believe checked exceptions
> would be wise, or even slightly a good idea.  Not until/unless it's done as 
> part
> of a global rethink of error handling that reimagines how exceptions and
> errors work at a fundamental level.  And that couldn't be done in a BC way
> with the current practice of "I dunno, throw, YOLO" in PHP exceptions, so
> they'd have to be some other, different channel.  We are definitely not
> ready for that kind of fundamental rethink of how error handling works in
> PHP.
> 
> [1] http://joeduffyblog.com/2016/02/07/the-error-model/
> 
> --
> PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit:
> https://www.php.net/unsub.php

There's also a decent article here 
https://www.artima.com/articles/the-trouble-with-checked-exceptions where 
Anders Hejlsberg discusses the problems he sees with checked exceptions.


-Jeff

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Rowan Tommins

On 30/06/2022 14:25, Dan Ackroyd wrote:

With automatic capturing of variables, for the code example I gave the
user would want the variable to be captured, and to them it looks like
it should be, but because of an optimization it is not.



Please look again at the detailed explanation I gave, and the examples 
that Guilliam posted. Your example can *only* work if the variable is 
captured by reference, because it requires the statement *inside* the 
closure to have an effect on a variable *outside* the closure. No 
version of auto-capture has ever proposed capturing by reference.


If instead of $some_resource = null; you wrote 
$some_container->some_resource = null; then that would have an effect on 
the object, but the "optimisation" would be irrelevant because the use 
of $some_container itself is not an assignment.




As I said, I think that problem is a lot easier to explain "either use
long closures or change your variable name if you don't want it
captured." than trying to explain "yes, the variable is referenced
inside the closure, but it's not captured because you aren't reading
from it".



Right now, assigning (or unsetting) a variable is the *only* way to 
force it to be local. That's why I said I would be more likely to 
support this feature alongside a "var" or "let" keyword to make such 
variables explicit. Not being able to have local variables *at all* 
other than by very careful variable naming is a terrible idea.



Just to re-iterate, here's your new example with explicit capture, to 
demonstrate that the closure *does not and cannot free the resource*: 
https://3v4l.org/WrTb5


class ResourceType
{
public function __destruct() {
echo "Resource is released.\n";
}
}

function get_callback()
{
$some_resource = new ResourceType();
$fn = function() use ($some_resource) {
// this line does nothing
// it overwrites a local variable which is never read
// next time the closure runs, it will start again as the captured value
$some_resource = null;
};
return $fn;
}

$fn = get_callback();
echo "Before callback\n";
$fn();
echo "After callback\n";
unset($some_resource);
echo "After destroying outer var\n";
// the captured reference is still live here, no matter how many times we call 
$fn()
// only destroying the closure frees it
unset($fn);
echo "After destroying closure\n";


One way of thinking of it is that assignments inside a closure are 
assignments to a local variable, which "shadow" any captured variable 
with the same name. If all you do with a variable is shadow it, then it 
is illogical to consider it "used" in that function.



On 30/06/2022 15:18, Robert Landers wrote:

Are
optimizations going to be applied to single-line arrow functions (I
didn't see that in the RFC, but I admittedly didn't look that hard and
I vaguely remember reading something about it in one of these
threads)?



I would expect so, yes. It could be considered a bug that the arrow 
function implementation currently "over-captures" variables, and it only 
wasn't a higher priority in Nikita's RFC because it is extremely rare 
that a single expression closure would have any local variables. Indeed, 
that lack of local scope is one of the big reasons why I and others 
supported that RFC, because it avoids all the confusion evident in 
today's messages.



Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Exception type hint

2022-06-30 Thread Larry Garfield
On Thu, Jun 30, 2022, at 8:35 AM, Dan Ackroyd wrote:
> Antoine wrote:
>> It could be beneficial for the whole ecosystem to have as well exceptions 
>> type hint.
>
> Here are my short notes on the topic.
> https://github.com/Danack/RfcCodex/blob/master/throws_declaration.md
>
> tl:dr someone probably needs to come up with a strong reason for why
> it would be a good thing.
>
> On Wed, 29 Jun 2022 at 17:39, Larry Garfield  wrote:
>>
>>   We are definitely not ready for that kind of fundamental rethink of how 
>> error handling works in PHP.
>
> I dunno. The current model is causing quite a few disagreements and
> pain, and you made a good case for how it could be better.
>
> It'd be a huge piece of work, but a better way of handling errors
> would be a significant improvement for PHP.

Oh there's definitely room to improve PHP's error handling, no question.  I 
just don't know that PHP is, at this time, capable of the "coherent multi-step 
roadmap so that different features dovetail together to result in more than the 
sum of their parts" planning that would be required to do it right. :-)

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Robert Landers
On Thu, Jun 30, 2022 at 3:26 PM Dan Ackroyd  wrote:
>
> Hi Rowan,
>
> Rowan wrote:
> > For that to work, it would require the variable to be captured by
> > reference, not value.
> > ...
> > The only way for it to work would be using capture by reference (not
> > supported by the proposed short syntax):
>
> I wrote about this before. Some of the words in the RFC are, in my
> opinion, quite inaccurate:
>
> Danack wrote in https://news-web.php.net/php.internals/117938 :
> > Those statements are true for scalar values. They are not true for objects:
>
> With automatic capturing of variables, for the code example I gave the
> user would want the variable to be captured, and to them it looks like
> it should be, but because of an optimization it is not.
>
> When the code doesn't work as they expect it to, the programmer is
> likely to add a var_dump to try to see what is happening. Which makes
> it look like their code 'should' work, as their resource object is
> still alive.
>
> > In fact, the "optimisation" is in my opinion a critical part of the
> > semantics, to avoid the opposite problem:
>
> As I said, I think that problem is a lot easier to explain "either use
> long closures or change your variable name if you don't want it
> captured." than trying to explain "yes, the variable is referenced
> inside the closure, but it's not captured because you aren't reading
> from it".
>
> cheers
> Dan
> Ack
>
>
> For this code, comment the var_dump in/out to affect the lifetime of the 
> object.
>
> class ResourceType
> {
> public function __destruct() {
> echo "Resource is released.\n";
> }
> }
>
> function get_callback()
> {
> $some_resource = new ResourceType();
> $fn = fn() {
> // // why is my lock released?
> var_dump($some_resource);
> // "Free that resource"
> $some_resource = null;
> };
> return $fn;
> }
>
> $fn = get_callback();
> echo "Before callback\n";
> $fn();
> echo "After callback\n";
>
> // Without var_dump
> Resource is released.
> Before callback
> After callback
>
> // With var_dump
> Before callback
> object(ResourceType)#1 (0) {
> }
> After callback
> Resource is released.
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

Rowan wrote:
> No, the captured value is tied to the lifetime of the closure itself,
not the variable inside the closure.

With the "optimization," it won't be captured at all by the closure,
possibly causing some resources to go out of scope early. Are
optimizations going to be applied to single-line arrow functions (I
didn't see that in the RFC, but I admittedly didn't look that hard and
I vaguely remember reading something about it in one of these
threads)? If so, it will probably change some behaviors in existing
applications if they were relying on it. Perhaps static analysis tools
can detect this and inform the developer.

Here's Dan's code: https://3v4l.org/99XUN#v8.1.7 that he just sent,
modified to not capture the $some_resource and you can see that it is
indeed released earlier than if it were captured.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Exception type hint

2022-06-30 Thread Dan Ackroyd
Antoine wrote:
> It could be beneficial for the whole ecosystem to have as well exceptions 
> type hint.

Here are my short notes on the topic.
https://github.com/Danack/RfcCodex/blob/master/throws_declaration.md

tl:dr someone probably needs to come up with a strong reason for why
it would be a good thing.

On Wed, 29 Jun 2022 at 17:39, Larry Garfield  wrote:
>
>   We are definitely not ready for that kind of fundamental rethink of how 
> error handling works in PHP.

I dunno. The current model is causing quite a few disagreements and
pain, and you made a good case for how it could be better.

It'd be a huge piece of work, but a better way of handling errors
would be a significant improvement for PHP.

cheers
Dan
Ack

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Dan Ackroyd
Hi Rowan,

Rowan wrote:
> For that to work, it would require the variable to be captured by
> reference, not value.
> ...
> The only way for it to work would be using capture by reference (not
> supported by the proposed short syntax):

I wrote about this before. Some of the words in the RFC are, in my
opinion, quite inaccurate:

Danack wrote in https://news-web.php.net/php.internals/117938 :
> Those statements are true for scalar values. They are not true for objects:

With automatic capturing of variables, for the code example I gave the
user would want the variable to be captured, and to them it looks like
it should be, but because of an optimization it is not.

When the code doesn't work as they expect it to, the programmer is
likely to add a var_dump to try to see what is happening. Which makes
it look like their code 'should' work, as their resource object is
still alive.

> In fact, the "optimisation" is in my opinion a critical part of the
> semantics, to avoid the opposite problem:

As I said, I think that problem is a lot easier to explain "either use
long closures or change your variable name if you don't want it
captured." than trying to explain "yes, the variable is referenced
inside the closure, but it's not captured because you aren't reading
from it".

cheers
Dan
Ack


For this code, comment the var_dump in/out to affect the lifetime of the object.

class ResourceType
{
public function __destruct() {
echo "Resource is released.\n";
}
}

function get_callback()
{
$some_resource = new ResourceType();
$fn = fn() {
// // why is my lock released?
var_dump($some_resource);
// "Free that resource"
$some_resource = null;
};
return $fn;
}

$fn = get_callback();
echo "Before callback\n";
$fn();
echo "After callback\n";

// Without var_dump
Resource is released.
Before callback
After callback

// With var_dump
Before callback
object(ResourceType)#1 (0) {
}
After callback
Resource is released.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Rowan Tommins

On 30/06/2022 11:29, Arnaud Le Blanc wrote:


I feel that the RAII pattern aka SBRM / Scope-Bound Resource Management is not
relevant in PHP context, and I don't believe that it's commonly used in PHP or
in garbage collected language.



I've used a simple version of the pattern effectively to implement 
transactions: if the Transaction object goes out of scope without being 
explicitly committed or rolled back, it assumes the program hit an 
unexpected error condition and rolls back.




One way the lifetime of a value could be extended is via a reference cycle.
These are easy to introduce and difficult to prevent or observe (e.g. in a
test or in an assertion).



I would expect reference cycles to be pretty rare in most code, 
particularly when you're dealing with a value with a short lifetime as 
is involved in most RAII scenarios.


The worst-case release of the cycle can also be made predictable by 
running gc_collect_cycles()




An other way would be by referencing the value
somewhere else. You can not guarantee that the lifetime of a value is
unaffected after passing it to a function.



Surely the only way to avoid that is with something like Rust's "borrow 
checker"? Otherwise, any function that has a reference to something can 
extend the lifetime of that reference by storing it inside some other 
structure with a longer lifetime. Manually freeing the underlying 
resource then just leads to a "use after free" error.




Another factor that makes RAII un-viable in PHP is that the order of the
destructor calls is unspecified. Currently, if multiple objects go out of
scope at the same time, they happen to be called in a FIFO order, which is not
what is needed when using the RAII pattern [0][1].



I can imagine this would be a problem for some advanced uses of the 
pattern, but for a simple "acquire lock, release on scope exit" or 
"start transaction, rollback on unexpected scope exit", it's generally 
not relevant.




Other languages typically have other ways to explicitly manage the lifetime of
resources. Go has `defer()` [2]. Python has context managers / `with` [3], C#
has `using` [4]. `with` and `using` can be implemented in userland in PHP.



My understanding is that C#'s "using" is indeed about deterministic 
destruction, but Pythons's "with" is a more powerful 
inversion-of-control mechanism. I would actually really love to have 
some version of Python's context managers in PHP, and think it would be 
a better alternative to closures in a lot of cases.


For instance, a motivation cited in support of auto-capture is something 
like this:


function doSomething($a, $b, $c) {
   return $db->doInTransaction(fn() {
   // use $a, $b, and $c
   // roll back on exception, commit otherwise
   return $theActualResult;
   }
}

But this is actually quite a "heavy" implementation: we create a 
Closure, capture values, enter a new stack frame, and have two return 
statements, just to wrap the code in try...catch...finally boilerplate.


The equivalent with a context manager would look something like this:

function doSomething($a, $b, $c) {
   with ( $db->startTransaction() as $transaction ) {
   // use $a, $b, and $c
   // roll back on exception, commit otherwise
   return $theActualResult;
   }
}

Here, the with statement doesn't create a new stack frame, it just 
triggers a series of callbacks for the boilerplate at the start and end 
of the block. No variables need to be captured, because they are all 
still available, and "return" returns from the doSomething() function, 
not the transaction wrapper.


The explanation of how Python's implementation works and why is an 
interesting read: https://peps.python.org/pep-0343/



Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Arnaud Le Blanc
Hi,

On jeudi 30 juin 2022 00:31:44 CEST Dan Ackroyd wrote:
> On Wed, 29 Jun 2022 at 18:30, Larry Garfield  wrote:
> > The conversation has died down, so we'll be opening the vote for this
> > tomorrow.
> I think I've just thought of a problem with the optimization bit of
> 'not capturing variables if they are written to before being used
> inside the closure'.
> 
> Imagine some code that looks like this:
> 
> // Acquire some resource e.g. an exclusive lock.
> $some_resource = acquire_some_resource();
> 
> $fn = fn () {
> // Free that resource
> $some_resource = null;
> }
> 
> // do some stuff that assumes the exclusive
> // lock is still active.
> 
> // call the callback that we 'know' frees the resource
> $fn();
> 
> That's a not unreasonable piece of code to write even if it's of a
> style many people avoid. I believe in C++ it's called "Resource
> acquisition is initialization", though they're trying to change the
> name to "Scope-Bound Resource Management" as that is a better
> description of what it is.

I feel that the RAII pattern aka SBRM / Scope-Bound Resource Management is not 
relevant in PHP context, and I don't believe that it's commonly used in PHP or 
in garbage collected language.

Also, in this particular code example, using an explicit fclose() would be 
better in every way, including legibility and reliability, so this doesn't 
appear to be realistic code.

Because of this, I don't think that we should be taking decisions on this 
feature based on this use case.

I've used the RAII pattern in PHP to manage temporary files, as a best-effort 
way to remove them (in a destructor) when they are not used anymore. However I 
would not rely on this for anything more critical or anything that requires 
predictability in resource release timing.

RAII is useful in C++ because memory is managed manually. This is not the case 
in PHP.

It's also useful in C++ to manage other kinds of resources such as file 
pointers or locks. In PHP it would be dangerous because you don't 
realistically control the lifetime of values, so you also don't control the 
timing at which the resources are closed. It's too easy to extend the lifetime 
of a value accidentally.

One way the lifetime of a value could be extended is via a reference cycle. 
These are easy to introduce and difficult to prevent or observe (e.g. in a  
test or in an assertion). An other way would be by referencing the value 
somewhere else. You can not guarantee that the lifetime of a value is 
unaffected after passing it to a function.

In C++ it's different because no code would implicitly keep a reference to a 
variable passed to it unless it was part of that code's contract, or unless 
the variable was refcounted.

Another factor that makes RAII un-viable in PHP is that the order of the 
destructor calls is unspecified. Currently, if multiple objects go out of 
scope at the same time, they happen to be called in a FIFO order, which is not 
what is needed when using the RAII pattern [0][1].

I think that RAII can only realistically be used in a non-managed, non-
refcounted, non-GC language. GC or reference counting should not be used to 
manage anything else than memory allocation.

Other languages typically have other ways to explicitly manage the lifetime of 
resources. Go has `defer()` [2]. Python has context managers / `with` [3], C# 
has `using` [4]. `with` and `using` can be implemented in userland in PHP.

Because of all these reasons, I don't think that RAII in PHP is practical or 
actually used. So I don't think that we should be taking decisions on Short 
Closures based on this use case.

> With the optimization in place, that code would not behave
> consistently with how the rest of PHP works

There exist no circumstance in PHP in which the existence of the statement
`$a = null` would extend the lifetime of the value bound to `$a`.

[0] Destructor order PHP: https://3v4l.org/iGAPj
[1] Destructor order C++: https://godbolt.org/z/f78Pa9j69
[2] https://go.dev/doc/effective_go#defer
[3] https://docs.python.org/3/reference/compound_stmts.html#with
[4] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/
keywords/using-statement

Cheers,
--
Arnaud Le Blanc

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Guilliam Xavier
On Thu, Jun 30, 2022 at 11:20 AM Robert Landers
 wrote:
>
> On Thu, Jun 30, 2022 at 10:19 AM Rowan Tommins  
> wrote:
> >
> > On 29/06/2022 23:31, Dan Ackroyd wrote:
> > > Imagine some code that looks like this:
> > >
> > > // Acquire some resource e.g. an exclusive lock.
> > > $some_resource = acquire_some_resource();
> > >
> > > $fn = fn () {
> > >  // Free that resource
> > >  $some_resource = null;
> > > }
> > >
> > > // do some stuff that assumes the exclusive
> > > // lock is still active.
> > >
> > > // call the callback that we 'know' frees the resource
> > > $fn();
> > >
> > > That's a not unreasonable piece of code to write
> >
> >
> > For that to work, it would require the variable to be captured by
> > reference, not value. Writing to a variable captured by value, like
> > writing to a parameter passed by value, is just writing to a local variable.
> >
> >
> > In fact, the "optimisation" is in my opinion a critical part of the
> > semantics, to avoid the opposite problem:
> >
> > // Acquire some resource e.g. an exclusive lock.
> > $some_resource = acquire_some_resource();
> >
> > $fn = fn () {
> >  // Use a variable that happens to have the same name
> >  // A naive implementation would see $some_resource mentioned, and
> > capture it
> >  // Over-writing the local variable here makes no difference; the
> > closure still holds the value for next time
> >  $some_resource = 'hello';
> > }
> >
> > // Free what we believe is the last pointer, to trigger the destructor
> > unset($some_resource);
> >
> > // If $some_resource gets captured, it can only be released by
> > destroying the closure
> > unset($fn);
> >
> >
> > Regards,
> >
> > --
> > Rowan Tommins
> > [IMSoP]
> >
> > --
> > PHP Internals - PHP Runtime Development Mailing List
> > To unsubscribe, visit: https://www.php.net/unsub.php
> >
>
> > For that to work, it would require the variable to be captured by
> > reference, not value.
>
> I think their suggested code would work (at least currently in PHP) by
> the simple fact they would increase the reference count on that
> object/resource until they set it as null. However, with the
> "optimization," the reference count will never be incremented and thus
> fail to work as defined.
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

No offense, but why don't you just try it? Please see equivalents of:
  - Dan's code: https://3v4l.org/51jXY => doesn't "work"
  - Dan's code with capture by reference (as said by Rowan):
https://3v4l.org/JoUVi => "works"
  - Rowan's code: https://3v4l.org/7ZVv3 => shows the "problem" with capture

PS: I see that Rowan just replied with refcount explanations. I agree
(but am sending this anyway)

Regards,

-- 
Guilliam Xavier

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Rowan Tommins

On 30/06/2022 10:20, Robert Landers wrote:

I think their suggested code would work (at least currently in PHP) by
the simple fact they would increase the reference count on that
object/resource until they set it as null. However, with the
"optimization," the reference count will never be incremented and thus
fail to work as defined.



No, the captured value is tied to the lifetime of the closure itself, 
not the variable inside the closure.


$some_resource = acquire_some_resource();
// refcount=1 (outer $some_resource)

$fn = function() use ($some_resource) {
    $some_resource = null;
}
// refcount=2 (outer $some_resource, closure $fn)

$fn();
// during execution, refcount is 3 (outer $some_resource, closure $fn, 
local $some_resource)
// once the local variable is written to, the refcount goes back to 2 
(outer $some_resource, closure $fn)


unset($some_resource);
// refcount=1 (closure $fn)

$fn();
// the captured variable always starts with its original value, 
regardless of how many times you execute the function

// during execution, refcount is now 2 (closure $fn, local $some_resource)
// after execution, refcount is still 1 (closure $fn)

unset($fn);
// only now does the refcount go down to 0 and trigger the destructor


The only way for it to work would be using capture by reference (not 
supported by the proposed short syntax):


$some_resource = acquire_some_resource();
// refcount=1: simple variable

$fn = function() use (&$some_resource) {
    $some_resource = null;
}
// refcount=1: a reference set with 2 members (outer $some_resource, 
closure $fn)


$fn();
// during execution, we have a reference set with 3 members (outer 
$some_resource, closure $fn, local $some_resource)
// the assignment assigns to this reference set, changing the value 
referenced by all 3 members

// refcount on the resource drops from 1 to 0, triggering the destructor

$fn();
// because it was captured by reference, the initial value of 
$some_resource in the closure has now changed



Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Robert Landers
On Thu, Jun 30, 2022 at 10:19 AM Rowan Tommins  wrote:
>
> On 29/06/2022 23:31, Dan Ackroyd wrote:
> > Imagine some code that looks like this:
> >
> > // Acquire some resource e.g. an exclusive lock.
> > $some_resource = acquire_some_resource();
> >
> > $fn = fn () {
> >  // Free that resource
> >  $some_resource = null;
> > }
> >
> > // do some stuff that assumes the exclusive
> > // lock is still active.
> >
> > // call the callback that we 'know' frees the resource
> > $fn();
> >
> > That's a not unreasonable piece of code to write
>
>
> For that to work, it would require the variable to be captured by
> reference, not value. Writing to a variable captured by value, like
> writing to a parameter passed by value, is just writing to a local variable.
>
>
> In fact, the "optimisation" is in my opinion a critical part of the
> semantics, to avoid the opposite problem:
>
> // Acquire some resource e.g. an exclusive lock.
> $some_resource = acquire_some_resource();
>
> $fn = fn () {
>  // Use a variable that happens to have the same name
>  // A naive implementation would see $some_resource mentioned, and
> capture it
>  // Over-writing the local variable here makes no difference; the
> closure still holds the value for next time
>  $some_resource = 'hello';
> }
>
> // Free what we believe is the last pointer, to trigger the destructor
> unset($some_resource);
>
> // If $some_resource gets captured, it can only be released by
> destroying the closure
> unset($fn);
>
>
> Regards,
>
> --
> Rowan Tommins
> [IMSoP]
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

> For that to work, it would require the variable to be captured by
> reference, not value.

I think their suggested code would work (at least currently in PHP) by
the simple fact they would increase the reference count on that
object/resource until they set it as null. However, with the
"optimization," the reference count will never be incremented and thus
fail to work as defined.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] [RFC] Short Closures 2, aka auto-capture take 3

2022-06-30 Thread Rowan Tommins

On 29/06/2022 23:31, Dan Ackroyd wrote:

Imagine some code that looks like this:

// Acquire some resource e.g. an exclusive lock.
$some_resource = acquire_some_resource();

$fn = fn () {
 // Free that resource
 $some_resource = null;
}

// do some stuff that assumes the exclusive
// lock is still active.

// call the callback that we 'know' frees the resource
$fn();

That's a not unreasonable piece of code to write



For that to work, it would require the variable to be captured by 
reference, not value. Writing to a variable captured by value, like 
writing to a parameter passed by value, is just writing to a local variable.



In fact, the "optimisation" is in my opinion a critical part of the 
semantics, to avoid the opposite problem:


// Acquire some resource e.g. an exclusive lock.
$some_resource = acquire_some_resource();

$fn = fn () {
    // Use a variable that happens to have the same name
    // A naive implementation would see $some_resource mentioned, and 
capture it
    // Over-writing the local variable here makes no difference; the 
closure still holds the value for next time

    $some_resource = 'hello';
}

// Free what we believe is the last pointer, to trigger the destructor
unset($some_resource);

// If $some_resource gets captured, it can only be released by 
destroying the closure

unset($fn);


Regards,

--
Rowan Tommins
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php