Hi

Sorry, got distracted for a few days...

>> (in list_column_helpers)
>> def render_list_column
>>     self.send("column_#{column}")
>>     rescue
>>       define_render_list_column #create a column override function
>>       self.send("column_#{column}")
>>     end
>> end
>>     
>
> I don't know if it's a good idea. It could break per-request configuration, 
> changing form_ui in create and update actions for example,

Hmm, actually I don't think so?  In any case the rough proposal is 
effectively that we cache the calculation of figuring out how to render 
each column - as you say later, there are quite a few ways to achieve 
this, this is just one way!

However, to continue this idea a bit further:

- Currently with the ruby VM, calling a function which does not exist 
and then "rescue"ing is moderately expensive when the call fails. 
However, it's very cheap for every subsequent call when we don't get a 
rescue.  In comparison checking for the existence of a function before 
calling it is less expensive than a rescue, but adds up quite a bit if 
we call it every time.

- So the idea was that currently you can override a column format 
function by declaring some function "mycol_column", so what we do is 
define these for every column it doesn't already exist.  Additionally 
the icing would  be to define it somewhere above the controller class so 
that if the user dynamically creates this function in some per-row 
config it will override our function.  However, if this is not possible 
I think it's only a minor tweak to adjust the per_row/per_request 
functions to override the newly created functions - one simple solution 
would be to define the renderme_column function to literally figure out 
the column type for each call (ie revert back to old per call dynamic 
rendering)


The big picture here though is that we separate out a library of tight 
column rendering helpers (which can still be overridden as per now), but 
separate these quite clearly from the function which figures out how we 
want to render the column

The current situation is that we run a ton of code to figure out how to 
render a column, and then right down in the bowls of that function we 
call the render function.  This makes for example figuring out how to 
add a date format helper quite involved in terms of figuring out how to 
hook into this.  Instead our algorithm should be to be one pass to 
figure out how to render the column, then another pass to run that 
render function (much easier to debug and extend)

Now, if you look at the plugins an interesting direction (but possibly 
not speedy?) would be to make all datatypes a kind of "plugin" where 
each data type (say "Text", "Date", etc) are each given a chance to scan 
the list of columns, decide which columns they want to hook into and 
claim those columns as their own.  It would require some kind of sort 
order so that we can prioritise the order plugins can "claim" columns.  
This would mean that adding new render's would simply be a case of 
adding them into the list of objects which get a chance to scan the col 
list and claim columns to render

The interesting bit about this idea is that with some tweaking it could 
be made to run at boot time and not per-request. Would need a bit of 
thought on how to handle per-request overrides of column rendering 
(personally I think it's acceptable to make the user define per-column 
renderers to override ours - these can make use of all the built-in AS 
code so they can be quite efficient functions and perhaps defined 
dynamically)

> Also, what do you think about caching what method call in an attribute of 
> column? We should homogenize arguments for overrides and form_ui methods for 
> using that.
>   

I think we are going down the same path here - the only question is now 
best to cache?

I think if we can define procs dynamically then we can implement this in 
the fastest possible way. User can then either override our choices, or 
we could add a flag which (bizarely) defines the column_render function 
to revert to doing some kind of dynamic lookup each time it's run (ie 
define something which effectively reverts to the old behaviour!)


> Caching the method for render we can put the logic in other method, and 
> method 
> which render only should to fill the caching attribute if it's empty 
> (caching_attribute ||= method_with_caching_logic) and then use that method.
>   

Indeed

I think the big win here is not so much the speed improvement, but the 
separation of logic from the rendering implementation - if we get this 
right it should become very simple to add new ways to render columns (ie 
rendering algorithms, not just overriding that one column)

> I think this is easier to improve, it should be our fist step IMHO, although 
> more tests would be useful to avoid regressions with these changes.
>   

One easy win is in the area of rendering the action links - I measured 
this as something like 10-20% of my overall rendering time on scaffold 
with quite a few columns

Additionally I observe that at least current versions of rails ERB have 
an apparently brain dead implementation of rendering templates which 
seems to do something like straight concatenations of strings, hence 
there is a kind of exponential behaviour as the size of partials goes up 
and as your partial gets more complex.  I saw a very clever trick 
implemented in Lua which renders a large bunch of concatenations by 
rendering them into an array and then merging that array down as a 
series of pyramid concatenations - this reduces the number of memory 
allocations to some log2(N) of the normal amount. 

The punchline being that if you slightly tweak the partials to remove 
whitespace, fold <td></td> onto the same line for short lines, remove 
line returns, remove windows \R\Ns (so that the <%- -%> works properly) 
then I observe something like a 5% improvement in rendering time JUST by 
tweaking the action links partial!

Anyway, the more code we can get out of per-request and into boot time 
the better

Cheers

Ed W

--

You received this message because you are subscribed to the Google Groups 
"ActiveScaffold : Ruby on Rails plugin" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/activescaffold?hl=en.


Reply via email to