model = Sketchup.active_model
defs = model.definitions
ents = model.active_entities
ents.each do |e|
if (e.is_a? Sketchup::Group) || (e.is_a? Sketchup::ComponentInstance)
# do something with e...
puts "#{e}"
dents = e.definition.entities
nested = dents.grep(Sketchup::Group).concat(dents.grep(Sketchup::ComponentInstance))
nested.each do |child|
# do something with each ent inside e...
puts " #{child}"
end
end
end
1-2% difference is usually not noticeable. I would choose whatever requires the least amount of code and thus is easiest/fastest to read. Code readability is very important when you go back later to add more features or to fix bugs.
Of the code examples you provided I’d say the first is easier to read because there is less text in total and the code is divided into smaller chunks. You can very easily see what entities are iterated before having to care what are later done to those entities. For this example the difference isn’t very big but it’s good to form a habit of writing as readable code as possible when making larger projects.
Btw, when using methods that atke arguments such as is_a? it is recommended to have parenthesis around the arguments. This makes it slightly faster and easier for the brain to parse the code. Again, it’s not a huge difference but when the codebase is getting bigger all these small things add up.
the keywords or and and are not recommended in Ruby since their priority can be quite unexpected. Also I wouldn’t use multiple rows for a condition since you could then easily read part of the condition as a part of the code block. For this example I would extract the condition to a separate method.
if is_instance?(entity)
# Do stuff
end
def is_instance?(entity)
entity.is_a?(Sekcthup::Group) || entity.is_a?(Sketchup::ComponentInstance)
end
One of the finding there was that for in loops was faster than .each (in general). But that held true for Ruby 1.8. In Ruby 2.0 and onwards that changed.
And there are many other subtle behaviours that could affect how fast your loop will be. So; profile, profile, profile.
I heartily share this sentiment, with one caveat: by “least amount of code” I would mean the simplest, cleanest expression vs multiple things packed onto each line. Packing onto a line has a tiny effect as the interpreter parses the code, but no effect at all on run time. But, at least in my experience, it makes it harder for a human to understand the logic. I always choose ease of reading over terseness, provided of course that the expressions are equivalent. Many logic errors result from trying to be too terse or clever!
You are getting into stylistic issues so we will have to agree to disagree. I do use parenthesis around if statements etc as I find them very much easier to speed read and maintain.
I certainly agree that adding parenthesis to all methods helps the brain to learn.
I use the c style && instead of and and I use || instead of or. It speeds readability and there is no confusion on precedence.
I use single quotes for string literals when possible. It is slightly faster than double quotes as the parser doesn’t have to take the time to look for escaped characters etc. Having said that I do make use of << for string concatenations and “#{}” instead of printf style.
I also break up long conditional statements on to multiple lines and I create references to objects.
Having said that Additionally when workable I like to have case statements on the same line where possible and I do make use of white space not tabs to line everything up. If you are sharing code spaces always line up - tabs only line up if the reader has their tab settings set the same as you.
case txt[0]
when 'type'; cab.type = s.to_i
when 'style'; cab.style = s.to_i
when 'description'; cab.description = s
when 'note'; cab.note = s
when 'model'; cab.model = s
TestUp in the Developer Tools repo is abandoned. TestUp2 is live and active. However, TestUp is for running test units - not for profiling.
It’s also worth having a look at what the Ruby community in general use (We don’t reinvent the wheel for SketchUp.)
In many cases when we have a small snippet we want to compare then Benchmark can be used:
For actual profiling, of digging into a call stack and see what is using the most time I’ve been experimenting with the RubyProf gem. But it’s been a pain to get working because it need compiling. Additionally it stopped working properly in recent SU versions so I had to hack it to get useful data. Been hoping to get time to package up this into a SU tool.
The most common reasons for slow extension performance that I observer are:
Not setting the second argument in model.start_operation to true.
Using .typename instead of .is_a? (Huge impact! Strings are slow, in Ruby; Very slow!)
Not using bulk methods in the API (entities.erase_entities(array_entities) is faster than entities.to_a.each { |e| e.erase! }. Similarly, array_entities.each { |e| selection.add(e) } is slower than selection.add(array_entities). Always operate in bulk if possible.
Yea - that’s what I do for very quick tests. I reach for Benchmark when I formalize my tests - setting up tests that I can run to monitor performance in my applications over time.
When trying to benchmark code, I would try to remove any IO code, as its duration/timing may be longer than the code under test. Obviously, IO to a hard drive will be slow, but puts is also IO. Said simply, having a puts in your blocks invalidates the test results.
I believe timing resolution varies by OS, and Windows may only be 1 frarme, or 1/60 second (ruby trunk may change this, as to backports to 2.4 or 2.3, unknown). Multiples of 0.0156 are the give-away…
Timings vary, which is the reason most tests using benchmark perform the tests many times.
Generally, most methods for selecting from collections will be pretty close as to time, and whatever other code you’re using (ie, code interacting with SU objects) will probably be where the optimizations can occur. Complex calculations may also require optimization.
Below is some code I used to check some selection methods (changed to compact it)…