Nick:
> PUSHMARK;
> XPUSHs(sv_2mortal(newSVpv('DeepThought'));
> XPUSHs(sv_2mortal(newSViv(42));
> PUTBACK;
> count = perl_call_method("Consider",G_EVAL);
> SPAGAIN;
> if (count >= 1) {
>   answer = SvIV(POPs));
> }
>
>You _want_ to keep that???

Tim:
> There may be scope for having two levels of API. One high level clean
> simple etc and the other a lower-level more performance oriented API.
> The former could be implemented in terms of the latter.

Indeed.  XS is hard, fast, dirty and ugly (in a sickly, beautiful
kinda way), but there's nothing to stop you from wrapping it all up
into a less efficent, but prettier API (with the possible exception
of reference counting).

Here's a trivial example of something I was just hacking on to make
life easier for myself in a current XS project.  In this case, I don't
care about making lots of function calls, doing a few unnecessary
conversions, or a bit of back-tracking because it all works out a
lot faster than the Perl code it's being written to replace.  But we
probably don't want to implement Perl opcodes this way.


/*------------------------------------------------------------------------
 * my_perl_call_coderef(SV *code, AV *args)
 *
 * Pushes any arguments in 'args' onto the stack then calls the code ref
 * in 'code'.  Calls my_fold_results() to massage the return value(s).
 *------------------------------------------------------------------------*/

SV *
my_perl_call_coderef(SV *code, AV *args)
{
    dSP;
    SV **svp;
    I32 count = (args && args != Nullav) ? av_len(args) : 0;
    I32 i;

    PUSHMARK(SP);
    for (i = 0; i <= count; i++) {
        if ((svp = av_fetch(args, i, 0)) != NULL) {
            XPUSHs(*svp);
        }
    }
    PUTBACK;
    count = perl_call_sv(code, G_ARRAY);
    SPAGAIN;

    return my_fold_results(count);
}

The biggest current problem with XS (from my perspective) is that reference
counting increases the complexity by Way Too Much.  Take a simple hash
store (off the top of my head)

    if ((svp = hv_store(hash, key, keylen, SvREFCNT_inc(val), 0)) == NULL) {
        SvREFCNT_dec(val);
        ...
    }

Contrasted to the equivalent in Ruby:

    if (rb_hash_aset(hash, key, value) == Qnil) {
        ...
    }

One of the nice things about the Ruby API is that there is an (almost)
1:1 mapping between what you can do in the Ruby language and what you
can do in the Ruby API.  And just for completeness, here's how
'rb_hash_aset' is bound into the hash vtable as the 'store' method:

    rb_define_method(rb_cHash, "store", rb_hash_aset, 2);

The clarity of the API makes it fairly painless to take a Ruby module
and re-write it in C for speed and efficiency.  Even if they're not
getting the raw, low-level performance of XS, they're getting bigger
wins than running interpreted code.  I expect the percentage of Perl
hackers prepared to recode Perl in XS for performance is rather small.

I've always thought that many, if not most, if not all, of the core
Perl modules should be written in XS/C, so that people can happily
use them without worrying about the overhead of loading N thousand lines
of Perl code.  The IO and CGI modules come immediately to mind, but there
are many.  At present, this would be something of a challenge.


A




-- 
Andy Wardley <[EMAIL PROTECTED]>   Signature regenerating.  Please remain seated.
     <[EMAIL PROTECTED]>   For a good time: http://www.kfs.org/~abw/

Reply via email to