[RFC] A differnt options system

Chris Shoemaker c.shoemaker at cox.net
Wed Feb 16 17:57:38 EST 2005


On Wed, Feb 16, 2005 at 02:30:27PM -0500, Derek Atkins wrote:
> 
> >  * But... there are cases where everything doesn't work perfectly, and
> >  * there are cases where things work, but painfully:
> >  *
> >  * 1) GncOptionWin's option layout is quite flat.  Linear layout order
> >  * can be specified in the scheme option definition, but that's it.
> 
> Well, not quite.  You supply a page and a layout order on the page.
> True, you can't put options next to each other, but is that
> necessarily a bad thing?  Agreed, the options system is not meant to
> be a generic dialog builder.  Is that really a problem?

Yes, it's AWFUL.  It means on page one of the dialog I have 20
checkboxes down only the left side of the page.  The dialog is as tall
as my screen so all the options fit.  Then on page two, I have two or
three wide options scrunched up at the top.  Both pages look awful.
It's an HMI disaster, and there's NO way to avoid it if you have
different shaped widgets.  The generated gui layout is only marginally
better than random widget placement!  How's a programmer to create a
friendly interface with that?

> 
> >  * 2) Some option types are buggy.
> 
> Oh?  Which ones?  If there are buggy option types that should
> definitely be fixed!  This is the first I've heard of buggy options.

By pure chance, I had to take a break from coding an hour ago to do
finances.  For my real books, I still use 1.8.9.  I was in a P&L
report, and checking the boxes for subtotaling (which by the way are
laid out *worse* than random, because they are misleading about which
field go with with key) when I saw:

 ** CRITICAL **: file option-util.c: line 173
(gnc_option_set_selectable): assertion `option->odb->set_selectable !=
NULL' failed.

and the report behaved as if the box was checked when it wasn't.  For
me to see strange behavior like this is not uncommon -- I do what I
always do.  Close the options and reopen.  You'd think this would be
an easy bug to fix.  Maybe it is, but knowing what I know, I'd guess
it's probably not. :(  

I want to help fix bugs, really.  But if people who have been hacking
gnucash for years only understand the options system in part, what
chance do I have after only a few months?

<snip explanation that the C api grows a needed>

> >  * 4) Reusing groups of options isn't easy.  There's probably some way
> >  * to define the option list as a concatenation of smaller option
> >  * lists, but I don't think there are any examples of this.
> 
> It's very easy, and there are examples.  See gnc:options-add-account-selection!
> in src/reports/report-system/options-utilities.scm for one example.
> Basically you write a scheme procedure that defines the block of
> options you want to create.

Thanks for pointing that out.  I knew it should be possible.

> 
> >  * 5) If you're storing option values in C as enumerated types
> >  * (multi-choice option type), you'll need to specify the enumeration
> >  * in C and in Scheme, and keep them in sync.
> 
> That's not quite true.  Yes, you need to define the list in the option
> definition in scheme, but what those values mean is up to you later.
> You could define them in one place and export to the other, or you can
> define in two places and keep them in sync.  That's just a matter of
> programming.  

Exactly, so if I want to display an option with a new enumeration, I
have to either duplicate the list or figure out how to "export" from
one language to the other.  I hope you can see how non-trivial that is
for people other than yourself.

> Can you show me an example where there's a list that needs to be
> kept in sync between scheme and C?

Well, the file you reference above contains:
(define (gnc:account-get-type-string-plural type)
  (assoc-ref
   (list
    (cons 'bank (_ "Bank"))
    (cons 'cash (_ "Cash"))
    (cons 'credit (_ "Credits"))
    (cons 'asset (_ "Assets"))
    (cons 'liability (_ "Liabilities"))
    (cons 'stock (_ "Stocks"))
    (cons 'mutual-fund (_ "Mutual Funds"))
    (cons 'currency (_ "Currencies"))
    (cons 'income (_ "Income"))
    (cons 'expense (_ "Expenses"))
    (cons 'equity (_ "Equities"))
    (cons 'checking (_ "Checking"))
    (cons 'savings (_ "Savings"))
    (cons 'money-market (_ "Money Market"))
    (cons 'receivable (_ "Accounts Receivable"))
    (cons 'payable (_ "Accounts Payable"))
    (cons 'credit-line (_ "Credit Lines")))
   type))

I suppose that's not exactly independent of xaccAccount* and
account_type_name[] in Account.c

> 
> >  * 6) Your options are displayed in a GtkNotebook page.  I hope that's
> >  * what you want, because that's the way it is.
> 
> And why is this a problem?  It's just a bunch of options.  If you have
> multiple pages how ELSE would display them other than a GtkNotebook?
> What other multi-page dialog method would you use?  A Druid?

What if I don't want a notebook with a single tab?

> 
> >  *    Of course these problems are probably solvable by improving
> >  * GNCOptionWin and GncOptionDB and the Scheme options system.  But,
> >  * that's not easy.  (Feel free to prove otherwise.)  The fact is, the
> >  * complexity of the "options triad" is beyond the comprehension of an
> >  * averagely bright high-school student.  And outside of its
> >  * author(s), it seems there are very few who understand its depths
> >  * (GncPropWin author excluded).
> 
> * raises his hand *
> 
> Take a look at the business options.  It adds a bunch of new option
> types.  It's pretty darn easy to do.  Granted, it depends on the data
> type you want to define an option, but adding new options is not a lot
> of code and is not something that happens very often.  So it seems
> like an awful lot of work to optimize for adding new options rather
> than optimizing for using the options database.

IMO, my proposal makes both adding new options and using existing
options easier.  As for using options, look at how
gnc-plugin-page-account-tree.c uses the options system.  Compare that
to the equivalent functionality with the proposed api.  Conceptually,
it's quite similar, especially w.r.t storage, but as for ease of use,
the proposed api is much simpler.

> 
> >  *     That said, there are cases where the options triad is clearly
> >  * what you need.  For example: 
> >  *
> >  * 1) You need access to the option values from Scheme, or 
> 
> We do.  The reports.

Yes, that is a real issue.  But wouldn't a scheme wrapper over the
proposed api solve that for the reports?  In that case, scheme and C
switch leads.  (And as a topic for some other fun thread: there are
better ways to generate html reports than from scheme, and I hope one
day that gnucash will use one of them.  After the lack of budgeting, I
consider report inflexibility the next most major drawback to gnucash.)

> 
> >  * 2) You need the option values to have a life-time longer than that
> >  * of any C-side object.
> 
> Why would you NOT want to store your options?  What's the point of
> making options if you don't store them for later?

Of course you store them.  You store them in C variables or structures
or whatever, and eventually they may be stored in some other form.
Maybe I wasn't clear on this point.  I'm basically referring to
overall program preferences here.  This is perhaps where gconf could
fit.

> 
> >  *     Furthermore, there are several qualities that make the options
> >  * triad appealing even when the above requirements are absent:
> >  * 
> >  * 1) The concept of "sections" is useful for organizing large sets of
> >  * options.
> >  *
> >  * 2) The GncOptionDB API hides the GTK+ details of setting and
> >  * getting values to/from the widgets.
> >  *
> >  * 3) The scheme option type definitions hide the GTK+ details.
> >  *
> >  * 4) The combination of 2) and 3) above mean that, conceivably, a
> >  * programmer could set/get option values without even knowing about
> >  * GTK+, (e.g. GtkEntry, or GtkSpinButton).  More realistically, it
> >  * means a programmer spends less time looking up things like
> >  * gtk_entry_set_text() and gtk_spin_button_get_value() in the GTK+
> >  * API Reference.
> 
> Yes, these are all good things!  IMHO these are features that should
> be retained.

My comments made a case that the proposed api retains these benefits.
Did you disagree?


> 
> >  * XML vs. Scheme:
> >  *
> >  *    Specifically, GncPropWin expects the option list and layout to
> >  * be defined in XML instead of Scheme.  Given GnuCash's extensive
> >  * investment in Scheme, this may prove controversial.  
> >  *
> >  *    Scheme has its pros and cons. <shameless grin> Scheme is a real
> >  * programming language, so it has computational power and
> >  * expressiveness that XML will never have.  OTOH, the task of
> >  * setting/getting option values (which is essentially a programming
> >  * language task and must be defined in whatever programming language
> >  * you're working in) is distinct from the task of enumerating the
> >  * list of options and their layout (which is not a computational task
> >  * but a descriptive task).
> 
> * shrugs * I don't really see this as a major issue, one way or the
> other.  Whether the options are defined in scheme or C seems to be a
> no-op tradeoff in my book.  So what if scheme is a full language and
> guile isn't?

Did you mean glade?  I think this is an issue only insofar as using
scheme to do things that scheme is not well-suited for (like gui
specification) becomes a maintenance burden and prevents the creation
of a reasonable GUI.

> 
> >  * No long-term option value storage:
> >  *
> >  *    Another significant design difference is the option value
> >  * storage.  GncPropWin is meant to be considered just a GUI tool,
> >  * like a dialog window, and doesn't provide any long-term (longer
> >  * than the dialog's lifetime) option value storage.  So, you must set
> >  * the option values every time you create the GncPropWin and get the
> >  * option values before the GncPropWin is destroyed.  (Which you have
> >  * to do anyway for the options triad if you're setting object
> >  * property values for C objects that don't have Scheme storage.)
> 
> I think this is a BAD THING.  What's the point of making options if
> you can't save them somewhere?

Ok, I guess I wasn't clear about storage.  You store the option values
by getting them from the dialog, just like things currently work on
the C side with the existing options system.  You know,
option_db_lookup stuff...  

> 
> >  *    Even though GncPropWin is less ambitious than the option triad
> >  * in that respect, I consider this a design feature, not a
> >  * short-coming, because it decouples value storage from the gui.  For
> >  * C object properties, this is good because the object will usually
> >  * provide their own property value storage as fields in the object's
> >  * structure.  For things like top-level program preferences this may
> >  * be not-so-good, because option value persistence no longer comes
> >  * "automatically".  
> 
> The triad has the gui and storage decoupled, too.  

You mean I can use the scheme-generated gui and have values stored with gconf?

> But you still need option storage somewhere.  So in essence you're
> just redesigning the triad without knowing that you're doing so!  :)

Yes and no.  Yes, I'm implementing a functionality that _in concept_
is already implemented.  But I think it's conscious.  :)

> 
> >  *    GncPropWin supports composition of option groups.  First,
> >  * libglade will support composition through the use of the "custom
> >  * widget".  This is very easy.  But, it requires that you create a
> >  * composite GtkWidget that derives from some GtkWidget class.
> 
> This is a LOT of work for the programmer.  More so than a simple
> scheme script to generate a bunch of options.

Wait a sec.  Let's compare apples to apples.  I think there are
actually two cases here.  First, there's the case where the "option
group" has high cohesion and really should be encapsulated into a
object so that it's behavior can live with it.  That case is analogous
to the task of creating a new option type, which is also a lot of work
in the current options system.

Second, there's the case where the "option group" is just a loose list
of options, like in options-utilities.scm.  In scheme this is trivial
to specify and reuse.  WORST case with glade would be to make the
group once and then cut-n-paste it into multiple other glade files.
But I can think of several less-than-worst-case alternatives.  One
such alternative is to automatically replace specially-named
containers with other glade files, but there may be better ways.


> 
> >  *     Are there any new benefits?  I hope so. :) I hope the chief new
> >  * benefit will be maintainability.  GncPropWin is quite a bit simpler
> >  * than the options triad, and it could be made even simpler if the
> >  * type generic interface was dropped.  It also seems to be more
> >  * powerful in terms of supported option types.  Newly invented widget
> >  * types are supported automatically, and anything that derives from
> >  * GtkWidget can be accessed.
> 
> It may be simpler but at the cost of functionality.  :(

While it doesn't do everything that the options triad does (by design)
it does do quite a bit that the option system can't do, like produce
nicely laid-out guis, and provide a simple C api.

But, it's important to highlight what it _doesn't_ do.  Please help me
complete this list:

1) Provide scheme-side option value access 

2) Provide persistence for program preference option values across
program executions

3) Provide for the composition of loosely-grouped option values in a
way that is as simple as in scheme

what else?

-chris


More information about the gnucash-devel mailing list