Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-22 Thread Leigh
On 21 March 2015 at 12:13, Georges.L cont...@geolim4.com wrote:

 Hi php internals,

 After some long and deep research i finally decided to write my first RFC
 about a feature i'd be interested to be improved in the php core: *Nested
 enclosing returns*


 The main purpose, as the title say, is to have the possibility to nest
 multiple return like we can do currently with break/continue.

 I thinks it'll being better with a scheme:




 function foo($foo = true)
 {
if(!$foo)
{
   return false, 3;// Please note the second return argument is the
 return nesting level
}
else
{
   return true;// Default nested return argument is always equal to
 1 (if not specified, current)
}
 }

 function bar($foo = true)
 {
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 2
echo 'Hi jon !';
 }

 function baz($foo = true)
 {
echo 'Hi bertie !';
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 3
echo 'Hi freddy !';
 }


 baz(true);  // Display:
  //  Hi bertie !
  //  Hi jon !
  //  Hi freddy !

 baz(false);  // Display:
  //  Hi bertie !


 Benefits:
 -Wont break compatibility
 -May improve code interpretation speed due to part of code skipped by the
 nested return.
 -Allow dynamic return expressions.

 Inconveniences:
 -May complicate debug/backtrace


I think this will lead to a debugging nightmare, sorry.

It allows functions to behave in an incredibly non-obvious way, makes it
really easy to break things, and when something is broken the complexity of
locating and fixing it feels like it will be insane.

I'm imagining functions with branches that have different return levels in
them, called from functions with branches with different return levels in
them I feel like crying and it's not even a real feature yet!


Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-22 Thread Patrick Schaaf
Am 21.03.2015 14:15 schrieb Georges.L cont...@geolim4.com:

 The main purpose, as the title say, is to have the possibility to nest
 multiple return like we can do currently with break/continue.

I think that is a complete nonstarter. Functions are reusable building
blocks, designed to be called from various places that the function author
should not be concerned with.

break/continue can always be analyzed at the single function level, with
semantics unambiguously given by the local nesting level within the
function.

On the other hand, functions being called from various places means the
nesting distance between a given point in the outer program, and the
function itself, is completely arbitrary for different calls.

In some places in our codebase we have logging functions that try to show
logically useful debug_backtraces, by leaving out a number of lowest
levels of the stack. Starting down that road soon required us to introduce
$up = 2 parameters to the inner logging functions, so that different call
pathes could impose how much to leave out (think some convenience
wrappers). This is a very brittle thing to do. Okay for debug backtrace
logging, because at worst it shows some unneccessary level or leaves out
some. But totally unmanageable when it affects really control flow.

I know exactly one language that provides similar stuff - TCL with its
uplevel and upvar constructs - and anybody who had to wrap their heads
around code using that, nifty as it can be, will know the cognitive strain
involved...

Patrick


Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-22 Thread Rowan Collins
On 21 March 2015 17:55:32 GMT, Georges.L cont...@geolim4.com wrote:
To be honest I had not thought about the bad side of this use, i guess
it
could be possible to not return upper than a try/catch block (then
return a
fatal error if our code is trying to returns upper than a try/catch
block).

Now the practical example:

// Code i have the hand on
function main()
{
 foo('bar');
 echo I'm an angel !;
}

function bar()
{
  echo I'm not Evil;
}

//Code i don't have the hand on (like a MVC core)
function foo($thing)
{
 //
 make_love_dont_war();
 call_user_func($thing);

 //Do some stuff i don't want to execute
 echo 'evil';
}

function make_love_dont_war()
{
 echo 'Make love, dont war.';
}

You get it ?

Not really, no. In this example, the code you want to skip happens to be all 
the code after executing the callback, but what if there was some essential 
cleanup there, or the evil line was before the callback, not after?

In general, a function should be a reusable, self-contained unit of code, and 
as such shouldn't want to know about where it was called from. But in order to 
know how many levels to force to return, you need to know how deeply nested you 
are, and the expected return type of the function you're jumping out of, as 
well as which code you're bypassing by doing so. If someone reuses the 
function, or refactors the calling code, some very confusing bugs will result.

Rather than jump N levels up the call stack, what you maybe want is jump up 
to somewhere labelled X. This is sort of what exceptions do - they jump up the 
stack until they find somewhere expecting to handle that condition. The 
function throwing the exception doesn't know where it will be caught, so is not 
fragile to reuse or refactoring. However, using exceptions for anything other 
than error handling is generally frowned upon, because they can lead to hard to 
follow logic which would be better off refactored in plain procedural/OO style.

In your example, it's up to the maintainers of the foo() function (e.g. 
framework) to make the evil optional, by passing in some additional setting, 
or allowing the callback to return a special value, or just splitting the work 
in such a way that you can access the desired functionality without calling 
foo() at all. If it's open source, you could submit a patch, or, worst case, 
maintain a fork.

Regards,
-- 
Rowan Collins
[IMSoP]


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



Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-21 Thread John Bafford

On Mar 21, 2015, at 10:17, Georges.L cont...@geolim4.com wrote:

 The main purpose of this RFC is *not* to improve the exception system of
 PHP but to improve the code logic/hierarchy.
 
 Hi php internals,
 
 After some long and deep research i finally decided to write my first RFC
 about a feature i'd be interested to be improved in the php core: *Nested
 enclosing returns*

Georges,

This would make simply looking at code and reasoning about what it does 
impossible.

At present, if I have the following code:

function foo() {
if(doSomething()) {
success();
} else {
failure();
}

return 42;
}

try {
bar(foo());
} catch($ex) {
}

Then I can make the following true statements about this code:
* foo always calls doSomething()
* foo always calls either success() or failure(), based on the result 
of doSomething()
* foo always returns 42
* bar is always called (with foo’s return value, 42)
* Alternatively to the above, any of the called functions may throw an 
exception, which will be caught by the catch block

If any of doSomething(), success(), failure(), or bar() can arbitrarily return 
to some higher calling scope, then the only thing I can say for sure is that 
doSomething() is called, after which my application could be in some 
dangerously inconsistent state because I have no idea what will be executed 
next.

This then provides significant security concerns. For example, if we have this:

function API_Function_With_Callback($callback) {
try {
$callback();

//do more stuff

return true;
} catch($ex) {
//do error stuff

return false;
}
}

function doEvil() {
$sentinel = //some unique value

$result = API_Function_With_Callback(function() use($sentinel) {
$backtrace = debug_backtrace();
$nestingLevel = //determine nesting level from backtrace
if($nestingLevel == 2) return $sentinel, 2;
else if($nestingLevel == 3) return $sentinel, 3;
else if($nestingLevel == 4) return $sentinel, 4;
// etc
}

// Exploit inconsistent state of Call_API_Function here
if($result === $sentinel) { … }
}

Then we can short-circuit code from some other library which isn’t prepared to 
deal with this kind of hijacking. More seriously, this sort of hijacking 
*can’t* be defended against (at least not without a weakening of your original 
proposal). Any function that takes a callback is potentially vulnerable to this 
sort of attack.


Can you suggest an actual, practical, example, where this would be such a 
benefit as to override the inherent difficulty about reasoning about this code, 
and the potential security concerns? Are there any other languages that make 
something like this possible?

I suspect that any code that could be “improved” with this functionality is 
already in significant need of improvement by more conventional means.

-John


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



Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-21 Thread Georges.L
To be honest I had not thought about the bad side of this use, i guess it
could be possible to not return upper than a try/catch block (then return a
fatal error if our code is trying to returns upper than a try/catch block).

Now the practical example:

// Code i have the hand on
function main()
{
 foo('bar');
 echo I'm an angel !;
}

function bar()
{
  echo I'm not Evil;
}

//Code i don't have the hand on (like a MVC core)
function foo($thing)
{
 //
 make_love_dont_war();
 call_user_func($thing);

 //Do some stuff i don't want to execute
 echo 'evil';
}

function make_love_dont_war()
{
 echo 'Make love, dont war.';
}

You get it ?



Georges.L

2015-03-21 17:07 GMT+01:00 John Bafford jbaff...@zort.net:


 On Mar 21, 2015, at 10:17, Georges.L cont...@geolim4.com wrote:

  The main purpose of this RFC is *not* to improve the exception system of
  PHP but to improve the code logic/hierarchy.
 
  Hi php internals,
 
  After some long and deep research i finally decided to write my first
 RFC
  about a feature i'd be interested to be improved in the php core:
 *Nested
  enclosing returns*

 Georges,

 This would make simply looking at code and reasoning about what it does
 impossible.

 At present, if I have the following code:

 function foo() {
 if(doSomething()) {
 success();
 } else {
 failure();
 }

 return 42;
 }

 try {
 bar(foo());
 } catch($ex) {
 }

 Then I can make the following true statements about this code:
 * foo always calls doSomething()
 * foo always calls either success() or failure(), based on the
 result of doSomething()
 * foo always returns 42
 * bar is always called (with foo’s return value, 42)
 * Alternatively to the above, any of the called functions may
 throw an exception, which will be caught by the catch block

 If any of doSomething(), success(), failure(), or bar() can arbitrarily
 return to some higher calling scope, then the only thing I can say for sure
 is that doSomething() is called, after which my application could be in
 some dangerously inconsistent state because I have no idea what will be
 executed next.

 This then provides significant security concerns. For example, if we have
 this:

 function API_Function_With_Callback($callback) {
 try {
 $callback();

 //do more stuff

 return true;
 } catch($ex) {
 //do error stuff

 return false;
 }
 }

 function doEvil() {
 $sentinel = //some unique value

 $result = API_Function_With_Callback(function() use($sentinel) {
 $backtrace = debug_backtrace();
 $nestingLevel = //determine nesting level from backtrace
 if($nestingLevel == 2) return $sentinel, 2;
 else if($nestingLevel == 3) return $sentinel, 3;
 else if($nestingLevel == 4) return $sentinel, 4;
 // etc
 }

 // Exploit inconsistent state of Call_API_Function here
 if($result === $sentinel) { … }
 }

 Then we can short-circuit code from some other library which isn’t
 prepared to deal with this kind of hijacking. More seriously, this sort of
 hijacking *can’t* be defended against (at least not without a weakening of
 your original proposal). Any function that takes a callback is potentially
 vulnerable to this sort of attack.


 Can you suggest an actual, practical, example, where this would be such a
 benefit as to override the inherent difficulty about reasoning about this
 code, and the potential security concerns? Are there any other languages
 that make something like this possible?

 I suspect that any code that could be “improved” with this functionality
 is already in significant need of improvement by more conventional means.

 -John




Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-21 Thread Georges.L
The main purpose of this RFC is *not* to improve the exception system of
PHP but to improve the code logic/hierarchy.

Using this like loop (for/foreach etc.) you can skip a lot of parent
callers for a desired purpose by example.

I agree with you in the sens were this can complicate significantly the
debug/trace process, but IMO, there's more benefits than inconvenience.

Also I agree with you too, were it can lead in a sort of spaghetti code
feature (like Goto operator is...), but which language is not a bit
spaghetti today?

But my request is not to have a fully dynamic nested return, but a
controlled dynamic nested return. I would not see this to be improved:

return $something, $nesting_level;

If I remember that feature has been removed in continue/break as of php
5.4, so this isn't that hard, right? :)


Georges.L

2015-03-21 14:20 GMT+01:00 Benjamin Eberlei kont...@beberlei.de:



 On Sat, Mar 21, 2015 at 1:13 PM, Georges.L cont...@geolim4.com wrote:

 Hi php internals,

 After some long and deep research i finally decided to write my first RFC
 about a feature i'd be interested to be improved in the php core: *Nested
 enclosing returns*



 The main purpose, as the title say, is to have the possibility to nest
 multiple return like we can do currently with break/continue.

 I thinks it'll being better with a scheme:




 function foo($foo = true)
 {
if(!$foo)
{
   return false, 3;// Please note the second return argument is the
 return nesting level
}
else
{
   return true;// Default nested return argument is always equal to
 1 (if not specified, current)
}
 }

 function bar($foo = true)
 {
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 2
echo 'Hi jon !';
 }

 function baz($foo = true)
 {
echo 'Hi bertie !';
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 3
echo 'Hi freddy !';
 }


 baz(true);  // Display:
  //  Hi bertie !
  //  Hi jon !
  //  Hi freddy !

 baz(false);  // Display:
  //  Hi bertie !


 Benefits:
 -Wont break compatibility
 -May improve code interpretation speed due to part of code skipped by the
 nested return.
 -Allow dynamic return expressions.

 Inconveniences:
 -May complicate debug/backtrace


 Hi Georges,

 In my opinion this is a bad idea.

 With break/continue/goto the jumps are restricted to only one function
 body to explicitly reduce the complexity in understanding them.

 With your proposal, as a user of a function I wouldn't know how deep a
 function returns. This can easily lead to extremely unexpected behavior.

 This is why exceptions are better for jumps up the call-stack, because
 they give the caller an explicit way of either accepting or catching the
 jump.



 Regards,
 Georges.L





Re: [PHP-DEV] RFC: Nested enclosing returns

2015-03-21 Thread Benjamin Eberlei
On Sat, Mar 21, 2015 at 1:13 PM, Georges.L cont...@geolim4.com wrote:

 Hi php internals,

 After some long and deep research i finally decided to write my first RFC
 about a feature i'd be interested to be improved in the php core: *Nested
 enclosing returns*


 The main purpose, as the title say, is to have the possibility to nest
 multiple return like we can do currently with break/continue.

 I thinks it'll being better with a scheme:




 function foo($foo = true)
 {
if(!$foo)
{
   return false, 3;// Please note the second return argument is the
 return nesting level
}
else
{
   return true;// Default nested return argument is always equal to
 1 (if not specified, current)
}
 }

 function bar($foo = true)
 {
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 2
echo 'Hi jon !';
 }

 function baz($foo = true)
 {
echo 'Hi bertie !';
foo($foo);
// Some stuff that will never be executed if $foo == false and
 nested return argument = 3
echo 'Hi freddy !';
 }


 baz(true);  // Display:
  //  Hi bertie !
  //  Hi jon !
  //  Hi freddy !

 baz(false);  // Display:
  //  Hi bertie !


 Benefits:
 -Wont break compatibility
 -May improve code interpretation speed due to part of code skipped by the
 nested return.
 -Allow dynamic return expressions.

 Inconveniences:
 -May complicate debug/backtrace


Hi Georges,

In my opinion this is a bad idea.

With break/continue/goto the jumps are restricted to only one function body
to explicitly reduce the complexity in understanding them.

With your proposal, as a user of a function I wouldn't know how deep a
function returns. This can easily lead to extremely unexpected behavior.

This is why exceptions are better for jumps up the call-stack, because they
give the caller an explicit way of either accepting or catching the jump.



 Regards,
 Georges.L