Can't exactly follow what you mean by that, Stefano, but I've tried my
"poor man's" method:
PROCEDURE ForOptimize*(s: ARRAY OF CHAR);
VAR i, j, len: INTEGER;
t1, t2: LONGINT;
ch: CHAR;
BEGIN
t1 := Services.Ticks();
FOR i := 0 TO 0FFFFH DO
FOR j := 0 TO LEN(s$)-1 DO ch := s[j] END
END ;
t2 := Services.Ticks();
StdLog.IntForm(t2-t1,10,5,' ',FALSE); StdLog.Ln;
t1 := Services.Ticks();
FOR i := 0 TO 0FFFFH DO
len := LEN(s$)-1;
FOR j := 0 TO len DO ch := s[j] END
END ;
t2 := Services.Ticks();
StdLog.IntForm(t2-t1,10,5,' ',FALSE); StdLog.Ln;
END ForOptimize;
Calling this with a 75-character string yielded "31" for both loops.
I know this is unmathematical and inelegant, but it's good enough for me.
The reason I've asked this is, due to my C habits I've recently run into a
problem that took an inordinate amount of time to spot -- probably because
it just wasn't obvious to me. Oberon does away with Pascal-like array
indexing (i.e. defining array indeces to start and end in any number you
like, a feature which, although superficially nice, probably wasn't worth
the effort in light of what it bought) so arrays are 0-based by default.
It also adds a C-like feature to strings terminating them with a null
character used as a sentinel -- again, probably because it is easier to
deal with. But there's one thing that escaped me.
The gotcha I mentioned a while ago was this: when we (those used to using
C) iterate over a string in C using an index, we naturally code it as
this:
for (i = 0; i<strlen(s); i++) ... etc.
You can replace the "strlen" call with a precalculated value, that is not
important. The important thing is, the predicate for the loop's
continuation says "while the index is smaller than the length of the
string." When you do this with Oberon like so...
FOR i := 0 TO LEN(s$) DO ... etc.
..you forget that "TO" means the length of the string will be used as the
last index value which doesn't exist as part of the string but is used for
the sentinel null character. So you have to remember to do this:
FOR i := 0 TO LEN(s$)-1 DO ... etc.
You may say this is a non-issue, but it's one of those typical tiny things
that gets on your nerves since it is so hidden-in-plain-sight that it runs
you up the wall.
With C's "for," you define how you continue the loop, which can be (and
frequently is) used to define the termination condition based on an index.
But then, with pointers, C is internally tuned to the null character so you
can write the above loop as:
for (; *s; s++){ ... } etc.
-or- with a while loop as...
while (*s) {
... etc.
s++;
}
..and you don't have to remember to refer to the length of the string and
subtract one from it not to go off the end. C will do it for you, and
terminate the loop by using that null character. This was what confused
me. (i.e. My mind is used to treating the sentinel as a convenient way to
avoid having to calculate a length value.)
Maybe with a while loop I wouldn't fall into this trap, such as:
i := 0;
WHILE i < LEN(s$) DO
...
INC(i)
END ;
..but not only does this require remembering to put that incrementation
at the bottom, in either case you feel the length is being recalculated so
you're tempted to create a "len" variable and calculate it beforehand. But
then, the little detail to remember is reversed in the loops:
len := LEN(s$)-1; (*exclude the last character from the
length*)
FOR i := 0 TO len DO... (*now you can include it in the loop index*)
i := 0;
WHILE i <= len DO... (*here, however, we have to say "<=" in the
predicate*)
Anyway, for those of you who are Oberon experts, these mundane things must
be well beneath your daily concern. I posted this following Chris's advice
so that other newbies can avoid this kinda frustration.
-- Ken
--
Message posted using http://www.talkaboutprogramming.com/group/comp.lang.oberon/
More information at http://www.talkaboutprogramming.com/faq.html