Iteration-scoped variable in JSF / Richfaces iteration? - optimization

OK, this should be an interesting one I think. I want to minimize the number of invocations to my Seam component inside an iteration. I am using Seam 2.2.1.CR1, Richfaces 3.3.3.Final, JSF 1.2 and Facelets.
Please take a look the following Facelet snippet:
<rich:datatable value="#{myBean.products}" var="prod">
<rich:column rowspan="#{rowspan.calcHomePageProductRowspan(prod)}">
#{prod.name}
</rich:column>
<rich:column rowspan="#{rowspan.calcHomePageProductRowspan(prod)}">
#{prod.number}
</rich:column>
...
<rich:column rowspan="#{rowspan.calcHomePageProductRowspan(prod)}">
#{prod.somethingElse1}
</rich:column>
<rich:column rowspan="#{rowspan.calcHomePageProductRowspan(prod)}">
#{prod.somethingElse2}
</rich:column>
...
<rich:column rowspan="#{rowspan.calcHomePageProductRowspan(prod)}">
#{prod.somethingElse3}
</rich:column>
</rich:datatable>
In the above code I am computing an attribute (here the rowspan, but that doesn't really matter, it could be any attribute or value at all, so please don't focus on that) by evaluating an EL expression. As you can see, the method that calculates the value takes the current prod as an argument.
I have made an internal optimization in the rowspan Seam component, and it keeps in a HashMap all the already computed values for products. So, when the the EL expression is evaluated at the second rich:column, the rowspan first looks up in the HashMap the already computed value, and returns that, instead of re-computing all over again.
Although this is better that re-computing all over again, I still have to make an invocation to a Seam component. Is there a way to somehow invoke the Seam component only once, and somehow retain the computed value for the current iteration?
The analogous to Java would be to define a variable inside the loop at each iteration, and reuse it throughout the iteration.
Note: I have already made other Seam-oriented optimizations such as #BypassInterceptors, the Seam component is in the EVENT scope, so no hierarchical lookups take place etc.

Is there a way to somehow invoke the Seam component only once, and somehow retain the computed value for the current iteration?
Sure, in theory.
But I am not sure I fully understand your question. Which seam component are you talking about? rowspan?
If that is the case, then yeah, its invoked each time you call it, which makes sense. You are looping through a dataTable, and for each row you call it.
Without knowing more details about what you are trying to do, its difficult to suggest an answer. Is the code slow? Is that why you need to optimize further?
Update
Try this, though I am not sure if it works
<rich:dataTable value="#{myBean.products}" var="prod">
<ui:param name="myrowspan" value="#{rowspan.calcHomePageProductRowspan(prod)}"/>
<rich:column rowspan="#{myrowspan}">
#{prod.name}
</rich:column>
</rich:dataTable>
Second update
So if you don't change your code to be a #Out, #Factory, #Unwrap or similar, then this will always be evaluated each time it runs. This is just how JSF works.
That's why they say that you should do this in your getters, because JSF will call this for each JSF Phase.
public List<Foo> getFoo() {
if(this.field != null) { 
field = (List)entityManager.createQuery("from Foo").getResultList();
}
return this.field;
}
If you wouldn't have cached the list, and checking for null, JSF would hit the database for each phase and for each row in the data table.
Thus this is just something you have to live with.

Related

How to make a class that inherits the same methods as IO::Path?

I want to build a class in Raku. Here's what I have so far:
unit class Vimwiki::File;
has Str:D $.path is required where *.IO.e;
method size {
return $.file.IO.s;
}
I'd like to get rid of the size method by simply making my class inherit the methods from IO::Path but I'm at a bit of a loss for how to accomplish this. Trying is IO::Path throws errors when I try to create a new object:
$vwf = Vimwiki::File.new(path => 't/test_file.md');
Must specify a non-empty string as a path
in block <unit> at t/01-basic.rakutest line 24
Must specify a non-empty string as a path
I always try a person's code when looking at someone's SO. Yours didn't work. (No declaration of $vwf.) That instantly alerts me that someone hasn't applied Minimal Reproducible Example principles.
So I did and less than 60 seconds later:
IO::Path.new
Yields the same error.
Why?
The doc for IO::Path.new shows its signature:
multi method new(Str:D $path, ...
So, IO::Path's new method expects a positional argument that's a Str. You (and my MRE) haven't passed a positional argument that's a Str. Thus the error message.
Of course, you've declared your own attribute $path, and have passed a named argument to set it, and that's unfortunately confused you because of the coincidence with the name path, but that's the fun of programming.
What next, take #1
Having a path attribute that duplicates IO::Path's strikes me as likely to lead to unnecessary complexity and/or bugs. So I think I'd nix that.
If all you're trying to do is wrap an additional check around the filename, then you could just write:
unit class Vimwiki::File is IO::Path;
method new ($path, |) { $path.IO.e ?? (callsame) !! die 'nope' }
callsame redispatches the ongoing routine call (the new method call), with the exact same arguments, to the next best fitting candidate(s) that would have been chosen if your new one containing the callsame hadn't been called. In this case, the next candidate(s) will be the existing new method(s) of IO::Path.
That seems fine to get started. Then you can add other attributes and methods as you see fit...
What next, take #2
...except for the IO::Path bug you filed, which means you can't initialize attributes in the normal way because IO::Path breaks the standard object construction protocol! :(
Liz shows one way to workaround this bug.
In an earlier version of this answer, I had not only showed but recommended another approach, namely delegation via handles instead of ordinary inheritance. I have since concluded that that was over-complicating things, and so removed it from this answer. And then I read your issue!
So I guess the delegation approach might still be appropriate as a workaround for a bug. So if later readers want to see it in action, follow #sdondley's link to their code. But I'm leaving it out of this (hopefully final! famous last words...) version of this answer in the hope that by the time you (later reader) read this, you just need to do something really simple like take #1.

Invalid Iterator Fix

So, looking for advice on how to fix a situation or maybe a better way to program it.
I'm using iteration to build a complicated string from key:value pairs in an unordered_map. To make this work, I'm iterating through the map to find specific items, then sending a search term to an outside function to create the string. The outside function uses its own iterator to search the same unordered_map for the passed search term, then creates the string, then erases the entries that it referenced. The problem, I believe, is that although the outside function's iterator is still valid because it called the erase function, the iterators in the main function are now invalidated and throwing an out of range error. Is there a way to reset the iterators or send them to the next valid key:value pair when they become invalidated in order to avoid the error?
The code is a mess (mostly because I'm still discovering C++) and it might be possible to use recursion to accomplish this, but I wasn't able to get recursion to work correctly.
I can post the code, but without understanding the inputs and required outputs, it's likely not going to help explain anything, so for now, I'll just leave the question as-is: is there a way to "re-validate" invalidated iterators?
I was able to resolve the issue by redefining each of the iterators once the scope of control returned back to them. For the last iterator (in the outside function) that deleted individual key:value pairs from the unordered_map, I used:
if (it != map.end()) it = map.erase(it);
This forces the iterator to move to the next valid key:value pair after the erasure.
That worked for the end of the line, but didn't work once control was returned to each of the previous iterators. In those case, the iterators were invalidated when the outside function erased a key:value pair. So as control returned to an iterator, I included the following line before it looped back for increment:
if (it != map.end()) it = map.begin();
It seems to have resolved all of the issues, though I'm sure there's a better way to handle it.

FreeMarker ?has_content on Iterator

How does FreeMarker implement .iterator()?has_content for Iterator ?
Does it attempt to get the first item to decide whether to render,
and does it keep it for the iteration? Or does it start another iteration?
I have found this
static boolean isEmpty(TemplateModel model) throws TemplateModelException
{
if (model instanceof BeanModel) {
...
} else if (model instanceof TemplateCollectionModel) {
return !((TemplateCollectionModel) model).iterator().hasNext();
...
}
}
But I am not sure what Freemarker wraps the Iterator type to.
Is it TemplateCollectionModel?
It doesn't get the first item, it just calls hasNext(), and yes, with the default ObjectWrapper (see the object_wrapper configuration setting) it will be treated as a TemplateCollectionModel, which can be listed only once though. But prior to 2.3.24 (it's unreleased when I write this), there are some glitches to look out for (see below). Also if you are using pure BeansWrapper instead of the default ObjectWrapper, there's a glitch (see below too).
Glitch (2.3.23 and earlier): If you are using the default ObjectWrapper (you should), and the Iterator is not re-get for the subsequent listing, that is, the same already wrapped value is reused, then it will freak out telling that an Iterator can be listed only once.
Glitch 2, with pure BeansWrapper: It will just always say that it has content, even if the Iterator is empty. That's also fixed in 2.3.24, however, you need to create the BeansWrapper itself (i.e., not (just) the Configuration) with 2.3.24 incompatibleImprovements for the fix to be active.
Note that <#list ...>...<#else>...</#list> has been and is working in all cases (even before 2.3.24).
Last not least, thanks for bringing this topic to my attention. I have fixed these in 2.3.24 because of that. (Nightly can be built from here: https://github.com/apache/incubator-freemarker/tree/2.3-gae)

In data flow coverage, does returning a variable use it?

I have a small question in my mind. I researched it on the Internet but no-one is providing the exact answer. My question is:
In data flow coverage criteria, say there is a method which finally returns variable x. When drawing the graph for that method, is that return statement considered to be a use of x?
Yes, a return statement uses the value that it returns. I couldn't find an authoritative reference that says so in plain English either, but here are two arguments:
A return statement passes control from one part of a program to another, just like a method call does. The value being returned is analogous to a function parameter. return therefore is a use just like being a function parameter is a use.
The other kind of use in data flow analysis is when a value leaves the program and has some effect on the outside world, for example by being printed. If we're analyzing a method, rather than an entire program, return causes the value to leave the scope which we're analyzing. So it's a use for the same reason that printing is a use.

suppress list elements that have already been encountered

Hi I have a velocity template that I am trying to edit
it currently has a block that looks like
#foreach( $element in $myList )
$element.field1 ($element.field2) issued by $element.field ($element.field4 )
<br><br>
#end
the problem is some elements in the list are duplicated and I need to suppress the duplicates.
psuedo code for what I want is
for each element in list
if element is not in displayed
display element
add element to displayed
endif
endfor
can someone point me in the right direction?
This kind of logic (de-duplication) is probably something to be avoided in your view (Velocity) layer. Following Model-View-Controller, it would be better to have this logic managed by controller classes, leaving the Velocity template to simply render the data structure it is passed.
For example, by using a data structure such as a java.util.Set, duplicates would not be admitted and so there would be no need for the template to de-duplicate.
Personally I found Rob Harrop's Pro Jakarta Velocity a really good guide to MVC, especially Chapter 4 "Using Velocity in an MVC environment".
Have the model use a Set, have your controller code populate the set, and then the simple loop in your template code can be used as it is now.
In general, the less logic you implement in your view layer, the better. It will also make your code easier to test, so you can verify its behaviour without having to fire up the presentation components, app servers etc etc.
If there really is no choice and the logic absolutely must be written in the template, then the following implements the psuedocode presented:
#set($displayed = [])
#foreach( $element in $myList )
#if(!$displayed.contains($element))
$element.field1 ($element.field2) issued by $element.field ($element.field4 )
<br><br>
#set($ignore = $displayed.add($element))
#end
#end
Note the messiness with #set($ignore = $displayed.add($element)) - this has to be done to suppress the output from java.util.List's add() method (boolean) from being output. Another reason not to write this in template code!
Of course, you would also need to make sure that equals() is correctly implemented on the type added to the list so that the List operations - contains() and add() work correctly.
Definitely an inferior solution to the MVC approach above, but presented as an option of last resort.