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

Re: [Scheme-reports] Comments on draft 6

John Cowan <cowan@x> wrote:
> Vitaly Magerya scripsit:
>> Hi, folks. I've read draft-6, and here are some comments (it's mostly
>> editorial things).
> Thanks so much for this close reading.  What follows reflects what I
> have already edited into draft 7.  I or my fellow editors will take up
> your other points when we can.

Thank you. I hope the rest won't get lost and forgotten over time.

>> Page 6, section 1.3.2: what's the significance of "newly allocated"
>> here? This is the first time such a phrase is used in the report;
>> maybe a reference to another section that clarifies what it means and
>> why is it important will help? Index has no references to "newly" or
>> "allocation".
> Changed to "need not be distinct from objects previously used for the
> same purpose."

There are multiple instances of "newly allocated" phrase in the
report. Do you intend to change them all? (For the record I do not
object the phrase itself, it is concise and clear, once you know
what it means, I only wish it to be explained. This is a minor
point in any case).

>> Page 18, section 4.2.5: how does the use of "lazy" in the example
>> ensures that heap is not exhausted? This is the only example of it's
>> usage and it's not clear what it does here, or why is it generally
>> needed (it's definition on page 17 does not clarify either).
> Added clause "because {\cf force} will in effect force such sequences
> iteratively."

I don't think this describes the need to lazy clearly enough. Well,
at least I don't get it...

Here's how I understand the issue (correct me if I'm wrong). Suppose
we have a promise P. Let's define A as (delay (force P)), and B as
(lazy P). These are the steps that will be taken if we'll force A:
* P is forced
* A is updated with the resulting value
* the same value is returned as the result

If we'll force B, this will happen:
* B is made to reference P (updates to P will update B)
* P is forced
* the result of that is returned

The difference being that (force B) tail-calls (force P), while
(force A) does not, hence the difference in space consumption.

I'd like to see this mechanics explained in the report somehow (not
using my words from the above though).

Maybe something along these lines could be added to lazy description
on page 17: "(lazy <expression>) is conceptually similar to (delay
(force <expression>)), with the difference that forcing the result
of lazy will in effect result in tail call to (force <expression>),
while forcing the result of (delay (force ...)) will not. Thus
iterative lazy algorithms that may result in a long series of (delay
(force ...)) chains can be rewritten using lazy to prevent consuming
unbounded space during evaluation".

Also maybe the examples of an infinite loop running in bounded
  (define (loop) (lazy (loop)))

... and in unbounded space:
  (define (loop) (delay (force (loop))))

... can be added as short demonstrations.

>> Page 25, section 5.4: define-record-type is said to bind <name> to "a
>> representation of record type", but there does not seem to be anything
>> else you might do with it (correct?). What is the rationale for
>> introducing this binding? Does this mean I can't name the constructor
>> the same as the record type?
> It is bound to provide extensibility to the large language, which will
> include more complex kinds of records.  You cannot name the constructor
> the same as the record type.

I see. Maybe a similar note should be added somewhere? Something
like "representation of record type bound to <name> is not utilized
in this report, but it serves as means to identify the record type
by further language extensions".

>> Page 32, section 6.2.4: "negative zero is an inexact value written
>> -0.0, which is distinct (in the sense of eqv?) from 0.0" and "however
>> numerical comparisons treat negative zero as equal to zero" -- but
>> eqv? on number is defined as numerical comparison (page 29, section
>> 6.1), so are they equal or not?
> They are equal in the sense of =, but distinct in the sense of eqv?.

So is section 6.1, page 29 wrong to say that eqv? on numbers is the
same as =?

>> Page 32, section 6.5.2: what is the rationale for short, single,
>> double and long inexact numbers? Are there implementations that
>> distinguish those?
> There are, notably Racket.  The rationale is that actual hardware and
> low-level software implement these things.

I see. (For the record, Racket uses "s" and "f" suffixes for 32-bit
floats, everything else is 64-bit floats).

>> Page 56, section 6.13.4: what is the rationale of current-second
>> function, what are it's intended uses?
> I'm somewhat at a loss here.  Most languages provide some variant of
> this functionality, but I can't find any specific rationales for it.

Fair enough, and that question was less editorial than the others,
so let me clarify. Specifying TAI is an unusual decision, and it
seems to me that either using Unix time or not providing this
function at all will be better, but I can only claim so if we agree
on goals of introduction of this function.

There are multiple things I would use current-second for. In the
absence of proper date library I may try to derive wall clock time
from current-second. Unfortunately to do this using TAI you'd need
a constantly updating leap second table, and this is impractical.

I may also use current-second to measure time intervals (as people
often do with Unix time functions available in many languages), but
this is conceptually wrong, because current-second is not monotonic
by design: it jumps when user adjusts clock (whether is is TAI or
Unix time). Besides, if we have current-jiffy, that is what should
be used to measure time intervals.

Finally, I may use current-second for timestamping things (e.g. to
name archived log files). This is one place where TAI is actually
a good choice (better than Unix time, which leaps backward at times),
but I would prefer to use a proper date library to make timestamps

Then there's an issue of how to actually obtain TAI. Unix time is
readily available on any machine that knows current date (they are
trivially related), but you can only derive TAI from Unix time with
a (constantly updating) leap second table, which is not a part of
any system I know of. It does not help that NTP gives you Unix time
(plus leap second indicator), not TAI.

Given the problems with obtaining TAI and the ease of obtaining
Unix time, I would not be surprised if implementations would define
current-second as current-unix-time + 34, which is basically a bug
(you'll need to change that to 35 at the end of this June).

So, in short: I'd like to know the intended uses for current-second
to figure out if TAI is a sensible choice. For uses I can think of,
a proper date library and a monotonic timer must be used instead.

(I'm aware that you folks are familiar with these issues, I'm only
documenting my current understanding here).

>> Page 56, section 6.13.4: what is the rationale for having
>> current-jiffy and jiffies-per-second functions? Why doesn't
>> current-jiffy return seconds directly?
> I've adopted an edited version of the CLtL2 rationale:
>     The reason for allowing jiffies to be implementation-dependent is
>     so that {\cf current-jiffy} can execute with minimum overhead. The
>     idea is that it should be very likely that a compactly represented
>     integer will suffice as the returned value.  Any particular jiffy
>     size will be inappropriate for some implementations: a microsecond
>     is too long for a very fast machine, while a much smaller unit
>     would force many implementations to return integers which must be
>     allocated for most calls, rendering {\cf current-jiffy} less useful
>     for accurate timing measurements.

I see. Is this an important optimization? Are there implementations
that have similar functionality (i.e. fixnum-based monotonic timer)?
I would have guessed that most just provide an inexact number of
seconds, and not bother to save a memory allocation on this operation.

Scheme-reports mailing list