Re: [PHP-DEV] [RFC] Fiber support (again)

2018-02-08 Thread Haitao Lv


> On Feb 9, 2018, at 06:22, Niklas Keller  wrote:
> 
>> 
>>> - How do you determine when a fiber has returned? Looking at the source,
>> it appears Fiber::status() must be used, comparing against constants.
>> Separate methods similar to Generator would be better IMO. e.g.:
>> Fiber::alive(), Fiber::suspended(), Fiber::running()
>> 
>> Offering methods like Fiber::alive, Fiber::running makes no difference to
>> check the Fiber::status() return value. This is just a style issue. And as
>> a language feature,
>> Fiber only offer the essential API and let other works to the user land.
> 
> 
> The language should offer a sane API, not the absolute minimum required to
> work for these things.

The Ruby's Fiber do offer a live? method but does not have a getStatus method.
The Lua's coroutine only offer a status method.

So do we really need to offer three additional helper method? Or what is your
advice about these API?

> 
>>> - What about throwing exceptions into a fiber?
>> 
>> Currently does not support throw exception into the fiber. User land code
>> could check
>> the value of Fiber::yield and throw exception themselves. The Ruby's Fiber
>> and Lua's
>> coroutine also does not support such api as well.
> 
> 
> And throw the exception where? That means async code with fibers can't
> really handle errors?

Actually you can transfer any thing to Fiber by the resume method. And you can
check the return value of Fiber::yield to handle error.

Fiber is designed as a primitive, low level, and lightweight feature. User land
code seldom not need to use them directly in your normal code.
So the following is not a big problem,

$a = Fiber::yield(...);
if ($a === false) {
   throw new Exception(...);
}

And both the Ruby and Lua does not offer such API as well.
> 
>> 
>>> 
>>> - Using Fiber::resume() to initialize the fiber and resume feels
>> awkward. Separate methods again would be better here, perhaps
>> Fiber::init(...$args) and Fiber::resume($send).
>> 
>> All Fiber created with a suspended status. So make resume to do both the
>> init and resume
>> do make sense.
>> 
> 
> It does't make sense to me. Reading the example in the README and
> understanding why the first resume() takes two arguments instead of one
> took me quite some minutes.

This Ruby's Fiber and Lua's coroutine using one resume API to init and resume
the coroutine. I do not think a dedicate is really required.

The generator cannot be init by it's send method. And if you want to implement
coroutine feature(without stack) by it, you have to write code

function run() {
if ($this->beforeFirstYield) {
$this->beforeFirstYield = false;
return $this->coroutine->current();
} else {
$retval = $this->coroutine->send($this->sendValue);
$this->sendValue = null;
return $retval;  
}   
}

It is verbose.

See 
https://nikic.github.io/2012/12/22/Cooperative-multitasking-using-coroutines-in-PHP.html

> 
>> Please see Ruby Fiber API https://ruby-doc.org/core-2.2.0/Fiber.html.
>> 
>>> 
>>> - What happens if the sub1() function in the RFC is invoked outside of a
>> fiber?
>> 
>> You will get a Fatal Error like
>> Fatal error: Uncaught Error: Cannot call Fiber::yield out of Fiber
>> 
>>> - I think a keyword here would be beneficial, even if it has a minor BC
>> impact. Fibers could then be written like generators. `await` or `emit` as
>> a keyword perhaps? This would be a less verbose API, feel less magical (a
>> static method call that actually pauses execution feels out of place), and
>> would allow Fibers to be returned from methods, named functions, etc with
>> less boilerplate.
>> 
>> Wishing this to be accepted by the community in the PHP 7.3, so no keyword
>> is accepted.
>> And if the community cannot accept, the Fiber can be still distributed as
>> a standalone
>> extension. So we cannot depend on a new keyword.
> 
> 
> Right, if it's a standalone extension it can't use a new keyword, but as a
> language feature it totally can.

In my opinion, using a keyword or call a method is just a coding style problem.
Introducing a new keyword does not offer any benefit by makes a minor BC.

Both Ruby's Fiber and Lua's coroutine does not required a dedicate keyword.

> Looking at the current README, there are two issues that must be completely
> solved IMO before accepting this:
> 
>> Each Fiber has a separate 4k stack. You can use the fiber.stack_size ini
> option to change the default stack size. You can also use the second
> argument of Fiber::__construct to set the stack size on fly.
> 
> Resizing of the stack should happen automatically, just like generators
> resize automatically.

This size is the init stack size. It means when a Fiber created, it will get a
dedicate stack of 4k size. When the fiber use all the stack space, zend vm will
allocate additional space for feature call frame, automatically.

The default size is 4k means that every fiber requires at least 4k memory to use
as 

Re: [PHP-DEV] Suggested change: change priority of new and ->

2018-02-08 Thread Haralan Dobrev
I really like the proposal and it's definitely improving more common modern
use cases.

However, I understand why the precedence is like that now in PHP to begin
with and so I think this should target PHP 8.

This change would be a bit similar to other weird use cases of variables
which were changed with PHP 7.

Best,
Harry

On Thu, 8 Feb 2018 at 20:45 Mcmuffin Mcguffin 
wrote:

> Hi,
>
> It's a common idiom in object-oriented languages to create an object and
> then immediately call a method on it, such as (in C# or Java):
>
> new DateTime ().ToString ()
>
> However, PHP grammar does not work this way. You have to put an additional
> round of parentheses around new clause, such as:
>
> (new DateTime ())->format ('Y-m-d')
>
> This is rather clunky for such a common scenario (you usually have to walk
> all the way back to the beginning of the expression to fix it). I have a
> pattern of using static factories in place of constructor just to avoid
> extra parentheses. Besides, the issue is relatively easy to fix. I've done
> and tested a change for grammar in this area. It's a slight adjustment to
> definition of dereferencable:
>
> dereferencable:
> > variable{ $$ = $1; }
> > |'(' expr ')'{ $$ = $2; }
> > *|new_expr{ $$ = $1; }*
> > |dereferencable_scalar{ $$ = $1; }
> > ;
> >
>
> There was a problem with shift/reduces though. PHP has a level of
> complexity in new expression which other languages don't. It's variable
> class instantiation, such as:
>
> new $class (arguments)
>
> Expressions in place of $class can be rather complex, though I don't think
> they really need to be. For example, such stuff is allowed:
>
> new $var[0]->prop (arguments)
>
> — which seems redundant and confusing. My fix to the problem was to force
> parentheses around complex expressions such as above:
>
> new ($var[0]->prop) (arguments)
>
> — while keeping simple cases of "new $class (arguments)" without change.
> Yes, this moves parentheses from one place to another (and occasionally
> breaks the old code) but frequency wise I think it's an improvement.
>
> What do you think?
>
> Jaroslav Wegner
>
-- 

Haralan Dobrev
CTO @ Clippings.com

https://hkdobrev.com


Re: [PHP-DEV] [RFC] Fiber support (again)

2018-02-08 Thread Niklas Keller
>
> > - How do you determine when a fiber has returned? Looking at the source,
> it appears Fiber::status() must be used, comparing against constants.
> Separate methods similar to Generator would be better IMO. e.g.:
> Fiber::alive(), Fiber::suspended(), Fiber::running()
>
> Offering methods like Fiber::alive, Fiber::running makes no difference to
> check the Fiber::status() return value. This is just a style issue. And as
> a language feature,
> Fiber only offer the essential API and let other works to the user land.


The language should offer a sane API, not the absolute minimum required to
work for these things.


> > - What about throwing exceptions into a fiber?
>
> Currently does not support throw exception into the fiber. User land code
> could check
> the value of Fiber::yield and throw exception themselves. The Ruby's Fiber
> and Lua's
> coroutine also does not support such api as well.


And throw the exception where? That means async code with fibers can't
really handle errors?


>
> >
> > - Using Fiber::resume() to initialize the fiber and resume feels
> awkward. Separate methods again would be better here, perhaps
> Fiber::init(...$args) and Fiber::resume($send).
>
> All Fiber created with a suspended status. So make resume to do both the
> init and resume
> do make sense.
>

It does't make sense to me. Reading the example in the README and
understanding why the first resume() takes two arguments instead of one
took me quite some minutes.


> Please see Ruby Fiber API https://ruby-doc.org/core-2.2.0/Fiber.html.
>
> >
> > - What happens if the sub1() function in the RFC is invoked outside of a
> fiber?
>
> You will get a Fatal Error like
> Fatal error: Uncaught Error: Cannot call Fiber::yield out of Fiber
>
> > - I think a keyword here would be beneficial, even if it has a minor BC
> impact. Fibers could then be written like generators. `await` or `emit` as
> a keyword perhaps? This would be a less verbose API, feel less magical (a
> static method call that actually pauses execution feels out of place), and
> would allow Fibers to be returned from methods, named functions, etc with
> less boilerplate.
>
> Wishing this to be accepted by the community in the PHP 7.3, so no keyword
> is accepted.
> And if the community cannot accept, the Fiber can be still distributed as
> a standalone
> extension. So we cannot depend on a new keyword.


Right, if it's a standalone extension it can't use a new keyword, but as a
language feature it totally can.

Looking at the current README, there are two issues that must be completely
solved IMO before accepting this:

> Each Fiber has a separate 4k stack. You can use the fiber.stack_size ini
option to change the default stack size. You can also use the second
argument of Fiber::__construct to set the stack size on fly.

Resizing of the stack should happen automatically, just like generators
resize automatically.

> Fiber::yield cannot be used in internal callback

This also seems problematic and will make fibers quite less useful,
especially as these yields can happen anywhere down the stack.

Regards, Niklas


[PHP-DEV] Suggested change: change priority of new and ->

2018-02-08 Thread Mcmuffin Mcguffin
Hi,

It's a common idiom in object-oriented languages to create an object and
then immediately call a method on it, such as (in C# or Java):

new DateTime ().ToString ()

However, PHP grammar does not work this way. You have to put an additional
round of parentheses around new clause, such as:

(new DateTime ())->format ('Y-m-d')

This is rather clunky for such a common scenario (you usually have to walk
all the way back to the beginning of the expression to fix it). I have a
pattern of using static factories in place of constructor just to avoid
extra parentheses. Besides, the issue is relatively easy to fix. I've done
and tested a change for grammar in this area. It's a slight adjustment to
definition of dereferencable:

dereferencable:
> variable{ $$ = $1; }
> |'(' expr ')'{ $$ = $2; }
> *|new_expr{ $$ = $1; }*
> |dereferencable_scalar{ $$ = $1; }
> ;
>

There was a problem with shift/reduces though. PHP has a level of
complexity in new expression which other languages don't. It's variable
class instantiation, such as:

new $class (arguments)

Expressions in place of $class can be rather complex, though I don't think
they really need to be. For example, such stuff is allowed:

new $var[0]->prop (arguments)

— which seems redundant and confusing. My fix to the problem was to force
parentheses around complex expressions such as above:

new ($var[0]->prop) (arguments)

— while keeping simple cases of "new $class (arguments)" without change.
Yes, this moves parentheses from one place to another (and occasionally
breaks the old code) but frequency wise I think it's an improvement.

What do you think?

Jaroslav Wegner


Re: [PHP-DEV] [RFC] Fiber support (again)

2018-02-08 Thread Haitao Lv


> On Feb 8, 2018, at 12:18, Aaron Piotrowski  wrote:
> 
>> 
>> On Feb 7, 2018, at 7:05 PM, Haitao Lv  wrote:
>> 
>> Hi internals,
>> 
>> I propose to introduce the Fiber feature AGAIN.
>> 
>> The main purpose of the RFC is to introducing a lightweight stackful 
>> coroutine support for PHP and make it possible to write non-blocking code in 
>> the blocking style.
>> 
>> In this RFC, no new keyword is needed. So it will not break the PHP 7.3 
>> release.
>> 
>> Please see the RFC https://wiki.php.net/rfc/fiber
>> 
>> Dmitry and I are working on the implementation at 
>> https://github.com/fiberphp/fiber-ext
>> And a series of usage demo can be found at 
>> https://github.com/fiberphp/fiber-demo
>> 
>> Please offer you comments.
>> 
>> Thank you.
>> 
>> ---
>> Haitao Lv
>> 
> 
> 
> Hi Haitao,
> 
> I'm very excited to see this sort of feature coming to PHP.
> 
> A couple of questions and thoughts:
> 
> - How do you determine when a fiber has returned? Looking at the source, it 
> appears Fiber::status() must be used, comparing against constants. Separate 
> methods similar to Generator would be better IMO. e.g.: Fiber::alive(), 
> Fiber::suspended(), Fiber::running()

Offering methods like Fiber::alive, Fiber::running makes no difference to check 
the Fiber::status() return value. This is just a style issue. And as a language 
feature,
Fiber only offer the essential API and let other works to the user land.

> - What about throwing exceptions into a fiber?

Currently does not support throw exception into the fiber. User land code could 
check
the value of Fiber::yield and throw exception themselves. The Ruby's Fiber and 
Lua's
coroutine also does not support such api as well.

> 
> - Using Fiber::resume() to initialize the fiber and resume feels awkward. 
> Separate methods again would be better here, perhaps Fiber::init(...$args) 
> and Fiber::resume($send).

All Fiber created with a suspended status. So make resume to do both the init 
and resume
do make sense.

Please see Ruby Fiber API https://ruby-doc.org/core-2.2.0/Fiber.html.

> 
> - What happens if the sub1() function in the RFC is invoked outside of a 
> fiber?

You will get a Fatal Error like
Fatal error: Uncaught Error: Cannot call Fiber::yield out of Fiber

> - I think a keyword here would be beneficial, even if it has a minor BC 
> impact. Fibers could then be written like generators. `await` or `emit` as a 
> keyword perhaps? This would be a less verbose API, feel less magical (a 
> static method call that actually pauses execution feels out of place), and 
> would allow Fibers to be returned from methods, named functions, etc with 
> less boilerplate.

Wishing this to be accepted by the community in the PHP 7.3, so no keyword is 
accepted.
And if the community cannot accept, the Fiber can be still distributed as a 
standalone
extension. So we cannot depend on a new keyword.

> Thanks to you and Dmitry for working on this!
> 
> Aaron Piotrowski
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php




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