XS: sysread () look-alike?

Discussion in 'Perl Misc' started by Ivan Shmakov, Aug 1, 2013.

  1. Ivan Shmakov

    Ivan Shmakov Guest

    I'm implementing a sysread () look-alike in XS:

    my $result;
    my $status
    = $myio->myread ($start, $count, RESULT);

    I wonder whether it's sensible to pass a scalar for RESULT (IOW,
    $result), or should I use a reference instead (\$result)?

    The issue with passing a scalar is that it won't (AIUI) be all
    that easy to allow for "filter" or "guard" functions at the Perl
    side, e. g.:

    our $myio;
    sub read_from_0 {
    my $r
    = $myio->myread (0, @_);
    die (error_message ($r))
    unless ($r == 0);
    }

    my $result;
    read_from_0 ($count, $result);

    Somehow, it seems that @_[1] in read_from_0 () won't be the same
    scalar as the caller's $result. (While for \$result, it would
    still be a /reference/ to the same scalar.)

    Anything else I should consider?

    TIA.

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 1, 2013
    #1
    1. Advertising

  2. Ivan Shmakov <> writes:
    > I'm implementing a sysread () look-alike in XS:
    >
    > my $result;
    > my $status
    > = $myio->myread ($start, $count, RESULT);
    >
    > I wonder whether it's sensible to pass a scalar for RESULT (IOW,
    > $result), or should I use a reference instead (\$result)?


    I think you should work with the language you are using and not
    against it: Perl is the opposite of C in this respect and passes
    everything 'by reference'. Consequently, using scalars in the way
    sysread does is totally fine. A better idea might be to return a
    scalar with the contents or undef on error, possibly using an
    optionally passed scalar for a more detailed status code. Or setting
    $! to a sensible value. Or using the perlapi croak-routine for error
    reporting.
    Rainer Weikusat, Aug 1, 2013
    #2
    1. Advertising

  3. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Rainer Weikusat <> writes:

    [...]

    > A better idea might be to return a scalar with the contents or undef
    > on error, possibly using an optionally passed scalar for a more
    > detailed status code. Or setting $! to a sensible value. Or using
    > the perlapi croak-routine for error reporting.


    In this case, the library I'm writing interface for has a host
    of possible error codes, which do not map to errno.h codes, but
    which I nevertheless wish to preserve.

    I've thus decided that I'd closely follow the library's own
    interface of returning a non-zero status code upon failure, and
    also provide convenience Perl wrappers, which raise an exception
    if the status returned is non-zero. Consider, e. g.:

    package XXX::Qux 0.1;

    sub check_rv {
    my ($name, $code, $args) = @_;
    my $r
    = $code->(@$args);
    die (XXX::Exception->new ($r, $name))
    unless ($r == 0);
    ## .
    return;
    }

    ## assuming XS wrappers inhabit this very same namespace, which they
    ## probably shouldn't

    sub foo {
    ## .
    check_rv_ref (q"xxx_foo",
    \&xxx_foo, \@_);
    }

    Naturally, the XXX::Exception object has ->xxx_err_no () and
    ->xxx_err_string () methods (providing access to the library's
    own "errno" and "strerror" facilities), as well as the
    conventional ->error () method, which is also the object's
    "stringification" routine.

    The only case I deviate from this convention is the one when the
    function returns an (array) reference from the XS wrapper in the
    case of success, like:

    sub check_rv_ref {
    my ($name, $code, $args) = @_;
    my $r
    = $code->(@$args);
    die (XXX::Exception->new ($r, $name))
    unless (ref ($r));
    ## .
    $r;
    }

    sub bar_baz {
    ## .
    check_rv_ref (q"xxx_bar_baz",
    \&xxx_bar_baz, \@_);
    }

    This is the case when the xxx_bar () C function is to return
    several values, typically via the storage pointed by its
    arguments; as in:

    xxx_error xxx_bar_baz (xxx_obj, int foo, int *bar, int *baz);

    This corresponds to the following XS wrapper usage:

    my $r
    = $xxx_obj->xxx_bar_baz (42);
    die ()
    unless (ref ($r));
    my ($bar, $baz)
    = @$r;

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 1, 2013
    #3
  4. Ivan Shmakov

    Ivan Shmakov Guest

    autodie

    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:


    [...]

    >> I've thus decided that I'd closely follow the library's own
    >> interface of returning a non-zero status code upon failure, and also
    >> provide convenience Perl wrappers, which raise an exception if the
    >> status returned is non-zero. Consider, e. g.:


    > It might be more convenient to do this via autodie. See
    > autodie::hints.


    How do I get the library's function called (so to convert the
    error code returned into a meaningful message) when using
    autodie?

    >> Naturally, the XXX::Exception object has ->xxx_err_no () and
    >> ->xxx_err_string () methods (providing access to the library's own
    >> "errno" and "strerror" facilities), as well as the conventional
    >> ->error () method, which is also the object's "stringification"
    >> routine.


    --
    FSF associate member #7257
    Ivan Shmakov, Aug 1, 2013
    #4
  5. Ivan Shmakov

    Ivan Shmakov Guest

    Re: autodie

    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:
    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:


    >>>> I've thus decided that I'd closely follow the library's own
    >>>> interface of returning a non-zero status code upon failure, and also
    >>>> provide convenience Perl wrappers, which raise an exception if the
    >>>> status returned is non-zero. Consider, e. g.:


    >>> It might be more convenient to do this via autodie. See
    >>> autodie::hints.


    >> How do I get the library's function called (so to convert the error
    >> code returned into a meaningful message) when using autodie?


    [...]

    > Ideally, you would want to be able to subclass autodie::exception and
    > arrange to pick up the xxx-specific error information at creation
    > time. I'm not sure if it's possible to make autodie use your
    > subclass automatically, though. You might want to talk to Paul; when
    > I had suggestions in the past for improving the interface, he was
    > very willing to listen.


    ACK, thanks.

    > Alternatively, you could just forget the idea of providing a
    > return-value interface, and just always throw your own exceptions.
    > If you do that, I would recommend making them objects rather than
    > strings, because it makes it possible to reliably distinguish them
    > from other exceptions when they're caught;


    Unless I'm missing something, this is exactly what I do. The
    point is that I'm hesitant to either generate exception objects
    /or/ call Perl code from XS, so my XS ("low-level") interface
    returns error codes, which the Perl wrapper methods then turn
    into proper exceptions (which are indeed objects.)

    > if your exception class doesn't inherit from something like
    > Exception::Class, it needs to provide overloaded stringify,


    The latter is also done.

    > and it needs to record at least file and line from caller at the
    > point where it's thrown.


    I don't seem to understand this one. Any specific examples,
    please?

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 1, 2013
    #5
  6. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:


    >> I'm implementing a sysread () look-alike in XS:


    >> my $result; my $status = $myio->myread ($start, $count, RESULT);


    >> I wonder whether it's sensible to pass a scalar for RESULT (IOW,
    >> $result), or should I use a reference instead (\$result)?


    > I would pass a reference, because it makes it clearer that the
    > function modifies its argument.


    Yes.

    Yet, this seem to go against the convention already set by the
    Perl core...

    [...]

    >> read_from_0 ($count, $result);


    >> Somehow, it seems that @_[1] in read_from_0 () won't be the same
    >> scalar as the caller's $result.


    > It will be. Both $_[1] in read_from_0 and the-equivalent-of-$_[2] in
    > myread will be aliases to $result.


    ACK, thanks. Indeed, my case was more like:

    sub myread {
    ## .
    check_rv (q"lowlevel_myread",
    \&lowlevel_myread, \@_);
    }

    with check_rv () later doing $_[1]->(@{$_[2]}).

    Alas, in this latter case, it doesn't seem to work anymore.

    So, the question is: is there any way to allow for such a use,
    apart from resorting to use a reference (\$result)?

    >> (While for \$result, it would still be a /reference/ to the same
    >> scalar.)


    >> Anything else I should consider?


    > I would put the buffer argument first, to match IO::Handle->sysread.


    It makes sense, indeed, though in this case I'd rather duplicate
    the signature of the library's function I'm writing the
    interface for, so not to confuse those already familiar with the
    C one.

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 2, 2013
    #6
  7. Ivan Shmakov <> writes:
    >>>>>> Ben Morrow <> writes:
    >>>>>> Quoth Ivan Shmakov <>:

    >
    > >> I'm implementing a sysread () look-alike in XS:

    >
    > >> my $result; my $status = $myio->myread ($start, $count, RESULT);

    >
    > >> I wonder whether it's sensible to pass a scalar for RESULT (IOW,
    > >> $result), or should I use a reference instead (\$result)?

    >
    > > I would pass a reference, because it makes it clearer that the
    > > function modifies its argument.

    >
    > Yes.
    >
    > Yet, this seem to go against the convention already set by the
    > Perl core...


    The reason for this is that the people who wrote 'the Perl core'
    created a language which doesn't support passs-by-value. Because of
    this, it is not necessary to pass a special 'derived value' in order
    to have 'output arguments' and dealing with output arguments requires
    no 'special indirection syntax'.

    [...]

    > sub myread {
    > ## .
    > check_rv (q"lowlevel_myread",
    > \&lowlevel_myread, \@_);
    > }
    >
    > with check_rv () later doing $_[1]->(@{$_[2]}).
    >
    > Alas, in this latter case, it doesn't seem to work anymore.


    perl -e 'sub nice { $_[0] = 1723; }; sub try { nice(@{$_[0]}); } sub watson { try(\@_); }; watson($r); print $r'

    Given the way argument passing works in Perl (by putting pointers to
    SVs on the stack), it is - unfortunately - not possible to weasel
    around pass-by-reference with Perl code in this way: At some point,
    you have to make a copy of the argument in question in order to create
    a different scalar/ SV.

    [...]

    > > I would put the buffer argument first, to match IO::Handle->sysread.

    >
    > It makes sense, indeed, though in this case I'd rather duplicate
    > the signature of the library's function I'm writing the
    > interface for, so not to confuse those already familiar with the
    > C one.


    Chances are that your Perl code is encountered by Perl programmers ...
    Rainer Weikusat, Aug 2, 2013
    #7
  8. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Ivan Shmakov <> writes:
    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:


    [...]

    >>> read_from_0 ($count, $result);


    >>> Somehow, it seems that @_[1] in read_from_0 () won't be the same
    >>> scalar as the caller's $result.


    >> It will be. Both $_[1] in read_from_0 and the-equivalent-of-$_[2]
    >> in myread will be aliases to $result.


    > ACK, thanks. Indeed, my case was more like:


    > sub myread {
    > ## .
    > check_rv (q"lowlevel_myread",
    > \&lowlevel_myread, \@_);
    > }


    > with check_rv () later doing $_[1]->(@{$_[2]}).


    > Alas, in this latter case, it doesn't seem to work anymore.


    ... Apparently, I've essentially confused \@_ with [ @_ ], and
    the first one indeed works as expected.

    Sorry for the noise.

    [...]

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 2, 2013
    #8
  9. Ivan Shmakov <> writes:
    >>>>>> Ivan Shmakov <> writes:
    >>>>>> Ben Morrow <> writes:
    >>>>>> Quoth Ivan Shmakov <>:

    >
    > [...]
    >
    > >>> read_from_0 ($count, $result);

    >
    > >>> Somehow, it seems that @_[1] in read_from_0 () won't be the same
    > >>> scalar as the caller's $result.

    >
    > >> It will be. Both $_[1] in read_from_0 and the-equivalent-of-$_[2]
    > >> in myread will be aliases to $result.

    >
    > > ACK, thanks. Indeed, my case was more like:

    >
    > > sub myread {
    > > ## .
    > > check_rv (q"lowlevel_myread",
    > > \&lowlevel_myread, \@_);
    > > }

    >
    > > with check_rv () later doing $_[1]->(@{$_[2]}).

    >
    > > Alas, in this latter case, it doesn't seem to work anymore.

    >
    > ... Apparently, I've essentially confused \@_ with [ @_ ], and
    > the first one indeed works as expected.


    The second one also works as expected: You are copying the contents of
    @_, hence, you get a different set of scalars.
    Rainer Weikusat, Aug 2, 2013
    #9
  10. Ivan Shmakov

    Ivan Shmakov Guest

    >>>>> Rainer Weikusat <> writes:
    >>>>> Ivan Shmakov <> writes:


    [...]

    > dealing with output arguments requires no 'special indirection
    > syntax'.


    Which is what I consider a serious drawback of the language.
    (The same applies to Fortran and C++, though.)

    [...]

    >>> I would put the buffer argument first, to match
    >>> IO::Handle->sysread.


    >> It makes sense, indeed, though in this case I'd rather duplicate the
    >> signature of the library's function I'm writing the interface for,
    >> so not to confuse those already familiar with the C one.


    > Chances are that your Perl code is encountered by Perl programmers
    > ...


    Given the (planned) incompleteness of the interface (at least
    for the first N releases), I'd expect for its users to check
    with the interfaced library's own documentation from time to
    time. And having two different interfaces to stumble upon
    doesn't seem like some clever time-saving feature.

    That doesn't mean that there can't be a more "Perl-friendly"
    interface on top of it, though.

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 2, 2013
    #10
  11. Ivan Shmakov <> writes:
    >>>>>> Rainer Weikusat <> writes:
    >>>>>> Ivan Shmakov <> writes:

    >
    > [...]
    >
    > > dealing with output arguments requires no 'special indirection
    > > syntax'.

    >
    > Which is what I consider a serious drawback of the language.
    > (The same applies to Fortran and C++, though.)


    I agree with that although I'm unsure to which degree this is rather
    based on 'cultural prejudices' than on actual reasons.
    Rainer Weikusat, Aug 2, 2013
    #11
  12. Ivan Shmakov

    Ivan Shmakov Guest

    XS; and exception objects

    >>>>> Ben Morrow <> writes:
    >>>>> Quoth Ivan Shmakov <>:


    [...]

    >> Unless I'm missing something, this is exactly what I do. The point
    >> is that I'm hesitant to either generate exception objects /or/ call
    >> Perl code from XS, so my XS ("low-level") interface returns error
    >> codes, which the Perl wrapper methods then turn into proper
    >> exceptions (which are indeed objects.)


    > Ah, OK. I though you were trying to provide both return-value and
    > exception interfaces so users could choose which they wanted.


    FWIW, I'm going to document both, but I don't expect for the
    users to actually use the return-value interface. (Other than
    in the cases the respective Perl wrapper methods are found to be
    faulty or otherwise flawed.)

    > Throwing exceptions from XS is fairly straightforward; you build your
    > object (however you like) and call Perl_croak_sv. However it would
    > probably be easier to have a My::Exception->throw method, which
    > builds and throws an exception; this means you just need to make a
    > method call, which goes like this:


    ... Which is exactly what I'm trying to avoid. Debugging XS
    code isn't all that easy to me, and I'm pretty sure that having
    to debug XS code paths intertwined with Perl's won't be of any
    help to me. Or to any inexperienced Perl user who may happen to
    have to debug my code, for that matter.

    [...]

    > and an exception of this class reaches the top-level 'print a message
    > and kill the program' exception handler, that message will not
    > include the 'at file ... line ...' information. Adding that
    > information is something die does if you pass it a string; if you
    > pass it an object, it has nowhere to put the information.


    > This means that your 'new' method needs to record that information,
    > somehow, so it can include it in the stringification.


    ACK, thanks for the information.

    For now, I'm effectively "substituting" die () with croak (),
    like:

    package main;
    require Carp;
    $SIG{"__DIE__"}
    = \&Carp::confess;

    for the "at file" error messages weren't so far nearly as
    helpful as complete stack traces, and my guess is that it also
    solves the issue at hand. Thus, I'm going to postpone this one
    until some later time.

    > You can pull it out of 'caller', though that means working out how
    > many stack frames to go back to get to the 'real' location of the
    > error.


    Yes, and it seems that there is indeed some choice.

    > You can also use Carp::shortmess, which gives you the message 'croak'
    > would have given you.


    It doesn't seem documented, does it?

    --
    FSF associate member #7257
    Ivan Shmakov, Aug 4, 2013
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Timo Nentwig

    J2ME: MemoryImageSource alike?

    Timo Nentwig, Mar 4, 2005, in forum: Java
    Replies:
    17
    Views:
    1,402
    Darryl Pierce
    Mar 22, 2005
  2. Replies:
    2
    Views:
    418
    Jesper Nordenberg
    Jun 2, 2005
  3. tom_usenet

    static constructor alike?

    tom_usenet, Sep 11, 2003, in forum: C++
    Replies:
    2
    Views:
    386
    Jesper Madsen
    Sep 11, 2003
  4. Paddy
    Replies:
    2
    Views:
    324
    Paddy
    Mar 14, 2006
  5. mathieu
    Replies:
    2
    Views:
    263
    mathieu
    Aug 29, 2007
Loading...

Share This Page