New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Recursion instead of goto #3

Closed
baghayi opened this Issue Sep 22, 2014 · 195 comments

Comments

Projects
None yet
@baghayi

baghayi commented Sep 22, 2014

May I ask if there is a reason why you prefer using goto instead of function recursion?

@igorw

This comment has been minimized.

Show comment
Hide comment
@igorw

igorw Sep 22, 2014

Owner

Why hello! Thank you for asking this most excellent question!

I have indeed considered alternatives to the goto. I have evaluated them to a great extent, and I am happy to present the results to you here.

When the PHP parser reads a source file, that source code is compiled down to a series of opcodes, that will then be executed by the Zend (tm) (r) Engine. The compiler does some basic optimizations, but is really quite stupid. And so, depending on what code you write, it will generate different opcodes. This has a direct performance impact.

There are several way in which a loop can be written. Let's start with the one you have proposed, the recursive call.

function retry($retries, callable $fn)
{
    try {
        return $fn();
    } catch (\Exception $e) {
        if (!$retries) {
            throw new FailingTooHardException('', 0, $e);
        }
        retry($retries - 1, $fn)
    }
}

When you give this code to the PHP compiler, it will generate these opcodes:

function name:  igorw\retry
number of ops:  24
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
  11     2      INIT_FCALL_BY_NAME                                       !1
         3      DO_FCALL_BY_NAME                              0  $0      
         4    > RETURN                                                   $0
  12     5*     JMP                                                      ->23
         6  >   CATCH                                        17          'Exception', !2
  13     7      BOOL_NOT                                         ~1      !0
         8    > JMPZ                                                     ~1, ->17
  14     9  >   FETCH_CLASS                                   4  :2      'igorw%5CFailingTooHardException'
        10      NEW                                              $3      :2
        11      SEND_VAL                                                 ''
        12      SEND_VAL                                                 0
        13      SEND_VAR                                                 !2
        14      DO_FCALL_BY_NAME                              3          
        15    > THROW                                         0          $3
  15    16*     JMP                                                      ->17
  16    17  >   INIT_NS_FCALL_BY_NAME                                    
        18      SUB                                              ~5      !0, 1
        19      SEND_VAL                                                 ~5
        20      SEND_VAR                                                 !1
        21      DO_FCALL_BY_NAME                              2  $6      
        22    > RETURN                                                   $6
  18    23*   > RETURN                                                   null

As you can see, it is generating 24 instructions. The most expensive portion of this is the function calls, since the arguments need to be sent individually, and there is an additional instruction (DO_FCALL_BY_NAME) for the actual function call.

There is no reason why this would be necessary. As described by Steele in his paper Lambda: The Ultimate GOTO, tail calls can be compiled to very efficient instructions. The PHP compiler however, does not take advantage of this technique, so calls are quite costly.

Let's try and improve this. By using a while loop.

function retry($retries, callable $fn)
{
    while (true) {
        try {
            return $fn();
        } catch (\Exception $e) {
            if (!$retries) {
                throw new FailingTooHardException('', 0, $e);
            }
            $retries--;
        }
    }
}

Here is what the compiler gives us:

function name:  igorw\retry
number of ops:  23
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
   9     2  >   FETCH_CONSTANT                                   ~0      'igorw%5Ctrue'
         3    > JMPZ                                                     ~0, ->22
  11     4  >   INIT_FCALL_BY_NAME                                       !1
         5      DO_FCALL_BY_NAME                              0  $1      
         6    > RETURN                                                   $1
  12     7*     JMP                                                      ->21
         8  >   CATCH                                        15          'Exception', !2
  13     9      BOOL_NOT                                         ~2      !0
        10    > JMPZ                                                     ~2, ->19
  14    11  >   FETCH_CLASS                                   4  :3      'igorw%5CFailingTooHardException'
        12      NEW                                              $4      :3
        13      SEND_VAL                                                 ''
        14      SEND_VAL                                                 0
        15      SEND_VAR                                                 !2
        16      DO_FCALL_BY_NAME                              3          
        17    > THROW                                         0          $4
  15    18*     JMP                                                      ->19
  16    19  >   POST_DEC                                         ~6      !0
        20      FREE                                                     ~6
  18    21    > JMP                                                      ->2
  19    22  > > RETURN                                                   null

This already looks a bit better. But there is a rather inefficient FETCH_CONSTANT instruction right at the top. This requires doing a namespace lookup against igorw\true. We can optimize that, by replacing while (true) with while (\true).

This gets rid of the FETCH_CONSTANT call, and puts the boolean true inline:

line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
   9     2  > > JMPZ                                                     true, ->21

But JUMPZ with argument true is a redundant expression. true is never zero. So ideally we would simply eliminate this check.

PS: for (;;) also has redundant jumps, so let's not use that.

So can we eliminate the redundant jump? Let's try a do-while loop!

function name:  igorw\retry
number of ops:  21
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
  11     2  >   INIT_FCALL_BY_NAME                                       !1
...
        15    > THROW                                         0          $3
  15    16*     JMP                                                      ->17
  16    17  >   POST_DEC                                         ~5      !0
        18      FREE                                                     ~5
  18    19    > JMPNZ                                                    true, ->2
  19    20  > > RETURN                                                   null

Awesome! The extra initial JMPZ has been removed! But, it comes at the cost of a JMPNZ at the end. So it will be more efficient for the success case, but for the retry, we will still do redundant checks for a jump that should be unconditional.

And there is a way to eliminate that final conditional, by using the excellent goto feature built into PHP. It produces the identical opcodes as do...while, but makes that final jump non-conditional!

And there you have it. This is the most efficient solution to do non-conditional loops in PHP. All other options are simply too slow.

Owner

igorw commented Sep 22, 2014

Why hello! Thank you for asking this most excellent question!

I have indeed considered alternatives to the goto. I have evaluated them to a great extent, and I am happy to present the results to you here.

When the PHP parser reads a source file, that source code is compiled down to a series of opcodes, that will then be executed by the Zend (tm) (r) Engine. The compiler does some basic optimizations, but is really quite stupid. And so, depending on what code you write, it will generate different opcodes. This has a direct performance impact.

There are several way in which a loop can be written. Let's start with the one you have proposed, the recursive call.

function retry($retries, callable $fn)
{
    try {
        return $fn();
    } catch (\Exception $e) {
        if (!$retries) {
            throw new FailingTooHardException('', 0, $e);
        }
        retry($retries - 1, $fn)
    }
}

When you give this code to the PHP compiler, it will generate these opcodes:

function name:  igorw\retry
number of ops:  24
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
  11     2      INIT_FCALL_BY_NAME                                       !1
         3      DO_FCALL_BY_NAME                              0  $0      
         4    > RETURN                                                   $0
  12     5*     JMP                                                      ->23
         6  >   CATCH                                        17          'Exception', !2
  13     7      BOOL_NOT                                         ~1      !0
         8    > JMPZ                                                     ~1, ->17
  14     9  >   FETCH_CLASS                                   4  :2      'igorw%5CFailingTooHardException'
        10      NEW                                              $3      :2
        11      SEND_VAL                                                 ''
        12      SEND_VAL                                                 0
        13      SEND_VAR                                                 !2
        14      DO_FCALL_BY_NAME                              3          
        15    > THROW                                         0          $3
  15    16*     JMP                                                      ->17
  16    17  >   INIT_NS_FCALL_BY_NAME                                    
        18      SUB                                              ~5      !0, 1
        19      SEND_VAL                                                 ~5
        20      SEND_VAR                                                 !1
        21      DO_FCALL_BY_NAME                              2  $6      
        22    > RETURN                                                   $6
  18    23*   > RETURN                                                   null

As you can see, it is generating 24 instructions. The most expensive portion of this is the function calls, since the arguments need to be sent individually, and there is an additional instruction (DO_FCALL_BY_NAME) for the actual function call.

There is no reason why this would be necessary. As described by Steele in his paper Lambda: The Ultimate GOTO, tail calls can be compiled to very efficient instructions. The PHP compiler however, does not take advantage of this technique, so calls are quite costly.

Let's try and improve this. By using a while loop.

function retry($retries, callable $fn)
{
    while (true) {
        try {
            return $fn();
        } catch (\Exception $e) {
            if (!$retries) {
                throw new FailingTooHardException('', 0, $e);
            }
            $retries--;
        }
    }
}

Here is what the compiler gives us:

function name:  igorw\retry
number of ops:  23
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
   9     2  >   FETCH_CONSTANT                                   ~0      'igorw%5Ctrue'
         3    > JMPZ                                                     ~0, ->22
  11     4  >   INIT_FCALL_BY_NAME                                       !1
         5      DO_FCALL_BY_NAME                              0  $1      
         6    > RETURN                                                   $1
  12     7*     JMP                                                      ->21
         8  >   CATCH                                        15          'Exception', !2
  13     9      BOOL_NOT                                         ~2      !0
        10    > JMPZ                                                     ~2, ->19
  14    11  >   FETCH_CLASS                                   4  :3      'igorw%5CFailingTooHardException'
        12      NEW                                              $4      :3
        13      SEND_VAL                                                 ''
        14      SEND_VAL                                                 0
        15      SEND_VAR                                                 !2
        16      DO_FCALL_BY_NAME                              3          
        17    > THROW                                         0          $4
  15    18*     JMP                                                      ->19
  16    19  >   POST_DEC                                         ~6      !0
        20      FREE                                                     ~6
  18    21    > JMP                                                      ->2
  19    22  > > RETURN                                                   null

This already looks a bit better. But there is a rather inefficient FETCH_CONSTANT instruction right at the top. This requires doing a namespace lookup against igorw\true. We can optimize that, by replacing while (true) with while (\true).

This gets rid of the FETCH_CONSTANT call, and puts the boolean true inline:

line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
   9     2  > > JMPZ                                                     true, ->21

But JUMPZ with argument true is a redundant expression. true is never zero. So ideally we would simply eliminate this check.

PS: for (;;) also has redundant jumps, so let's not use that.

So can we eliminate the redundant jump? Let's try a do-while loop!

function name:  igorw\retry
number of ops:  21
compiled vars:  !0 = $retries, !1 = $fn, !2 = $e
line     # *  op                           fetch          ext  return  operands
---------------------------------------------------------------------------------
   7     0  >   RECV                                             !0      
         1      RECV                                             !1      
  11     2  >   INIT_FCALL_BY_NAME                                       !1
...
        15    > THROW                                         0          $3
  15    16*     JMP                                                      ->17
  16    17  >   POST_DEC                                         ~5      !0
        18      FREE                                                     ~5
  18    19    > JMPNZ                                                    true, ->2
  19    20  > > RETURN                                                   null

Awesome! The extra initial JMPZ has been removed! But, it comes at the cost of a JMPNZ at the end. So it will be more efficient for the success case, but for the retry, we will still do redundant checks for a jump that should be unconditional.

And there is a way to eliminate that final conditional, by using the excellent goto feature built into PHP. It produces the identical opcodes as do...while, but makes that final jump non-conditional!

And there you have it. This is the most efficient solution to do non-conditional loops in PHP. All other options are simply too slow.

@igorw igorw closed this Sep 22, 2014

@ssx

This comment has been minimized.

Show comment
Hide comment
@ssx

ssx Sep 22, 2014

Igor will you marry me <3

ssx commented Sep 22, 2014

Igor will you marry me <3

@michellesanver

This comment has been minimized.

Show comment
Hide comment

SCOTT!!! :(

@ssx

This comment has been minimized.

Show comment
Hide comment
@ssx

ssx Sep 22, 2014

BUT LOOK AT THIS MAN

ssx commented Sep 22, 2014

BUT LOOK AT THIS MAN

@dazz

This comment has been minimized.

Show comment
Hide comment
@dazz

dazz Sep 22, 2014

@michellesanver Don't worry, I sit next to him and I was first!

dazz commented Sep 22, 2014

@michellesanver Don't worry, I sit next to him and I was first!

@mickaelandrieu

This comment has been minimized.

Show comment
Hide comment
@mickaelandrieu

mickaelandrieu Sep 23, 2014

Thanks for this explanation, your PHP knowledge is amazing o_O

Thanks for this explanation, your PHP knowledge is amazing o_O

@baghayi

This comment has been minimized.

Show comment
Hide comment
@baghayi

baghayi Sep 23, 2014

Hello @iGore
Thank you for this great explanation.
It was very helpful.

baghayi commented Sep 23, 2014

Hello @iGore
Thank you for this great explanation.
It was very helpful.

@b-viguier

This comment has been minimized.

Show comment
Hide comment
@b-viguier

b-viguier Sep 23, 2014

So, you have to rename your Twitter account igorgoto, it will be more efficient... :)

So, you have to rename your Twitter account igorgoto, it will be more efficient... :)

@asgrim

This comment has been minimized.

Show comment
Hide comment
@asgrim

asgrim Sep 23, 2014

This is the best justification for using "goto" in real life ever. Nicely done Igor.

asgrim commented Sep 23, 2014

This is the best justification for using "goto" in real life ever. Nicely done Igor.

@rainbow-alex

This comment has been minimized.

Show comment
Hide comment
@rainbow-alex

rainbow-alex Sep 23, 2014

Why not manually unroll the loop a few times. Most invocations will be for small n, so you might eliminate jumps alltogether.

Why not manually unroll the loop a few times. Most invocations will be for small n, so you might eliminate jumps alltogether.

@docteurklein

This comment has been minimized.

Show comment
Hide comment
@docteurklein

docteurklein Sep 23, 2014

+1 for marrying me too :)

+1 for marrying me too :)

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

@igorw You should write a book "Answering GitHub Issues The Right Way".

@igorw You should write a book "Answering GitHub Issues The Right Way".

@acleon

This comment has been minimized.

Show comment
Hide comment
@acleon

acleon Sep 23, 2014

Thanks for the explanation, but I'm unclear as to where the do...while approach falls down. Where would the overhead be on something like:

do {
    try {
        return $fn();
    }
    catch (\Exception $e) { }
}
while($retries--);

throw new FailingTooHardException('', 0, $e);

acleon commented Sep 23, 2014

Thanks for the explanation, but I'm unclear as to where the do...while approach falls down. Where would the overhead be on something like:

do {
    try {
        return $fn();
    }
    catch (\Exception $e) { }
}
while($retries--);

throw new FailingTooHardException('', 0, $e);
@davestevens

This comment has been minimized.

Show comment
Hide comment
@davestevens

davestevens Sep 23, 2014

@acleon I was a bit confused when I was reading this too, if you look at the actually code in the repo:
https://github.com/igorw/retry/blob/6c85162523e6a036f5b65c8cb2ec16c65b120d44/src/retry.php
You'll see that by using goto rather than a loop they are removing the use of conditional jump operands.

@acleon I was a bit confused when I was reading this too, if you look at the actually code in the repo:
https://github.com/igorw/retry/blob/6c85162523e6a036f5b65c8cb2ec16c65b120d44/src/retry.php
You'll see that by using goto rather than a loop they are removing the use of conditional jump operands.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

"All other options are simply too slow."

Have you actually benchmarked this? You do realize that the cost of network operations is several orders of magnitude larger than the cost of a few extra opcodes?

This is a textbook illustration of premature optimization that gains almost no optimization and sacrifices lots of maintainability in the process. If your purpose is purely academic, then go for it, I suppose. Otherwise...

"All other options are simply too slow."

Have you actually benchmarked this? You do realize that the cost of network operations is several orders of magnitude larger than the cost of a few extra opcodes?

This is a textbook illustration of premature optimization that gains almost no optimization and sacrifices lots of maintainability in the process. If your purpose is purely academic, then go for it, I suppose. Otherwise...

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

...otherwise you can still go for it since implementation is fairly simple and consists of only several lines of code, so it is not a big deal.

...otherwise you can still go for it since implementation is fairly simple and consists of only several lines of code, so it is not a big deal.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

So readability and maintainability are "not a big deal"?

So readability and maintainability are "not a big deal"?

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

@jcoleman I don't see any readability nor maintainability issues in this project. Do you?

@jcoleman I don't see any readability nor maintainability issues in this project. Do you?

@tminard

This comment has been minimized.

Show comment
Hide comment

tminard commented Sep 23, 2014

goto

@dave1010

This comment has been minimized.

Show comment
Hide comment
@dave1010

dave1010 Sep 23, 2014

@davestevens @igorw are conditional jump operands (while($retries)) any different to doing a conditaional (if (!$retries)), and then a jump (goto beginning)?

@davestevens @igorw are conditional jump operands (while($retries)) any different to doing a conditaional (if (!$retries)), and then a jump (goto beginning)?

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

For reference: https://files.ifi.uzh.ch/rerg/arvo/courses/kvse/uebungen/Dijkstra_Goto.pdf

This is a great demonstration of why so many computer science people look down on the PHP community. Your justification is basically "why not", when my point is that "it doesn't actually gain you anything.

For reference: https://files.ifi.uzh.ch/rerg/arvo/courses/kvse/uebungen/Dijkstra_Goto.pdf

This is a great demonstration of why so many computer science people look down on the PHP community. Your justification is basically "why not", when my point is that "it doesn't actually gain you anything.

@jbrooksuk

This comment has been minimized.

Show comment
Hide comment
@jbrooksuk

jbrooksuk Sep 23, 2014

@igorw since you're an internal PHP developer, can't you do something about this?

@igorw since you're an internal PHP developer, can't you do something about this?

@ankitml

This comment has been minimized.

Show comment
Hide comment
@ankitml

ankitml Sep 23, 2014

Any improvement which is not done to the worst performing step is not an improvement at all. The code is as fast as the slowest step. So irrespective of this detailed analysis, you need to first show that this loop is the slowest thing in the program. The whole point is you should have strong reasons to go against the standard practices of good programming.

ankitml commented Sep 23, 2014

Any improvement which is not done to the worst performing step is not an improvement at all. The code is as fast as the slowest step. So irrespective of this detailed analysis, you need to first show that this loop is the slowest thing in the program. The whole point is you should have strong reasons to go against the standard practices of good programming.

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

@jcoleman Peronaly, I never use gotos, because such tiny performance improvements does not change anything in apps I write.
But @igorw stated that performance is the most important thing he considered when choosing between different implementations.
You said:

You do realize that the cost of network operations is several orders of magnitude larger than the cost of a few extra opcode.

I don't see any network operations in this project, so your argument is not apply-able here.

@jcoleman Peronaly, I never use gotos, because such tiny performance improvements does not change anything in apps I write.
But @igorw stated that performance is the most important thing he considered when choosing between different implementations.
You said:

You do realize that the cost of network operations is several orders of magnitude larger than the cost of a few extra opcode.

I don't see any network operations in this project, so your argument is not apply-able here.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

"I don't see any network operations in this project, so your argument is not apply-able here."

The readme specifically states that the primary use-case for this project is for retrying network operations. Where else would you use this construct?

"I don't see any network operations in this project, so your argument is not apply-able here."

The readme specifically states that the primary use-case for this project is for retrying network operations. Where else would you use this construct?

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

@jcoleman Hehe, right. I agree, in case of retrying network operations, this tiny benefit is irrelevant.

@jcoleman Hehe, right. I agree, in case of retrying network operations, this tiny benefit is irrelevant.

@hausdorff

This comment has been minimized.

Show comment
Hide comment
@hausdorff

hausdorff Sep 23, 2014

@jcoleman @umpirsky Yeah, but your point remains: this code is not unmaintainable. You can complain that it doesn't fit a style standard, but that's about as far as @jcoleman is going to get here. Particularly since the GOTO is restricted just like it is in C (where it is used heavily and where it is even considered good style for things like error handling), which means most of the complaints that Dijkstra is making aren't even applicable here.

@jcoleman @umpirsky Yeah, but your point remains: this code is not unmaintainable. You can complain that it doesn't fit a style standard, but that's about as far as @jcoleman is going to get here. Particularly since the GOTO is restricted just like it is in C (where it is used heavily and where it is even considered good style for things like error handling), which means most of the complaints that Dijkstra is making aren't even applicable here.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

This is not C. Is there another language where GOTO is considered good style? Not in common languages.

This is not C. Is there another language where GOTO is considered good style? Not in common languages.

@josegonzalez

This comment has been minimized.

Show comment
Hide comment
@josegonzalez

josegonzalez Sep 23, 2014

Semi-related:

I thought you could not namespace the following constants

  • NULL
  • TRUE
  • FALSE
  • ZEND_THREAD_SAFE
  • ZEND_DEBUG_BUILD

Though this php eval says you can for any version of PHP that supports namespaces (though not on HHVM).

The best part is that if you don't use define to define the named constant, it does show the behavior PHP says isn't possible:

http://3v4l.org/1vAHs

Semi-related:

I thought you could not namespace the following constants

  • NULL
  • TRUE
  • FALSE
  • ZEND_THREAD_SAFE
  • ZEND_DEBUG_BUILD

Though this php eval says you can for any version of PHP that supports namespaces (though not on HHVM).

The best part is that if you don't use define to define the named constant, it does show the behavior PHP says isn't possible:

http://3v4l.org/1vAHs

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

@hausdorff So basically you admit that it's not good style (which is really the same thing as unmaintainability in many respects) and that it doesn't actually help speed up the operation that it's intended to speed up.

So again I say, the question isn't "why not" but rather "why?"

@hausdorff So basically you admit that it's not good style (which is really the same thing as unmaintainability in many respects) and that it doesn't actually help speed up the operation that it's intended to speed up.

So again I say, the question isn't "why not" but rather "why?"

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 23, 2014

maintainability?? you'd rather have me find the code that calls the function, then find the function, which may be in a different file or class, and then trace that, rather than having 5-6 lines of code with a goto command and goto anchor all easily visible?? well formed gotos are trivially maintainable.

doing ANYTHING you don't NEED to do is a hit on performance... oh, "the DB calls take the longest, so they are the only thing that should be optimized"... sounds like you've never written a system with load balanced front-ends with an external DB. making the front ends more efficient isn't about that front end doing individual things faster... yes, it's a TINY gain that won't make any individual process run noticeably faster, but everything the front-ends do are likely to b tiny processes anyways, so making them more efficient may significantly increase the number of requests per second you're able to continuously process. it's called SCALABILITY and it's just as, if not more important than maintainability.

maintainability?? you'd rather have me find the code that calls the function, then find the function, which may be in a different file or class, and then trace that, rather than having 5-6 lines of code with a goto command and goto anchor all easily visible?? well formed gotos are trivially maintainable.

doing ANYTHING you don't NEED to do is a hit on performance... oh, "the DB calls take the longest, so they are the only thing that should be optimized"... sounds like you've never written a system with load balanced front-ends with an external DB. making the front ends more efficient isn't about that front end doing individual things faster... yes, it's a TINY gain that won't make any individual process run noticeably faster, but everything the front-ends do are likely to b tiny processes anyways, so making them more efficient may significantly increase the number of requests per second you're able to continuously process. it's called SCALABILITY and it's just as, if not more important than maintainability.

@hausdorff

This comment has been minimized.

Show comment
Hide comment
@hausdorff

hausdorff Sep 23, 2014

@jcoleman I didn't say whether I thought it was or was not good style. I said you can assert it's bad style, but that's about the only merit your argument has. There is no universal standard that is "considered" good style (as you put it). The only thing you can hope for in the end is consistency.

That's my point. This code is not unmaintainable individually. You can argue that it doesn't fit with the style conventions of some existing code base, but the bottom line is there is nothing innately bad going on here.

@jcoleman I didn't say whether I thought it was or was not good style. I said you can assert it's bad style, but that's about the only merit your argument has. There is no universal standard that is "considered" good style (as you put it). The only thing you can hope for in the end is consistency.

That's my point. This code is not unmaintainable individually. You can argue that it doesn't fit with the style conventions of some existing code base, but the bottom line is there is nothing innately bad going on here.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 23, 2014

@cloudward If we can't have a rational discussion, then there's no point in having one at all.

@cloudward If we can't have a rational discussion, then there's no point in having one at all.

@hausdorff

This comment has been minimized.

Show comment
Hide comment
@hausdorff

hausdorff Sep 23, 2014

@jcoleman And, to answer your point that he's asking why not instead of why, sure, basically all code is a "why not". What's wrong with that? This is a one-off function. It's not a part of a large code base. I say ask why not all you want.

@jcoleman And, to answer your point that he's asking why not instead of why, sure, basically all code is a "why not". What's wrong with that? This is a one-off function. It's not a part of a large code base. I say ask why not all you want.

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 23, 2014

@jcoleman you're absolutely right. using gotos can be extremely rational as demonstrated here.

@jcoleman you're absolutely right. using gotos can be extremely rational as demonstrated here.

@hackerhasid

This comment has been minimized.

Show comment
Hide comment
@hackerhasid

hackerhasid Sep 23, 2014

there has been more time spent here debating than has been spent by computers running this. so if you're looking for the slowest function to be optimized it's this - "stop arguing!"

(i've never use the library but i found the explanation by @igorw interesting at least)

there has been more time spent here debating than has been spent by computers running this. so if you're looking for the slowest function to be optimized it's this - "stop arguing!"

(i've never use the library but i found the explanation by @igorw interesting at least)

@qbolec

This comment has been minimized.

Show comment
Hide comment
@qbolec

qbolec Sep 23, 2014

What does it say about this thread, that CTRL+F for "test" and "profiler" does not find any single post?

qbolec commented Sep 23, 2014

What does it say about this thread, that CTRL+F for "test" and "profiler" does not find any single post?

@umpirsky

This comment has been minimized.

Show comment
Hide comment
@umpirsky

umpirsky Sep 23, 2014

@hackerhasid It's just little healthy afternoon GitHub flame.

@hackerhasid It's just little healthy afternoon GitHub flame.

@docteurklein

This comment has been minimized.

Show comment
Hide comment
@docteurklein

docteurklein Sep 23, 2014

@jcoleman you made my day trying to make a point on this :D Can't you just admire the amazing explanation of @igorw, profit from his wonderful experiments and take him as an example of how to distribute small, reusable micro-libs ? Please.

@jcoleman you made my day trying to make a point on this :D Can't you just admire the amazing explanation of @igorw, profit from his wonderful experiments and take him as an example of how to distribute small, reusable micro-libs ? Please.

@qbolec

This comment has been minimized.

Show comment
Hide comment
@qbolec

qbolec Sep 23, 2014

@cloudward I have a feeling that you haven't look carefully at the VLD output presented in the three links I've shared with you. Which saddens me, as it took some effort to prepare them :(

qbolec commented Sep 23, 2014

@cloudward I have a feeling that you haven't look carefully at the VLD output presented in the three links I've shared with you. Which saddens me, as it took some effort to prepare them :(

@whatever

This comment has been minimized.

Show comment
Hide comment
@whatever

whatever Sep 23, 2014

This is getting so :neckbeard:

This is getting so :neckbeard:

@gigablah

This comment has been minimized.

Show comment
Hide comment
@gigablah

gigablah Sep 24, 2014

Considering the use cases of this library -- presumably network/database calls and file IO -- the time spent on calling $fn is probably several orders of magnitude more than the loop itself. In that case it doesn't really matter that much whether @igorw uses goto or recursive call or Dynamic Loop Unrolling Via Code Generation (I made that up).

Still the first reply is the awesomest thing I've read this week. As for the rest, I can't believe "cargo cult" hasn't been mentioned yet.

Considering the use cases of this library -- presumably network/database calls and file IO -- the time spent on calling $fn is probably several orders of magnitude more than the loop itself. In that case it doesn't really matter that much whether @igorw uses goto or recursive call or Dynamic Loop Unrolling Via Code Generation (I made that up).

Still the first reply is the awesomest thing I've read this week. As for the rest, I can't believe "cargo cult" hasn't been mentioned yet.

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

Considering the theoretical nature of the first reply, it doesn't really matter what really matters.

in this case, "reverse cargo cult" would fit better. it's not about using something you don't understand.... it's about understanding something you use, and knowing that it provides you many safeguards and guarantees that you think are more valuable than the cost of considering a negligibly better alternative at every chance you come upon to consider one.

that doesn't change the whole point of igor's post... there are times when using goto is the negligibly better alternative.

Considering the theoretical nature of the first reply, it doesn't really matter what really matters.

in this case, "reverse cargo cult" would fit better. it's not about using something you don't understand.... it's about understanding something you use, and knowing that it provides you many safeguards and guarantees that you think are more valuable than the cost of considering a negligibly better alternative at every chance you come upon to consider one.

that doesn't change the whole point of igor's post... there are times when using goto is the negligibly better alternative.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 24, 2014

@qbolec I fear that @cloudward is either 1.) unable to comprehend, 2.) seriously confused, or 3.) a troll.

@cloudward The VLD output that @qbolec posted demonstrated that you're wrong. Objectively. Not subjectively. In Igor's version, he eliminates a pointless jmpnz but there's still a bool_not followed by a jmpz. In contrast, the do/while version that @acleon posted (which is not the same as what Igor tested) has a post_dec followed by a jmpz. So either way you have to do some kind of comparison.

Let me say that again: you cannot avoid having any comparison. It's fundamentally impossible to remove all comparison and still have the same behavior. You can swap the comparison between the while condition and the if guarding the throw, but you can't remove it entirely.

Edit: And by your own metrics (CPU instruction count and memory size), the do/while version that @acleon presented wins over the goto version.

@qbolec I fear that @cloudward is either 1.) unable to comprehend, 2.) seriously confused, or 3.) a troll.

@cloudward The VLD output that @qbolec posted demonstrated that you're wrong. Objectively. Not subjectively. In Igor's version, he eliminates a pointless jmpnz but there's still a bool_not followed by a jmpz. In contrast, the do/while version that @acleon posted (which is not the same as what Igor tested) has a post_dec followed by a jmpz. So either way you have to do some kind of comparison.

Let me say that again: you cannot avoid having any comparison. It's fundamentally impossible to remove all comparison and still have the same behavior. You can swap the comparison between the while condition and the if guarding the throw, but you can't remove it entirely.

Edit: And by your own metrics (CPU instruction count and memory size), the do/while version that @acleon presented wins over the goto version.

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

@jcoleman the code i posted, and @steverhoades ran and confirmed demonstrated that use of goto is SOMETIMES negligibly better ALWAYS... it isn't about right and wrong. that is the truth. that is what igor said, and all i've done is defend that.

i have no fear at all @jcoleman will claim he's done and come back again... much as a troll would.

@jcoleman the code i posted, and @steverhoades ran and confirmed demonstrated that use of goto is SOMETIMES negligibly better ALWAYS... it isn't about right and wrong. that is the truth. that is what igor said, and all i've done is defend that.

i have no fear at all @jcoleman will claim he's done and come back again... much as a troll would.

@gigablah

This comment has been minimized.

Show comment
Hide comment
@gigablah

gigablah Sep 24, 2014

@cloudward I was referring to the "goto considered harmful" cargo cult, but yeah.

@cloudward I was referring to the "goto considered harmful" cargo cult, but yeah.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 24, 2014

@cloudward Your code that @steverhoades didn't include the do/while sample.

@cloudward Your code that @steverhoades didn't include the do/while sample.

@jameswatts

This comment has been minimized.

Show comment
Hide comment
@jameswatts

jameswatts Sep 24, 2014

Isn't it awesome that in the year 2014 there's such a detailed discussion happening around the GOTO operator? Someone ping me when the classic conversation about eval() starts, that one's always a good laugh. #nostalgia

Isn't it awesome that in the year 2014 there's such a detailed discussion happening around the GOTO operator? Someone ping me when the classic conversation about eval() starts, that one's always a good laugh. #nostalgia

@pminnieur

This comment has been minimized.

Show comment
Hide comment
@pminnieur

pminnieur Sep 24, 2014

Btw, could you PLEASE use tabs instead of spaces for indentation? TYVM!

Btw, could you PLEASE use tabs instead of spaces for indentation? TYVM!

@drgomesp

This comment has been minimized.

Show comment
Hide comment
@drgomesp

drgomesp Sep 24, 2014

Come on guys, I need to focus on work here...

Come on guys, I need to focus on work here...

@daylerees

This comment has been minimized.

Show comment
Hide comment
@daylerees

daylerees Sep 24, 2014

I won't lie. The comment gave me an erection.

I won't lie. The comment gave me an erection.

@mitchellvanw

This comment has been minimized.

Show comment
Hide comment
@mitchellvanw

mitchellvanw Sep 24, 2014

The amount of awesome from @igorw's comment could not be measured.

The amount of awesome from @igorw's comment could not be measured.

@stanimirovv

This comment has been minimized.

Show comment
Hide comment
@stanimirovv

stanimirovv Sep 24, 2014

Golly gosh, that's one amazing answer !

Golly gosh, that's one amazing answer !

@Nyalab

This comment has been minimized.

Show comment
Hide comment
@Nyalab

Nyalab Sep 24, 2014

debate:

goto debate;

Nyalab commented Sep 24, 2014

debate:

goto debate;

@bloodyowl

This comment has been minimized.

Show comment
Hide comment
@bloodyowl

bloodyowl Sep 24, 2014

why would anybody care? it's php

why would anybody care? it's php

@eddiejaoude

This comment has been minimized.

Show comment
Hide comment
@eddiejaoude

eddiejaoude Sep 24, 2014

Very good reply! 👍

Very good reply! 👍

@josegonzalez

This comment has been minimized.

Show comment
Hide comment
@josegonzalez

josegonzalez Sep 24, 2014

@bloodyowl says the guy whose entire life depends on not blocking a single thread...

@bloodyowl says the guy whose entire life depends on not blocking a single thread...

@vita10gy

This comment has been minimized.

Show comment
Hide comment
@vita10gy

vita10gy Sep 24, 2014

I don't understand the "this is a micro library so one little goto doesn't count the same as it otherwise might" argument. "It's 19 lines, get over it @jcoleman"

Any well designed codebase will have plenty of things encapsulated into little one job routines like this. You should be working with 20 lines of code, give or take, at a time, all the time. The same "well surely a goto is fine in this little ol' function...for speed" argument would apply constantly, and that's how in the big picture you wind up with an unmaintainable turd sandwich.

WE are the expense. WE should strive to do everything we can to ensure everything we do can be maintained as easily and painlessly as possible. If that isn't the fastest possible code, then spend a comparative pittance on upgrading the sever.

Recursion should probably be avoided where a loop is just as painless and readable, but being worried about the "cost" of a loop is, IMO, silly. There are almost certainly always better places for you to invest your time than avoiding the cost of a bleeping while loop in anything you'd be using PHP* to accomplish.

*Edit: This was not a "bash PHP" point. But you're not writing a first person shooter or other such thing where wringing every clock cycle possible out of a predefined system is important, in PHP. If all the "extra" memory of all the while loops you use is effecting your server, then spend $50 on some RAM. Don't spend your time on stuff like this.

I don't understand the "this is a micro library so one little goto doesn't count the same as it otherwise might" argument. "It's 19 lines, get over it @jcoleman"

Any well designed codebase will have plenty of things encapsulated into little one job routines like this. You should be working with 20 lines of code, give or take, at a time, all the time. The same "well surely a goto is fine in this little ol' function...for speed" argument would apply constantly, and that's how in the big picture you wind up with an unmaintainable turd sandwich.

WE are the expense. WE should strive to do everything we can to ensure everything we do can be maintained as easily and painlessly as possible. If that isn't the fastest possible code, then spend a comparative pittance on upgrading the sever.

Recursion should probably be avoided where a loop is just as painless and readable, but being worried about the "cost" of a loop is, IMO, silly. There are almost certainly always better places for you to invest your time than avoiding the cost of a bleeping while loop in anything you'd be using PHP* to accomplish.

*Edit: This was not a "bash PHP" point. But you're not writing a first person shooter or other such thing where wringing every clock cycle possible out of a predefined system is important, in PHP. If all the "extra" memory of all the while loops you use is effecting your server, then spend $50 on some RAM. Don't spend your time on stuff like this.

@josegonzalez

This comment has been minimized.

Show comment
Hide comment
@josegonzalez

josegonzalez Sep 24, 2014

Has anyone here made a pull request to change this to a faster method?

Has anyone here made a pull request to change this to a faster method?

@darkrain

This comment has been minimized.

Show comment
Hide comment
@darkrain

darkrain Sep 24, 2014

now i know how i can get womens

now i know how i can get womens

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

@vita10gy yes... this isn't about high level coding style guides... it's just a low level view into how PHP CAN be optimized. in all my years writing PHP, i think i have maybe 2 goto commands in the million+ lines of code i've written, and they were in a compiler for a dynamic language that lives side by side with PHP. using the goto was by far the best solution speed wise and maintainability wise. i'm passionate about this because the "never use goto" camp is strong, and i don't want to see it deprecated. there are very few use cases where it makes a lot of sense, but they do exist.

BTW, thanks for submitting all those portals in phoenix park ;) we live close.

@vita10gy yes... this isn't about high level coding style guides... it's just a low level view into how PHP CAN be optimized. in all my years writing PHP, i think i have maybe 2 goto commands in the million+ lines of code i've written, and they were in a compiler for a dynamic language that lives side by side with PHP. using the goto was by far the best solution speed wise and maintainability wise. i'm passionate about this because the "never use goto" camp is strong, and i don't want to see it deprecated. there are very few use cases where it makes a lot of sense, but they do exist.

BTW, thanks for submitting all those portals in phoenix park ;) we live close.

@vita10gy

This comment has been minimized.

Show comment
Hide comment
@vita10gy

vita10gy Sep 24, 2014

@cloudward You ENL or RES?

Edit: also, as far as this goes, I'm not sure you can in one breath say that you've used goto 2 times in all your years, and in the next worry that the 'no goto ever' brigade is trying to rid the world of a useful tool. Almost by definition something can't be almost never useful and super useful.

I think you could make a good argument that even if it has a very rare proper usage, (which while I can't think of any, I'm sure it does), and lots of ways to completely misuse it, that it would be for the greater good to just not have it.

I mean, I can think of a couple use cases why rigging the windows in my house with explosives would be a good idea. All that really matters is if those use cases are worth all the times I blow guests or my wife up.

@cloudward You ENL or RES?

Edit: also, as far as this goes, I'm not sure you can in one breath say that you've used goto 2 times in all your years, and in the next worry that the 'no goto ever' brigade is trying to rid the world of a useful tool. Almost by definition something can't be almost never useful and super useful.

I think you could make a good argument that even if it has a very rare proper usage, (which while I can't think of any, I'm sure it does), and lots of ways to completely misuse it, that it would be for the greater good to just not have it.

I mean, I can think of a couple use cases why rigging the windows in my house with explosives would be a good idea. All that really matters is if those use cases are worth all the times I blow guests or my wife up.

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Sep 24, 2014

@cloudward I have to say that I'd totally agree with most of that. I'm not advocating eliminating GOTO, and I'm not advocating never using it (remember, I've used GOTO in production too).

If the purpose of this code usage was purely and exercise in how to do low-level optimization in PHP, then I think that's cool too.

I just don't think that it's necessary (or that the speed it potentially gains is relevant) here in this use case.

@cloudward I have to say that I'd totally agree with most of that. I'm not advocating eliminating GOTO, and I'm not advocating never using it (remember, I've used GOTO in production too).

If the purpose of this code usage was purely and exercise in how to do low-level optimization in PHP, then I think that's cool too.

I just don't think that it's necessary (or that the speed it potentially gains is relevant) here in this use case.

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

@vita10gy goto is like nuclear weapons... if you're using one, you better have a good reason, and most of the people who have them in good faith plan on not using them, but they're still building more and more of them.

i'm ENL

@vita10gy goto is like nuclear weapons... if you're using one, you better have a good reason, and most of the people who have them in good faith plan on not using them, but they're still building more and more of them.

i'm ENL

@vita10gy

This comment has been minimized.

Show comment
Hide comment
@vita10gy

vita10gy Sep 24, 2014

Figures, ENL would be GOTO lovers. ;)

Figures, ENL would be GOTO lovers. ;)

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

@jcoleman i added in the do while to the test, and used as many gotos as i could. the case in point is "n = 0"... where in wall time goto and do while are often exactly equal, and sometimes either one of them are faster. that directly relates to your post about adding a useless MOV to significantly speed up a system... there might be timings that are ripe for better overall performance, if everyone is doing things as conservatively as possible, that might block everyone from doing anything productively. something about good will hunting wanting a blonde. but technically, in the n = 0 case (which is expected to happen most frequently), the goto does a single less thing at the lowest possible level.

<?php

$n = 1000;
$a = 1;

start:

$start = microtime(true);

try {
    $a = 1;
    while(\true) {
        if($a > $n) {
            throw new Exception('done');
        }
        $a++;
    }
} catch(Exception $e) {
}

$after_while = microtime(true);

try {
    $a = 1;
    start_goto:
    if($a > $n) {
        throw new Exception('done');
    }
    $a++;
    goto start_goto;
} catch(Exception $e) {
}

$after_goto = microtime(true);

try {
    $a = 1;
    do {
        if($a > $n) {
            throw new Exception('done');
        }
        $a++;
    } while(\true);
} catch(Exception $e) {
}

$end = microtime(true);

echo "n = $n\n\twhile    " . ($after_while-$start) . "\n\tgoto     " . ($after_goto-$after_while) . "\n\tdo while " . ($end-$after_goto) . "\n\n";

$n = $n / 10;
if($n >= 1) {
    goto start;
} elseif($n > 0) {
    $n = 0;
    goto start;
}

?>

@jcoleman i added in the do while to the test, and used as many gotos as i could. the case in point is "n = 0"... where in wall time goto and do while are often exactly equal, and sometimes either one of them are faster. that directly relates to your post about adding a useless MOV to significantly speed up a system... there might be timings that are ripe for better overall performance, if everyone is doing things as conservatively as possible, that might block everyone from doing anything productively. something about good will hunting wanting a blonde. but technically, in the n = 0 case (which is expected to happen most frequently), the goto does a single less thing at the lowest possible level.

<?php

$n = 1000;
$a = 1;

start:

$start = microtime(true);

try {
    $a = 1;
    while(\true) {
        if($a > $n) {
            throw new Exception('done');
        }
        $a++;
    }
} catch(Exception $e) {
}

$after_while = microtime(true);

try {
    $a = 1;
    start_goto:
    if($a > $n) {
        throw new Exception('done');
    }
    $a++;
    goto start_goto;
} catch(Exception $e) {
}

$after_goto = microtime(true);

try {
    $a = 1;
    do {
        if($a > $n) {
            throw new Exception('done');
        }
        $a++;
    } while(\true);
} catch(Exception $e) {
}

$end = microtime(true);

echo "n = $n\n\twhile    " . ($after_while-$start) . "\n\tgoto     " . ($after_goto-$after_while) . "\n\tdo while " . ($end-$after_goto) . "\n\n";

$n = $n / 10;
if($n >= 1) {
    goto start;
} elseif($n > 0) {
    $n = 0;
    goto start;
}

?>
@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 24, 2014

n = 1000
while 0.00028491020202637
goto 0.0002291202545166
do while 0.00021195411682129

n = 100
while 5.793571472168E-5
goto 4.6014785766602E-5
do while 5.0067901611328E-5

n = 10
while 3.6954879760742E-5
goto 2.8133392333984E-5
do while 2.6941299438477E-5

n = 1
while 2.598762512207E-5
goto 2.598762512207E-5
do while 2.598762512207E-5

n = 0
while 2.6941299438477E-5
goto 2.5033950805664E-5
do while 2.598762512207E-5

n = 1000
while 0.00028491020202637
goto 0.0002291202545166
do while 0.00021195411682129

n = 100
while 5.793571472168E-5
goto 4.6014785766602E-5
do while 5.0067901611328E-5

n = 10
while 3.6954879760742E-5
goto 2.8133392333984E-5
do while 2.6941299438477E-5

n = 1
while 2.598762512207E-5
goto 2.598762512207E-5
do while 2.598762512207E-5

n = 0
while 2.6941299438477E-5
goto 2.5033950805664E-5
do while 2.598762512207E-5

@tamasimrei

This comment has been minimized.

Show comment
Hide comment
@tamasimrei

tamasimrei Sep 25, 2014

on a personal note: it's amazing that people actually have time for this.
and like someone said, yeah, let's talk about indentation! :)

on a personal note: it's amazing that people actually have time for this.
and like someone said, yeah, let's talk about indentation! :)

@cloudward

This comment has been minimized.

Show comment
Hide comment
@cloudward

cloudward Sep 25, 2014

@tamasimrei the code i pasted was indented with tabs, but github seems to ignore them. i tried wrapping in <pre> and <code>, but it just made it worse. i guess markdown wants me to add 4 spaces to the start of every line. you're right, i don't have time for that.

@tamasimrei the code i pasted was indented with tabs, but github seems to ignore them. i tried wrapping in <pre> and <code>, but it just made it worse. i guess markdown wants me to add 4 spaces to the start of every line. you're right, i don't have time for that.

@evert

This comment has been minimized.

Show comment
Hide comment
@evert

evert Sep 25, 2014

@cloudward you start and end your code with triple-backtick to turn it into a codeblock as such:

```php
// code goes here
```

If you're going to show the world the importance of your argument, you might as well do it with syntax highlighting enabled!

evert commented Sep 25, 2014

@cloudward you start and end your code with triple-backtick to turn it into a codeblock as such:

```php
// code goes here
```

If you're going to show the world the importance of your argument, you might as well do it with syntax highlighting enabled!

@hassankhan

This comment has been minimized.

Show comment
Hide comment
@hassankhan

hassankhan Sep 28, 2014

@jgoux Holy shit that was my thread!

@jgoux Holy shit that was my thread!

@igorw

This comment has been minimized.

Show comment
Hide comment
@igorw

igorw Oct 28, 2014

Owner

In case you need some more reasons why the GOTO statement is a feasible option for performance critical code such as the code in this library, I can highly recommend this paper by Knuth:

Owner

igorw commented Oct 28, 2014

In case you need some more reasons why the GOTO statement is a feasible option for performance critical code such as the code in this library, I can highly recommend this paper by Knuth:

@vita10gy

This comment has been minimized.

Show comment
Hide comment
@vita10gy

vita10gy Oct 29, 2014

This is a joke right?

This is a joke right?

@jcoleman

This comment has been minimized.

Show comment
Hide comment
@jcoleman

jcoleman Oct 29, 2014

"Performance critical code" such as saving an instruction or two when
retrying web requests. If this isn't trolling, I don't know what is.

On Tue, Oct 28, 2014 at 8:40 PM, vita10gy notifications@github.com wrote:

This is a joke right?


Reply to this email directly or view it on GitHub
#3 (comment).

"Performance critical code" such as saving an instruction or two when
retrying web requests. If this isn't trolling, I don't know what is.

On Tue, Oct 28, 2014 at 8:40 PM, vita10gy notifications@github.com wrote:

This is a joke right?


Reply to this email directly or view it on GitHub
#3 (comment).

@DGuidi

This comment has been minimized.

Show comment
Hide comment
@DGuidi

DGuidi Feb 17, 2015

here from this post
thank you all, you made my day.

DGuidi commented Feb 17, 2015

here from this post
thank you all, you made my day.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment