-LY_DEFINE (ly_get_grob_property,
- "ly:get-grob-property", 2, 0, 0, (SCM grob, SCM sym),
- "Get the value of a value in grob @var{g} of property @var{sym}. It\n"
-"will return @code{'()} (end-of-list) if @var{g} doesn't have @var{sym} set.\n"
-"\n"
-"Grob properties are stored as GUILE association lists, with symbols as\n"
-"keys. All lookup functions identify undefined properties with\n"
-"end-of-list (i.e. @code{'()} in Scheme or @code{SCM_EOL} in C)\n"
-"\n"
-"Properties are stored in two ways:\n"
-"@itemize @bullet\n"
-"@item mutable properties.\n"
-"Grob properties that change from object to object. The storage of\n"
-"these are private to a grob. For example pointers to other grobs are\n"
-"always stored in the mutable properties.\n"
-"\n"
-"@item immutable properties.\n"
-"Grob properties that are shared across different grobs of the same\n"
-"type. The storage is shared, and hence it is read-only. Typically, this\n"
-"is used to store function callbacks, and default settings. They are\n"
-"initially read from @file{scm/grob-description.scm}.\n"
-"@end itemize\n"
-"\n")
-{
- Grob * sc = unsmob_grob (grob);
- SCM_ASSERT_TYPE (sc, grob, SCM_ARG1, __FUNCTION__, "grob");
- SCM_ASSERT_TYPE (gh_symbol_p (sym), sym, SCM_ARG2, __FUNCTION__, "symbol");
-
- return sc->internal_get_grob_property (sym);
-}
-
-LY_DEFINE (spanner_get_bound, "ly:get-spanner-bound", 2 , 0, 0,
- (SCM slur, SCM dir),
- "Get one of the bounds of @var{spanner}. @var{dir} is @code{-1} "
- "for left, and @code{1} for right.")
-{
- Spanner * sl = dynamic_cast<Spanner*> (unsmob_grob (slur));
- SCM_ASSERT_TYPE (sl, slur, SCM_ARG1, __FUNCTION__, "spanner grob");
- SCM_ASSERT_TYPE (ly_dir_p (dir), slur, SCM_ARG2, __FUNCTION__, "dir");
- return sl->get_bound (to_dir (dir))->self_scm ();
+LY_DEFINE (ly_grob_property, "ly:grob-property",
+ 2, 1, 0, (SCM grob, SCM sym, SCM deflt),
+ "Return the value of a value in grob@tie{}@var{g} of property"
+ " @var{sym}. It returns @code{'()} (end-of-list) or"
+ " @var{deflt} (if specified) if @var{sym} is undefined"
+ " in@tie{}@var{g}.")
+{
+ Grob *sc = unsmob_grob (grob);
+
+ LY_ASSERT_SMOB (Grob, grob, 1);
+ LY_ASSERT_TYPE (ly_is_symbol, sym, 2);
+ if (deflt == SCM_UNDEFINED)
+ deflt = SCM_EOL;
+
+ SCM retval = sc->internal_get_property (sym);
+ if (retval == SCM_EOL)
+ retval = deflt;
+
+ return retval;