Something I all too often observe in plugins for SketchUp that kills performance is the usage of .typename
within loops. I blame the SketchUp Ruby API documentation for this widespread usage as it’s used throughout the code examples.
Alex Mozg illustrated how big the performance hit is with his speed test snippet posed in a SketchUcation thread.
Using his script I found the biggest model I had at hand and came out with the following results:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | === AT - SpeedTest === is_a? - 16.297s kind_of? - 16.141s class - 18.703s typename - 88.703s === Model Statistics === edges = 8396595 faces = 1026520 groups = 52643 components = 526428 construction_lines = 2 construction_points = 4 images = 0 section_planes = 0 texts = 0 others = 0 |
=== AT - SpeedTest === is_a? - 16.297s kind_of? - 16.141s class - 18.703s typename - 88.703s === Model Statistics === edges = 8396595 faces = 1026520 groups = 52643 components = 526428 construction_lines = 2 construction_points = 4 images = 0 section_planes = 0 texts = 0 others = 0
As you can see, .typename
is many times slower than .class
or .is_a?
. This is because .typename
means string comparison which is a slow operation in any language. The other methods compares based on object classes which is simple lookups – many times faster.
The exception
There is a set of entities where one has to use .typename
in order to determine what an entity is; Polyline3d, DimensionLinear and DimensionRadial. All of these report Sketchup::DrawingElement
to Entity.class
. These are entities which the Ruby API doesn’t really expose any control over. The only thing is that .typename
will return "Polyline3d"
, "DimensionLinear"
and "DimensionRadial"
respectively.
If you really need to identify these objects in a loop, first check if it’s class is SketchUp::DrawingElement
then use .typename
in order to reduce string comparisons.
1 2 3 4 5 6 7 8 9 10 11 | for entity in entities if entity.class == Sketchup::DrawingElement if entity.typename == 'Polyline3d' # ... elsif entity.typename == 'DimensionLinear' # ... elsif entity.typename == 'DimensionRadial' # ... end end end |
for entity in entities if entity.class == Sketchup::DrawingElement if entity.typename == 'Polyline3d' # ... elsif entity.typename == 'DimensionLinear' # ... elsif entity.typename == 'DimensionRadial' # ... end end end
hi Thom,
nice write-up,
when I grep my Plugins folder for .typename I get 276 hits,
can find and replace be used to en-mass, with a filter for ‘Polyline3d’ or would each need case use evaluation and testing?
Which of the alternatives would be the ‘safest’ switch.
john
You cannot do a simple search and replace I’m afraid. The pattern for which
.typename
is used may vary.It could be in a
if else
structure:It could be in a
switch
structure:Or it could even be used standalone – maybe to just display the description of the selected entity. (A use case I didn’t describe in the exception section.)
The ‘Polyline3d’ etc. tests is only needed if the script needs to be checking for polyline or dimension entities. I described them as cases where one cannot avoid using
.typename
.So unfortunately, one has to look at each plugin and the source code in order to make a reliable replacement for
.typename
.I really wish the API documentation would change its examples to not use that method. It promotes a really bad practice unfortunately.
[…] Avoid Entity.typename, use Entity.is_a? […]