Is there a way to pass BIFs as function arguments OR dynamically call BIFs?

51 views
Skip to first unread message

Kevin Cox

unread,
Dec 26, 2012, 11:09:35 PM12/26/12
to ra...@googlegroups.com
I have a function called "apply" that takes an array and applies a function to each element.

I want to be able to pass in a built-in function...

apply(array, trim)

or even...
apply(array, 'trim')
as opposed to...

apply(array, function(el) {
return trim(el)
})

...for the sake of brevity.

I know I can use evaluate() in my apply function...

evaluate(fn & '("' & el & '")')
...but clearly that's not ideal in terms of performance.

I googled quite a few terms for both railo and coldfusion, but didn't find anything.

Any ideas?

Thanks!

Igal @ getRailo.org

unread,
Dec 26, 2012, 11:59:56 PM12/26/12
to ra...@googlegroups.com
the closest thing I can think of is to declare the function outside the closure, i.e.

function udfTrim( input ) {

    return trim( input );
}

then you can call

    apply( array, udfTrim );

also, you can define the UDFs in a way that will set them to the Application scope, as I suggested in
https://groups.google.com/d/msg/railo/I77_UTFvetg/LZ5npo0ktgkJ

then if your trim() udf is referenced as Application.functions.udfTrim you can pass it like so:

    apply( array, Application.functions.udfTrim );


Igal

Adam Cameron

unread,
Dec 28, 2012, 7:56:47 AM12/28/12
to ra...@googlegroups.com
This is something I've been mulling over as to whether it's a good idea or not. Should BIFs have their status elevated to being first-class functions? Would this even be possible (I have no idea about the architectural considerations of this). It's certainly something I've wanted to do in the past.

Ooh... I think perhaps I have today's blog article topic... :-)

--
Adam

Adam Cameron

unread,
Dec 28, 2012, 8:55:47 AM12/28/12
to ra...@googlegroups.com

Bruce Kirkpatrick

unread,
Dec 28, 2012, 10:15:09 PM12/28/12
to ra...@googlegroups.com
What does your application do that requires this to be fast every time?   I haven't had a need to execute something like this in a tight loop and because I know it is slower to write it this way, I wouldn't write it this way.  If I did need this to be optimized, I would probably end up pre-generating as much of the data and caching it or rewriting it in the simple, obvious way (loop over the array).  Allow me to explain why.

I often have a desire to make CFML language more elegant and similar to other languages, but some of these additions may result in the language being slower.

I recently started looking at how Railo relates to the Java code it was written with and reading how Java works.  It seems to me that the answer to a lot of performance questions like this should be to for you to consider adding a Java class or built-in function to Railo instead of attempting to use CFML.  The performance of these operations in Railo is based on the speed of a Java hash map and some additional logic on top of them.  If you were working with Java directly, your array wouldn't need to use hash maps to locate the data, and this may result in your code going hundreds of times faster then the CFML version.   The dynamic language overhead (mainly use of hashmaps to resolve every variable/function) is why built-in functions in Railo are usually faster then making your own CFC or function with CFML.   Built-in functions are usually mostly Java code (not always).   I did a speed comparison on this exact kind of thing a week ago and I was pleasantly surprised with how easy it was to download Railo source, add some custom code, build it and deploy it to my test server.  I have almost no Java experience.  I think the best thing about Railo besides being faster, is that we actually can tinker with it's inner workings and add in our own built-in functions and more.

Another observation would be that calling a user defined function in a loop is significant slower then calling a built in function in a loop.

I think you'd find that this would be much faster if you did a few thousand loops (make sure you use local (explicitly scoped) variables as well):
var i=0;
var n=0;
var arr=["   test  "," asda ", " test2 "];
var count=arraylen(arr);
for(i=1;i<10000;i++){
  for(n=1;n LTE count;n++){
    arr[n]=trim(arr[n]);
  }
}

The overhead of calling a function in Railo is fairly expensive because of the additional struct/scope operations it does in Java especially if you have several arguments, defaults, etc.
When you are trying to shave off a few more milliseconds under heavy load, you want to do the equivalent of "inlining" a function.  In C/C++, the compiler is even able to automate this kind of task, but in Railo, you'd have to do it manually.

More information about this concept:

You basically take all the guts of the function and put all the code out into your main script as local variables and eliminate any unnecessary work.  I frequently do this on core system features.  For example, when I check the user login state, rather then call a function, I just access a struct value directly with no validation using structkeyexists(request, 'user') instead of myCustomUserLoggedIn().  It wasn't a pointless premature optimization for me to do this because I prioritized my work around finding the functions that were called the most (an easy task with Railo's debugging features).   

A clever way to test your entire application's performance is to make your entire request happen a few hundred times, that way the numbers in Railo debugger will be bigger.  Often these things only register as 1ms on a normal request, but under heavy load, they'll sometimes jump to 50ms.   Sometimes, I run apachbench on the application and visit the railo debug logs while its running to see performance statistics when the app is under stress and I focus on those areas instead of what I think might be causing trouble.

In my app, the latency of the Internet is often worse then the server side processing time.   This kind of optimization has no impact on performance if your app is still touching the disk for all its data.  

Here are the worst things you can do in Railo in order of how expensive/slow they can be:

1. Request a resource from a remote server in a public request.
2. Run a query on a local database
3. Read from local files
4. Use createobject / cfinclude
5. Call a function

If you have eliminate all of those issues in your performance sensitive app, then you probably need to start writing with Java or C to squeeze out more performance or look at full page static caching instead of running dynamic pages all the time.

Bruce Kirkpatrick

unread,
Dec 28, 2012, 10:35:08 PM12/28/12
to ra...@googlegroups.com
The new Railo 4 member function syntax appears to use Java in such a way where there is less dynamic overhead.  This is probably the fastest way to do it THIS WAY in currently version of Railo, but looping over the array with a for loop should still be faster if it is relatively small.  The cost of accessing the "i" variables costs more then the trim operation most likely if the array grows large enough.

MyArray.each(function(item){});

You can see the source for this here:
and here:

I've noticed that some of the other Railo users have been referencing the Java code in their answers. I'm trying to make a habit of doing this in the future.  I used to think of Railo as a mysterious black box, but now it is just more code.

James Kilford

unread,
Jan 1, 2013, 8:39:08 AM1/1/13
to ra...@googlegroups.com
An interesting reply, Bruce.  Thanks!
Reply all
Reply to author
Forward
0 new messages