develooper Front page | perl.perl5.porters | Postings from August 2023

Re: PPC Elevator Pitch for Perl::Types

Thread Previous | Thread Next
From:
Oodler 577 via perl5-porters
Date:
August 19, 2023 02:56
Subject:
Re: PPC Elevator Pitch for Perl::Types
Message ID:
ZOAvTddLIdaJNaLH@odin.sdf-eu.org
> Re: PPC Elevator Pitch for Perl::Types
> From: Dave Mitchell
> Date: August 18, 2023 09:19
> Subject: Re: PPC Elevator Pitch for Perl::Types
> Message ID: ZN83kPGe3bEaC5O4@iabyn.com

Hi Dave, thank you for your reply. Please see our answer inline,
below.

> On Wed, Aug 16, 2023 at 04:37:07AM +0000, Oodler 577 via perl5-porters wrote:
> > # Proposed Perl Changes Elevator Pitch for Perl::Types
> [...]
> > Fortunately, the Perl compiler already provides

> By "Perl compiler", do you mean RPerl?

Yes.

> > #!/usr/bin/perl
> > use Perl::Types;
> > 
> > sub squared {
> >     { my number $RETURN_TYPE };
> >     ( my number $base ) = @ARG;
> >     return $base ** 2;
> > }
> > 

> That's weird perl syntax. What's @ARG and $RETURN_TYPE? Is this something
> RPerl related?

`@ARG` is just the alias for `@_`, provided by `English.pm`.

https://perldoc.perl.org/perlvar#@ARG

https://perldoc.perl.org/English

`$RETURN_TYPE` was the simplest pure-Perl syntax we could come up
with, which allows us to specify a subroutine's return type without
changing its behavior.  Can you please suggest possible pure-Perl
syntax alternatives for specifying a subroutine return type, without
requiring any changes to the existing Perl internals?

> In what circumstances are these type checks carried out / enforced? Is it
> just on scalar and list assignment? Or more generally? For example, does
> this croak?

>     sub mutate { $_[0] = 'foo' }
>     my number $x;
>     mutate($x);

The Perl compiler currently supports type enforcement for subroutine
calls, so that is our starting point for Perl::Types.  Thus, your
example above would not croak, because the subroutine does not
specify any data types for its input arguments.  Type checking is
simply disabled for subroutines without input argument types.

If you added `( my number $my_arg ) = @ARG;` to the top of your
`mutate()` subroutine, then yes it would croak with a complaint
`... number value expected but undefined/null value found ...`
because you never assigned a value to `$x`.  This is achieved by
inserting calls to the appropriate type-checking C macros or
functions for each typed input argument, inserted immediately
following the `@ARG` statement.  So for your `mutate()` subroutine,
Perl::Types would automatically call either the `number_CHECK()`
or `number_CHECKTRACE()` macro on the value received into `$my_arg`,
which is where the croaking occurs:

https://metacpan.org/release/WBRASWELL/RPerl-7.000000/source/lib/RPerl/DataType/Number.h#L137-149

```c
// [[[ TYPE-CHECKING MACROS ]]]
#define number_CHECK(possible_number) \
        (not(SvOK(possible_number)) ? \
                        croak("\nERROR ENV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but undefined/null value found,\ncroaking") : \
                        (not(SvNOKp(possible_number) || SvIOKp(possible_number)) ? \
                                        croak("\nERROR ENV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but non-number value found,\ncroaking") : \
                                        (void)0))
#define number_CHECKTRACE(possible_number, variable_name, subroutine_name) \
        (not(SvOK(possible_number)) ? \
                        croak("\nERROR ENV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but undefined/null value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name) : \
                        (not(SvNOKp(possible_number) || SvIOKp(possible_number)) ? \
                                        croak("\nERROR ENV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but non-number value found,\nin variable %s from subroutine %s,\ncroaking", variable_name, subroutine_name) : \
                                        (void)0))
```

> Speaking as a perl internals expert, can you explain to me in general
> terms how Perl::Types does its thing?

As you can see in the C macros above, we are exposing the real
native Perl data types by directly accessing the `SvOK()`, `SvIOKp()`,
and `SvNOKp()` internals.  Perl::Types is not inventing its own
definition of types, it is only exposing the already-existing real
native Perl data types such as `IV`, `NV`, `PV`, etc.  Real native
Perl data structures can likewise be exposed by way of the `AV`
and `HV` Perl data types, by directly accessing `SvAROKp()` and
`SvHROKp()`:

https://metacpan.org/release/WBRASWELL/RPerl-7.000000/source/lib/RPerl/DataStructure/Array/SubTypes1D.cpp#L72-118
https://metacpan.org/release/WBRASWELL/RPerl-7.000000/source/lib/RPerl/DataStructure/Hash/SubTypes1D.cpp#L92-166

```c
boolean number_arrayref_CHECK(SV* possible_number_arrayref, const boolean no_croak)
{
    if ( not( SvOK(possible_number_arrayref) ) ) { CROAK_OR_RETURN(no_croak, "\nERROR ENVAVRV00, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_arrayref value expected but undefined/null value found,\ncroaking") }
    if ( not( SvAROKp(possible_number_arrayref) ) ) { CROAK_OR_RETURN(no_croak, "\nERROR ENVAVRV01, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber_arrayref value expected but non-arrayref value found,\ncroaking") }
 
    AV* possible_number_array;
    integer possible_number_array_length;
    integer i;
    SV** possible_number_array_element;
 
    possible_number_array = (AV*)SvRV(possible_number_arrayref);
    possible_number_array_length = av_len(possible_number_array) + 1;
 
    for (i = 0;  i < possible_number_array_length;  ++i)  // incrementing iteration
    {
        possible_number_array_element = av_fetch(possible_number_array, i, 0);
 
        if (not(SvOK(*possible_number_array_element))) { CROAK_OR_RETURN(no_croak, "\nERROR ENVAVRV02, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but undefined/null value found at index %"INTEGER",\ncroaking", i) }
        if (not(SvNOKp(*possible_number_array_element) || SvIOKp(*possible_number_array_element))) { CROAK_OR_RETURN(no_croak, "\nERROR ENVAVRV03, TYPE-CHECKING MISMATCH, CPPOPS_PERLTYPES & CPPOPS_CPPTYPES:\nnumber value expected but non-number value found at index %"INTEGER",\ncroaking", i) }
    }
 
    return 1;
}
```

(Please see the links above for `number_arrayref_CHECKTRACE()`,
etc.)

Type checking is currently controlled on a per-file basis using
the `TYPE_CHECKING` preprocessor directive:

https://metacpan.org/release/WBRASWELL/RPerl-7.000000/source/lib/RPerl/Test/TypeCheckingTrace/AllTypes.pm#L1-2

```perl
# [[[ PREPROCESSOR ]]]
# <<< TYPE_CHECKING: TRACE >>>
```

The `TYPE_CHECKING` directive can have a value of `OFF` for disabled,
`ON` to call the `foo_CHECK()` macros/functions, and `TRACE` to
call the `foo_CHECKTRACE()` macros/functions.  The only difference
between `ON` and `TRACE` is the inclusion of the offending subroutine
and variable names for easier debugging.

Does that help answer your initial questions?

> -- 
> Indomitable in retreat, invincible in advance, insufferable in victory
>     -- Churchill on Montgomery

On Behalf of the _Perl::Types Committee_,
Brett Estrade 

--
oodler@cpan.org
oodler577@sdf-eu.org
SDF-EU Public Access UNIX System - http://sdfeu.org
irc.perl.org #openmp #pdl #native

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About