0

I have been working with laravel (PHP) recently, and there is an option when using their fluent ORM to define where clauses using closures. This gives us two, functionally equivalent, ways to specify a where clause that should only be added in certain cases:

Example 1

    $query = App::make('Vendor_Orders')->
        where(function($query) use ($admin) {
            if (!$admin) {
                $query->where('vendor_id', '=', $this->id);
            }
        })->
        get();

Example 2

    $query = App::make('Vendor_Orders');
    if (!$admin) {
        $query->where('vendor_id', '=', $this->id);
    }
    $query = $query->get();

As you can see, one of these is using a closure (and maintaining the "fluent-ness"), while the other avoids it. My instinct is to prefer the second, because using an anonymous function like that is adding an extra stack frame, which I would expect to make the program less efficient (possibly a holdover from my time working with C). On the other hand, my colleague (whose first language was PHP) prefers the first example, because it avoids the use of a second assignment operator, and he doesn't see anything wrong with piling up extra function calls.

This started me wondering - how much effect does that extra stack frame really have, in a modern system? Does it make any practical difference if one uses a function call instead of an if statement?

I'm not looking for subjective which-do-you-prefer answers, I'm asking for some sort of facts regarding the impact of unnecessary jumps - particularly to anonymous functions - in modern, interpreted languages (e.g. PHP, Java, etc.). Possibly also some notes on how this differs from old-school compiled languages.

  • 2
    I don't do PHP, but generally closures don't add stack frames, they add an object on the heap containing the values of the free variables. In any case I'd say you're both missing the point. You're writing code for other people first and foremost, and when you do find a performance problem the fix probably won't involve something as trivial as this. (It's also strange to lump both PHP and Java under the same bucket of "interpreted languages".) – Doval Aug 4 '14 at 15:09
  • 2
    @Doval Creating a closure does that. Calling it adds a stack frame like any other function call. Otherwise agreed. – user7043 Aug 4 '14 at 16:08
  • Every stack frame I create is necessary for the proper functioning of my line-of-business application. – Jesse C. Slicer Aug 4 '14 at 16:36
  • Avoiding stack frames is especially wrong in C (and even more so in C++). They are optimizing compilers and can inline many of the calls. – Jan Hudec Aug 4 '14 at 18:45
  • @JanHudec Can you explain this more? I would imagine that the main risk of calling a function is having to page memory - if the whole program isn't included in memory at once, and function A is stored far from caller B, then calling the function would slow execution while it reads in the in relevant section. I'd think this would be more of a problem for a compiled language like C than a scripting one. Although it doesn't apply to closures, which are presumably always in memory anyway. – Benubird Aug 5 '14 at 8:02
4

Interesting question, but I really think you are approaching this at the wrong level of abstraction. You are writing a web application, probably it will be maintained by yourself and colleagues who will need to make changes to your code. Your first cost to consider is your own productivity. Is one version of the code clearer than the other? Does one version fit better with your coding conventions and style? Is one version easier to test and refactor?

Once you have considered all of that, then thing about whether performance is really an issue. This is difficult for web applications, because the overall performance of an app can be influenced by many things which are outside of your control. However, if you can stress test this code then that would be a good idea. But don't just performance test this snippet, work through a whole use case. Then use a profiler to see whether using more or fewer closures really has an overall effect on your code.

In general though, I would suggest that this sort of micro-managing of performance will lead you down an unproductive rabbit hole. Not only is it difficult (and time consuming) to figure out whether your coding style is having a real effect on the end-user, it may be that performance can be improved by changing or updating or reconfiguring your PHP runtime.

There are SO MANY variables in performance benchmarking, better to deal with readability and maintenance issues first.

2

The additional invocation is essentially trivial. Avoiding doing something better to avoid a function call is a premature micro-optimization. Write first for readability and maintainability. Once the program is written, you can benchmark performance, and make adjustments from there (and I would strongly suspect your performance bottleneck is not the stack).

Part of the reason this is so trivial is that code calls functions a lot, therefore compilers and interpreters have highly optimized the internals of calling a function. It is better to make the code more readable and not worry so much about the stack.

(I'd still say the second is better, but because it is more readable to me.)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.