Re: glib: GTimer patch for elapsed time



On Sat, 2002-07-27 at 07:01, Owen Taylor wrote:

> Well, clearly it was wrong for start to reset; but that's done
> with so we have to work from there. To me, adding continue() to do
> what start should have done is less confusing then adding a second
> elapsed time variable that behaves differently than the main one.

Yes, but that is only the implementation - start() may happen to end up
effectively resetting the elapsed time.  But my point is that it is the
implementation that needs to be improved, and _not_ the interface.  The
user should not have to know or care about the implementation and what
it should or should not have done.

In my proposed patch, the semantics of start() and stop() do not change
at all - conceptually they still start and stop the timer, which is what
you would expect.  The difference is simply in the reporting; until now
you could only query the time elapsed since the last start call.  That
is made clear in the docs.  All I added was a way to return the total
elapsed running time - as far as the user is concerned, there is a
single new feature, and all the rest works exactly the same (and is
backward compatible).

Under your proposal, adding continue() would still require adding
another variable to track the total elapsed time, then change most of
the other functions accordingly.  But then you are not only changing
slightly the semantics of start() because users now have to potentially
call continue() instead, but then you are also changing the documented
meaning of elapsed(), since it may return the total time or just the
last "lap" time.

Let's look at it from the users' perspective.  We have:

a)   my patch, that adds a single new function to return the total
elapsed running time.  All other code behaves the same.

b)   we add continue(), which is called instead of start() sometimes,
and elapsed() returns the last step time if you most recently called
start(), or the total elapsed if you have been calling continue().

I think it is more confusing having two slightly different ways of
starting the clock.  You would require the user to maintain state
external to the GTimer code to decide which API to call!

> The second variable strikes me as being a somewhat inflexible 
> interface because the question then becomes "what if I want another
> total (groups of 10 events)". There is a general principle that
> you should either allow 1 of something or an unlimited number of that
> thing. Not 2 or 3 or 5.

I agree, but I don't really understand your point here.  With my
proposed patch, you create a timer, then you can indeed start it and
stop it an unlimited number of times, and it will correctly track the
total running time.  How is that possibly inflexible?  If you want to
track groups of events, use one timer per group.

Don't think of it as a "second variable" - think of it as allowing the
user to use the GTimer like a stopwatch, which is just what the
interface implies you can do.

> >  I think having g_timer_continue() is less orthogonal than the original
> > interface, and would be more confusing to the user (eg. do you do a
> > continue after a reset or only after stop?).  Also, it belies the
> > implementation somewhat, since it effectively exposes state to the
> > user.  Client code would potentially need some logic to decide whether
> > to call start if it was the first time since a reset, or continue of
> > start has already been called.
> 
> It would be very simple; three primitives:
> 
>  continue
>  stop
>  reset
> 
> and:
> 
>  start == reset + continue

Put like that it seems simple, but you don't address my point above -
you are exposing internal state to the user, who shouldn't need to worry
about that sort of thing.
 
> > I've tested my patch and written some client code; it looks and works
> > just fine.  Simple usage where the timer is being used inside the one
> > function to time a single event doesn't make much difference.  But when
> > you create a timer that belongs to a window, start and stop it based on
> > user events, and display the elapsed time on window updates, that's when
> > you need this sort of API.
> 
> All we are adding here is convenience, since it is easy enough to
> keep your own total elapsed time. API should be added when it
> :
> 
>  a) Enables something that isn't otherwise possible
>  b) Makes an activity significantly easier
> 
> If you are just making something marginally easier than there is the
> danger that you are just obscuring what's really going on.

Surely the whole point of providing the GTimer support in the first
place was to add value beyond having to call gettimeofday() yourself. 
You provide an interface that allows the user to achieve what they need,
and encapsulate the mechanism for how it is done.  Otherwise why do we
bother providing these APIs if not to provide a uniform easy to use
interface?  Following the above argument, GTimer might not exist at all.

When I first tried to use the GTimer in my own application, I reasonably
expected it to be able to track total elapsed time, and was surprised
when it didn't.  Imagine you are writing a game, and you need to track
the total time the game is in play.  So you create the timer in your
window init() function and keep it hanging around.  You have a regular
event that updates the display in your GUI with the current elapsed
time.  And when the user presses the start and stop buttons, you need to
start and stop the game timer appropriately in the event handlers. 
Obviously the game clock must show the _total_ elapsed time in the GUI
update loop.  This is a very genuine and common sort of requirement,
which is not met by the current implementation, but is provided in a
fully backward-compatible way by my patch.

> 
> I'm not sure saving:
> 
>  double total = 0;
>  
>  for (each iteration) {
>    g_timer_start (timer);
> 
>    total += g_timer_elapsed (timer);
>  }
> 
>  g_print ("%g", total);
> 
> Really meets the criterion of "significantly easier". Perhaps the
> right direction here is simple to do nothing?

I don't believe so - the above example is trivial, and by doing all the
work in a single function, it does not show the sort of application that
would benefit from a decent stopwatch timer (see above example).

Anyway, isn't this breaking encapsulation if you have to do half the
work of the timer outside its own implementation?  What good is a timer
that has the interface for a regular stopwatch, but does not behave like
one, or expects you to track its internal state?

The RogueWave toolkit has a timer class that behaves almost the same as
I am proposing for GTimer:

    http://www.roguewave.com/support/docs/tlsref/rwtimer.cfm

Another example is at http://quantlib.org/quep/quep3/classTimer.html.

Have you examined the actual patch I proposed?

I can post some sample code to illustrate the usage of the modified
GTimer if that would help.

  ::gavin

-- 
Gavin Baker // gavinb*antonym_org // Linux|Python|Esperanto|MIDI|Cheese




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