Re: Comparing Pika-syle and JNI-style Tom Lord 14 Jan 2004 21:41 UTC


    > From: Jim Blandy <xxxxxx@redhat.com>

    > It's worth noting here that SCM_LSET is essentially a 'linearizing'
    > assignment operator.  I'd been thinking of providing a similar
    > operator for Minor:
    > [nice example]

So we're another step closer to saying that these two interfaces are
just duals of each other (modulo error handling foo and topics we
haven't gotten to yet like tail calls and continuation foo).

But they aren't _quite_ duals.  JNI/Minor-style still has this
mandatory separate allocation of handles and liveness of unfreed
handles until returning from C to Scheme (at least in implementations
not storing scheme values in `mn_ref *' variables and using
conservative GC).   At the very least, JNI/Minor-style is tolerant of
code that is generally undesirable.

You're niftier example indirectly reveals the problem:

    >      mn_ref *
    >      assq (mn_call *c, mn_ref *key, mn_ref *alist)
    >      {
    >        mn_ref *pair = 0;
    >        mn_ref *pair_key = 0;
    >
    >        while (mn_pair_p (c, alist))
    >          {
    >            pair     = mn_set (c, pair,     mn_car (c, alist));
    >            pair_key = mn_set (c, pair_key, mn_car (c, pair));
    >
    >            if (mn_ref_eq (c, key, pair_key))
    >              return pair;
    >
    >            alist = mn_to_cdr (c, alist);
    >          }
    >
    >        return mn_false (c);
    >      }

Ok, but now:

	while (N--)
          {
             ... assq (...); ...
          }

is O(N) space.  I guess you need to put back the free calls just
before the returns -- right where GCUNPROs would go.

There's also that:

    >            pair     = mn_set (c, pair,     mn_car (c, alist));

needs to allocate and free an intermediate handle (for the return
value of mn_car, in implementations that don't store scheme values
directly in `mn_ref *' variables and use conservative GC techniques)
but the relative cost of those mandatory instructions in minor
compared to other things in Pika is something I'd find hard to guess
about.

    > I think this underscores how fundamentally similar the two are:
    > - Minor calls correspond to Pika frames.

Correspond to but aren't isomorphic because of their different
lifetimes.  That's the almost-but-not-quite-duals point.  You seem to
agree:

    > - Minor heap-allocates while Pika stack-allocates.

    > I think the biggest difference between the two is that Pika ties
    > reference lifetimes very tightly to lexical block lifetimes, whereas
    > Minor binds them to call lifetimes, but allows/requires you to do some
    > other explicit frees.  Each has some advantages and some
    > disadvantages.

I don't mean to be gratuitously argumentative.   I don't see any
advantage to the call-lifetime hack other than that it is slightly
more tolerant of sloppy code that we'd want to discourage anyway.
Your revised assq implementation is an example.

Just as a point of interest: I remember back in the early days of
Guile the syntax issues of C code were something we worried quite a
lot about.  Some of the discussions concluded, for example, that
conservative GC was imperative because we figured that anything else
would be too hard for "average C programmers" to use and it seemed
(incorrectly) at the time that conservative GC let us write Scheme
expressions in C in a very direct style without having to think about
it too hard.  Two things happened in the years following: (a) GC
became much more widely accepted (thank you, James Gosling) and so
what the "average C programmer" can be counted on for has expanded;
(b) it turns out that conservative GC is a sham in the sense that if
you use it without a deep understanding of permissable C optimizations
and eternal vigilance about what they might effect -- you're going to
lose by writing subtly incorrect code.  Scheme expressions aren't (in
a simple way) C expressions and that's all there is too it -- trying
to hide that fact in the manner of JNI doesn't help anyone (anymore).
I think there's an analogy between the interactions of conservative GC
and C optimizations on the one hand and on the other hand the
interactions between JNI/Minor-style conventions and semantics and
call lifetimes on the other.

-t