[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Issue 5336: Remove downcasting methods from Grob_array and Grob_info

From: nine . fierce . ballads
Subject: Re: Issue 5336: Remove downcasting methods from Grob_array and Grob_info (issue 344010043 by address@hidden)
Date: Mon, 11 Jun 2018 17:38:35 -0700


My intent was to make it clear to the person using these objects what
is going on.

One thing that was hidden was the extra cost of getting an Item* over
getting a Grob*.  Consider this excerpt from the old version of

    create_line_spanner (info.grob ());
    if (has_interface<Spanner> (info.grob ()))
        started_.push_back (info.spanner ());
        current_dynamic_spanner_ = info.spanner ();

Perhaps the person who wrote this code understood but didn't care that
he asked three times (at least: I haven't looked into
create_line_spanner) for a runtime check that info refers to a
Spanner.  I think it is more likely that he did not see or had
forgotten about the cast.  If he hadn't had info.spanner () available
to him, and had had to type out dynamic_cast<Spanner*> (info.grob ()),
he probably would have structured the code to do it once, not three

To be clear, the cost of dynamic casting in lilypond is not huge; but
it is noticeable and it can be improved.  Last week I profiled one of
the rest regression tests that always shows differences and found that
1% of cycles are spent on dynamic casting.  I think that's 1% of score
processing, but it might be 1% of the total; I'm not sure because it
was my first time using the tool and I chose to move on to another
task before verifying which.

Point two:

    Ligature_bracket_engraver::acknowledge_note_column (Grob_info info)
      if (ligature_)
          Tuplet_bracket::add_column (ligature_,
                                      info.item ());
          add_bound_item (ligature_, info.item ());

If info refers to a Spanner, then this code passes a null pointer to
add_column and add_bound_item.  I'm not sure if that would be bad, but
let's assume it would.  If the person who coded this had had to write,

    Item *item = dynamic_cast<Info*> (info.grob ());
    ... (item);
    ... (item);

he would be more likely to notice that the pointer might be null and
handle it.

But now let's say that we know that it is impossible for
acknowledge_note_column to be passed a Grob_info referring to anything
but an Item.  (That might actually be the case, but I'm not sure.)
Well, that's checkmate for Grob_info::item (), because all that is
required to handle _that_ is static_cast, and _it_ doesn't have the
overhead of a function call and a dynamic_cast.

Along the same lines are things like the following.  I hope I can
describe this as "loose" without offending any of my worthy comrades

    Paper_column::get_rank (Grob const *me)
      return dynamic_cast<Paper_column const *> (me)->rank_;

If "me" is a valid Grob that is not a Paper_column, this dereferences
a null pointer, which is not something that any function should be
doing, especially not one with an interface that accepts a Grob.  A
function that will not work with anything but a Paper_column should
have Paper_column in its signature.

Well, my kids have come home!  I have to go, but I think that's about
all I have to write anyway.  I'll add more later if anything comes to


Presenting dynamic casts as simple getters was hiding something that
is better left in the open.

Please review this at

Affected files (+57, -73 lines):
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/include/grob-array.hh
  M lily/include/grob-info.hh
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/
  M lily/

reply via email to

[Prev in Thread] Current Thread [Next in Thread]