Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search

[REBOL] Re: Speeding up code

From: joel:neely:fedex at: 14-Feb-2002 21:59

Hi, Sunanda, Things have been a bit too busy for me to follow up before now... Sorry! [SunandaDH--aol--com] wrote:
> Object+functions of course give a lot more room to breathe -- it > is easier to have persistent variables in them than it is with > function+refinements. >
I can interpret that statement two ways -- both of which I agree with wholeheartedly -- and it's quite likely that you meant both of them, of course! 1) Using "literal" series values inside a function to cache the persistent data is certainly more obscure and provides more opportunities for error than the use of object attributes. 2) Using a single object to manage behavior over a single state (collection of attributes), then MAKEing more objects from that prototype (if needed for multiple stateful entities) lets us completely separate the management of the collection from the management of (each) state. I've even experimented with building closures via USE but gave up as soon as I hit the need for multiple "cases" to be active at once. I couldn't see anything that closures do that objects don't do at least as well/clearly, and objects are more general.
> From the outside there is almost no difference between calling an > object/function and a function/refinement. If I rewrote my code > to be an object but with the same interface, you couldn't tell > the difference from seeing the invocation: > > >> unit-timer/start "A code unit" >
Perhaps I misunderstood, but I thought part of the original post expressed a desire to *avoid* having that interface. A simple typo, such as unit-timer/start "A code unit" ; ; *LOTS* of lines of code here ; unit-timer/end "A code unti" could waste considerable time, thus (I had thought) the desire to avoid having the string argument at all.
> I say _almost_ no difference for two reasons: > > 01 -- In the original code, an invocation without a refinement > executes the code and returns False: > >> print unit-timer > == false >
Just out of curiousity, why? I saw that, but didn't understand it.
> If it was an object, invocating the object name alone returns > the object: > >> print unit-timer > ?object? > > There is no implicit init code for a Rebol object. >
I'm afraid I don't understand the phrase "init code" in that last sentence. It is certainly possible to have initialization code that is evaluated at the time an object is created, but I don't get the impression that this is what you're talking about.
> 02 -- Help Unit-timer in the original returns an "overview" > plus help for each refinement. If Unit-timer were an object, > there'd be no obvious place for the overview. And I don't know > any easy way of getting help for a function embedded in an object -- > > >> help watchmaker/start > watchmaker/start is a path >
The gimmick I showed in my previous email was certainly a kludge. I'm glad Brett pulled out the link to DocKimbel's enhanced HELP (thanks, Brett!). I'd also toyed with the idea of simply having a HELP method defined within an object (actually, it could even just be a string!) that provides an overview of the object's entire protocol.
> (This seems an obvious design oversight that RT could fix one day). >
Could be. They've certainly accepted such suggestions in the past.
> Objects of course don't just give more room to breathe, they open > an opportunity to work in a quite different way. Your code is a > good example of this in that it assigns the functionality to user > variables. I'm not sure what this next example does to your > collection and report-all, but if I want a timer than lives on > between program runs, I can do it with your code: > > LongTime: watchmaker/new "long-life" > Longtime/start > ... > Longtime/stop > write %longtime.wat mold longtime > ...... > Longtime: do read %longtime.wat mold > longtime/start >
You could actually save the WATCHMAKER instead of an individual WATCH. There's only one catch (in the version I posted yesterday) about restoring the WATCHMAKER from a file, as illustrated below.
>> total-time: watchmaker/new "Total" >> total-time/start
== 21:31:57.11
>> web-time: watchmaker/new "Web" >> web-time/start
== 21:32:15.4
>> write %persistentwatchmaker.r mold watchmaker
Time passes... I kept the same session to show that it really did work to reload the WATCHMAKER (almost).
>> laterwatchmaker: do load %persistentwatchmaker.r >> laterwatchmaker/collection: reduce laterwatchmaker/collection
== [ make object! [ label: "Total" total: 0 began: 21:31:57.11 ended: 0 reset: func [][...
>> laterwatchmaker/report-all
== ["Total" 401.18 "Web" 382.89]
>> watchmaker/report-all
== ["Total" 417.88 "Web" 399.59]
>> laterwatchmaker/report-all
== ["Total" 419.96 "Web" 401.67] I had to REDUCE the collection after reloading... YUCHK! An easy fix would be to add appropriately-named methods to the WATCHMAKER, perhaps /CHECKPOINT (and /RESTORE), that would save (and reinstate) the attributes from each WATCH in the collection into (and from) a given data file.
> (This would be more useful if the function worked across > midnights) > > One tiny question. You have a to-seconds function I just use > to-decimal. Any significant difference there? >
The answers to these (very good) points are that - I was lazy and in a hurry, and - I didn't know that TO-DECIMAL on a date! or time! would convert time-of-day to seconds-since-midnight. (Thanks for that!) The fix to both points is to revise WATCH as follows: watch: make object! [ label: "" total: began: ended: 0 reset: func [] [total: began: 0] start: func [] [began: now/precise] stop: func [/local ended] [ ended: now/precise if date? began [ total: ended - began * 86400 + total + to-decimal ended/time - began/time began: 0 total: total + to-seconds ended ] ] report: func [] [ if date? began [stop start] reduce [label total] ] ] Thanks for the suggestions! -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;