The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

RPerl Quick-Start Checklist & Guide

Restricted Perl, The Optimizing Perl 5 Compiler

DESCRIPTION

RPerl is a compiler. For general info:

https://github.com/wbraswell/rperl/blob/master/README.md

http://rperl.org

SYNOPSIS, PERL PROGRAM, INPUT CODE

Filename my_program.pl:

#!/usr/bin/env perl

# My Program Name
# My Program Description

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

# [[[ HEADER ]]]
use RPerl;
use strict;
use warnings;
our $VERSION = 0.001_000;

# [[[ CRITICS ]]]
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls)  # USER DEFAULT 1: allow numeric values & print operator
## no critic qw(RequireInterpolationOfMetachars)  # USER DEFAULT 2: allow single-quoted control characters & sigils
## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers)  # USER DEFAULT 3: allow constants

# [[[ INCLUDES ]]]
use My::FooPackage qw(foo_exported_ok);
use My::BarClass;

# [[[ CONSTANTS ]]]
use constant PI  => my number $TYPED_PI  = 3.141_59;
use constant PIE => my string $TYPED_PIE = 'pecan';

# [[[ SUBROUTINES ]]]
sub pies_are_round {
    { my void $RETURN_TYPE };
    print 'in pies_are_round(), having PIE() = ', PIE(), "\n";
    return;
}

sub pi_r_squared {
    { my number $RETURN_TYPE };
    ( my number $r ) = @ARG;
    my number $area = PI() * $r ** 2;
    print 'in pi_r_squared(), have $area = PI() * $r ** 2 = ', $area, "\n";
    return $area;
}

# [[[ OPERATIONS ]]]
pies_are_round();
my number $area = pi_r_squared(23.456_789);

foo_exported_ok(42);
print My::PackageFoo::foo_not_exported(3), "\n";

my My::BarClass $bar_object = My::BarClass->new(bar_number => 21.12, bar_string => 'howdy');
$bar_object->bar_method1(3);
my number $bar_method2_retval = $bar_object->bar_method2(5);

SYNOPSIS, PERL PROGRAM, COMPILE & EXECUTE

$ rperl -V my_program.pl
$ ./my_program

SYNOPSIS, PERL MODULES, INPUT CODE

Filename My/FooPackage.pm:

# [[[ HEADER ]]]
use RPerl;
package My::FooPackage;
use strict;
use warnings;
our $VERSION = 0.001_000;

# [[[ EXPORTS ]]]
use RPerl::Exporter qw(import);
our @EXPORT_OK = qw(foo_exported_ok);

# [[[ CRITICS ]]]
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls)  # USER DEFAULT 1: allow numeric values & print operator
## no critic qw(RequireInterpolationOfMetachars)  # USER DEFAULT 2: allow single-quoted control characters & sigils
## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers)  # USER DEFAULT 3: allow constants

# [[[ INCLUDES ]]]
use My::OtherPackage;  # implementation left as an exercise for the user
use My::OtherClass;    # ditto

# [[[ CONSTANTS ]]]
use constant FOO_CONSTANT => my string $TYPED_FOO_CONSTANT = 'foo constant data';

# [[[ SUBROUTINES ]]]

sub foo_exported_ok {
    { my void $RETURN_TYPE };
    ( my integer $arg ) = @ARG;
    print 'in My::FooPackage::foo_exported_ok(), received $arg = ', $arg, "\n";
    return;
}

sub foo_not_exported {
    { my string $RETURN_TYPE };
    ( my integer $arg ) = @ARG;
    print 'in My::FooPackage::foo_exported_ok(), received $arg = ', $arg, "\n";
    return('howdy' x $arg);
}

1;    # end of class

Filename My/BarClass.pm:

# [[[ HEADER ]]]
use RPerl;
package My::BarClass;
use strict;
use warnings;
our $VERSION = 0.001_000;

# [[[ OO INHERITANCE ]]]
# RPerl base class, no inheritance; replace with parent class as needed
use parent qw(RPerl::CompileUnit::Module::Class);
use RPerl::CompileUnit::Module::Class;

# [[[ CRITICS ]]]
## no critic qw(ProhibitUselessNoCritic ProhibitMagicNumbers RequireCheckedSyscalls)  # USER DEFAULT 1: allow numeric values & print operator
## no critic qw(RequireInterpolationOfMetachars)  # USER DEFAULT 2: allow single-quoted control characters & sigils
## no critic qw(ProhibitConstantPragma ProhibitMagicNumbers)  # USER DEFAULT 3: allow constants

# [[[ INCLUDES ]]]
use My::OtherPackage;  # implementation left as an exercise for the user
use My::OtherClass;    # ditto

# [[[ CONSTANTS ]]]
use constant BAR_CONSTANT => my string $TYPED_BAR_CONSTANT = 'bar constant data';

# [[[ OO PROPERTIES ]]]
our hashref $properties = {
    bar_number => my integer $TYPED_bar_number = 42.23,
    bar_string => my string $TYPED_bar_string  = 'default bar string data'
};

# [[[ SUBROUTINES & OO METHODS ]]]

sub bar_method1 {
    { my void::method $RETURN_TYPE };
    ( my My::BarClass $self, my integer $arg ) = @ARG;
    print 'in My::BarClass->bar_method1(), received $arg = ', $arg, "\n";
    print ($self->{bar_string} x $arg);
}

sub bar_method2 {
    { my number::method $RETURN_TYPE };
    ( my My::BarClass $self, my integer $arg ) = @ARG;
    print 'in My::BarClass->bar_method2(), received $arg = ', $arg, "\n";
    return($self->{bar_number} * $arg);
}

1;    # end of class

SYNOPSIS, PERL MODULES, COMPILE & TEST LOAD

$ rperl -V My/FooPackage.pm My/BarClass.pm
$  perl -e 'use My::FooPackage; use My::BarClass;'

QUICK-START CHECKLIST

  • 1. File Formats, Programs & Modules: Follow Exact Syntax & Order In Synopsis Code Examples Above

  • 2. Data Types, Constants & Variables & OO Properties: Always use constant PI => my number $TYPED_PI = 3.141_59; or my integer $foo; or our hashref $properties = { foo => my integer $TYPED_foo = 23, ...}; ; Never use constant PI => 3.141_59; or my $foo; or our $properties = { foo => 23, ...};

  • 3. Return Types, Subroutines & OO Methods: Always sub foo {{ my integer $RETURN_TYPE }; ...} ; Never sub foo ($) {...} etc.

  • 4. Argument Types, Subroutines & OO Methods: Always ( my integer $arg1, my string $arg2, ... ) = @ARG; ; Never my $arg1 = shift; my $arg2 = shift;

  • 5. Data Structures By Reference: Always my integer_arrayref $ar = [...]; & my integer_hashref $hr = {...}; ; Never my @a = (...); or my %h = (...);

  • 6. Lexical Variables: Always my integer $foo ; Never our $foo or state $foo etc.

  • 7. No Punctuation Variables: Never Use $_ or @_ or $! etc.

  • 8. Perl Critic: Always perlcritic --brutal my_program.pl or perlcritic --brutal MyModule.pm, Except For Specified & Allowed ## no critic Commands

  • 9. No External Dependencies: Always Write Your Own Code & Only Load CPAN Modules From Non-Compiled Code; Never Directly Load Non-Compilable Code or CPAN Modules etc.

  • 10. Pure Perl: Always Low-Magic Perl 5, Never XS or Non-Perl Code

QUICK-START GUIDE

RPerl currently supports a restricted subset of the Perl 5 programming language.

This Quick-Start Guide is meant to serve as a primer or companion for the much more in-depth textbook Learning RPerl.

Here are the most important things a Perl programmer needs to know to get started using RPerl immediately.

1. File Formats

All RPerl program and module files must follow specific file formats, as shown in the Synopsis code examples.

"SYNOPSIS, PERL PROGRAM, INPUT CODE"

"SYNOPSIS, PERL MODULES, INPUT CODE"

The first line of Perl code in any RPerl file must be use RPerl;, after which the files must be organized into the proper format for 1 of 3 file types:

1. Perl Program, .pl File Name Suffix, Ex. foo.pl
2. Perl Module Package, .pm File Name Suffix, Ex. Foo.pm
3. Perl Module Class, .pm File Name Suffix, Ex. Foo.pm

You can see above that both packages and classes must use the *.pm file name suffix; they are compiled differently based on the presence a class' OO inheritance use parent qw(...); and OO properties our hashref $properties = {...};.

If the OO inheritance and properties are not found, a *.pm file name is assumed to be a package and not a class.

The official RPerl file format templates are here:

Program Template

Package Template

Class Template

2. Data Types & Data Structures

All RPerl constants, variables, subroutine & object method return values, and object properties must have an explicitly-specified scalar data type or non-scalar data structure.

2a. Scalar Data Types

"CHAPTER 2: SCALAR VALUES & VARIABLES (NUMBERS & TEXT)" in RPerl::Learning

RPerl provides 7 scalar data types:

  • boolean

  • unsigned_integer

  • integer (core)

  • gmp_integer

  • number (core)

  • character

  • string (core)

Of the 7 RPerl scalar data types, 3 are directly (natively) supported by the Perl 5 core: integer, number, and string. This means the Perl 5 core is capable of directly identifying and storing those 3 core types. The remaining 4 non-core types are indirectly supported by the Perl 5 interpreter: boolean and unsigned_integer can be stored within either an integer or number; character can be stored within a string; and gmp_integer is supported by the use bigint; wrapper around the Math::BigInt::GMP module.

2b. Array Data Structures

"CHAPTER 3: ARRAY VALUES & VARIABLES" in RPerl::Learning

For arrays with more than just a few elements, it may be impractical or impossible to pass by value, because a full copy of each array element must be made in the process, which may fill up all your program's available memory or take a prohibitively long time to complete. Also, Perl allows us to provide explicit data types only when an array is stored by reference, so we can not provide a data type for an array stored by value. Because of these reasons, all RPerl arrays are stored by reference, and are declared with an explicit RPerl data type ending with _arrayref.

my                  @foo_by_value           = (2, 4, 6);  # fine in normal Perl, error in RPerl
my                  $foo_by_reference       = [2, 4, 6];  # fine in normal Perl, error in RPerl
my integer_arrayref $foo_by_reference_typed = [2, 4, 6];  # fine in normal Perl, fine  in RPerl

In a few special cases, Perl forces us to provide an array by value instead of by reference, in which case we need to "dereference" our array variable, which is the process of converting from the stored-by-reference memory address to the stored-by-data values. This is achieved by use of Perl's closefix array dereference syntax, comprised of enclosing the scalar array variable within at-sign-curly-braces @{ }. Because all arrays in RPerl are stored by reference, only necessary uses of the dereference syntax are supported by the RPerl compiler. (Please see "Section 3.8: push & pop Operators" in RPerl::Learning for more information on pop.)

my integer_arrayref $foo_by_reference_typed = [10, 20, 30];                    # fine in normal Perl, fine  in RPerl
my integer          $foo_last_element       = pop @{$foo_by_reference_typed};  # fine in normal Perl, fine  in RPerl,   necessary dereference 
my                  @foo_by_value           = @{$foo_by_reference_typed};      # fine in normal Perl, error in RPerl, unnecessary dereference

In normal Perl, a single array may contain elements with multiple different data types, such as a three-element array containing one string and one integer and one floating-point number. In RPerl, a single array must contain elements of all the same data type, so you can have a three-element array with all strings, but you can't store an integer inside an array of strings, and likewise you can't store a string inside an array of integers, etc.

my integer_arrayref $foo = [5, 10, 15];                 # fine
my  number_arrayref $bar = [5, 10, 15.5];               # fine
my  string_arrayref $bat = ['five', 'ten', 'fifteen'];  # fine

my integer_arrayref $foo = [5, 10, 15.5];               # error in RPerl, compiled modes
my  number_arrayref $bar = [5, 10, 'fifteen'];          # error in RPerl, compiled modes
my  string_arrayref $bat = ['five', 'ten', 15];         # error in RPerl, compiled modes

You can create an array with only one element, sometimes called a "singleton"; you can even create an empty array with zero elements:

my integer_arrayref $foo = [];    # zero elements, empty     array
my integer_arrayref $bar = [23];  # one  element,  singleton array

To display the contents of an array, you may utilize the *_arrayref_to_string() family of stringification subroutines:

my integer_arrayref $foo;
$foo = [23, 42, 2_112];
print '$foo = ', integer_arrayref_to_string($foo), "\n";

Running the code example above generates the following output:

$foo = [23, 42, 2_112]

RPerl currently supports the following array stringification subroutines, with support for all RPerl array data types coming soon:

  • integer_arrayref_to_string()

  • number_arrayref_to_string()

  • string_arrayref_to_string()

2c. Hash Data Structures

# NEED ADD CONTENT!

3. Return Types

# NEED ADD CONTENT!

4. Argument Types

# NEED ADD CONTENT!

5. Data Structures By Reference

# NEED ADD CONTENT!

6. Lexical Variables

# NEED ADD CONTENT!

7. No Punctuation Variables

# NEED ADD CONTENT!

8. Perl Critic

# NEED ADD CONTENT!

9. External Dependencies

# NEED ADD CONTENT!

10. Pure Perl

# NEED ADD CONTENT!

SEE ALSO

rperl

Learning RPerl e-Book, POD Format

Learning RPerl e-Book, Web Format

The Low-Magic Perl Commandments

AUTHOR

William N. Braswell, Jr.

mailto:wbraswell@NOSPAM.cpan.org