Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6

by u65 (Chaplain)
on Aug 06, 2015 at 00:56 UTC ( [id://1137601]=perlmeditation: print w/replies, xml ) Need Help??

I have posted a draft tutorial in my scratchpad here below (per Arunbear's suggestion) and am looking for constructive criticism. Thanks.

UPDATE 1: Added three subheadings including an informal list of Perl 6's desirable features.

UPDATE 2: Added link to rosettacode in the "Some Longer Comments" section below.

UPDATE 3: After some rework (perltidy, perlcritic) in the Perl 5 code, modified the Perl 6 code accordingly, then made additional improvements to the Perl 6 code to be more Perl6ish.

=== BEGIN TUTORIAL ===

Introduction

Perl 6 is almost upon us, and it promises to cure many of the shortcomings of Perl 5. For all the official information, check out its web site at <http://perl6.org>. I use the instructions here <http://rakudo.org/how-to-get-rakudo/> for a Linux source installation with the rakudobrew script.

I asked for users opinions of Perl 6's "killer" features on the Perl 6 users list and following are some of the responses:

  • variables must be declared
  • strong typing available
  • built-in command line processing
  • built-in multiple dispatch
  • the where clause
  • built-in sets and bags
  • built-in pick and roll
  • built-in better arithmetic (Rat number type)
  • improved regex
  • no parens required for if statements
  • built-in facilities for the language to parse, transform and extend itself (std grammar, macros)
  • awesome error messages
  • hyphens allowed in names
  • grammars
  • easy interface with C
  • named subroutine arguments
  • better classes and namespaces
  • built-in object methods
  • see rosettacode for good examples

Some longer comments:

  • Just make them look at Perl6 source code, e.g., on rosettacode. Someone who doesn't see how wonderful Perl6 is, is a lost soul anyway.
  • Less cumbersome to write and easier to read.
  • Grammars: Perl 6 is most attractive to me as a framework development tool. It lets you be really creative in how you let users describe their problem to your framework, whether that be webserver, parser, etc.
  • One thing that was not mentioned already is using Rat instead of standard floating point number. It prevents many silly mistakes, especially when counting money.

Purpose

This tutorial aims to show how my typical modest Perl 5 scripts translate into Perl 6. As the current Perl 6 documentation is not yet complete, my beginning Perl 6 efforts have resulted in putting together a simple model for a typical task for me. It was completed somewhat by trial and error along with much help from the Perl 6 mailing list.

The Code

A typical script of mine does something like the following:

  • Provides a simple usage statement when executed without any arguments.
  • Provides detailed help when the '--help' or '-h' or '?' options are provided.
  • Opens and parses some kind of data file (often in a special key-value format).
  • Takes some kind of action with the input data.
  • Writes data to STDOUT or a specific file.
  • Provides a friendly results message upon successful completion.

The following table is a side-by-side comparison of the two example programs (both of which work for me; please report any errors you may find). There are some comments to indicate differences in Perl 5 versus Perl 6, but many are not documented explicitly. In many cases of my Perl 6 usage, as in Perl 5, TIMTOWTDI, so I'm sure both programs can be improved.

Below the programs is the input data file used by each program. Run each program like this to compare results (assuming you have done chmod +x filename for each file):

$ ./tutorial-p5.pl -g -d >& p5.txt $ ./tutorial-p6.pl -g -d .& p6.txt
Perl 5Perl 6
#!/usr/bin/env perl # file: tutorial-p5.pl # PRELIMS ======================== use v5.10; # features 'say' and 'state' use strict; use warnings; use File::Basename; # p6: no such module yet use Data::Dumper; my $default_infile = 'tutorial-data.txt'; my $prog = basename $0; my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage .= ' | --help | ? [--debug[=N]]'; # ARG/OPTION HANDLING ======================== if (!@ARGV) { say $usage . "\n"; exit; } foreach my $arg (@ARGV) { my $oarg = $arg; # save original for error handling my $val = undef; my $idx = index $arg, q{=}; if ($idx >= 0) { $val = substr $arg, $idx+1; $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if (! -e $infile); my %user; my @keywords = qw(last first job); my %keywords; @keywords{@keywords} = (); parse_data_file($infile, \%user, $debug); if ($debug) { say 'DEBUG: Dumping user hash after loading:'; print Dumper(\%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file { my $fname = shift @_; my $href = shift @_; my $debug = shift @_ || 0; say "Parsing input file '$fname'..."; open my $fp, '<', $fname or die "$fname: $!"; my $uid = undef; my $linenum = 0; while (defined(my $line = <$fp>)) { ++$linenum; my $err = 0; # remove comments my $idx = index $line, q{#}; if ($idx >= 0) { $line = substr $line, 0, $idx; } # skip blank lines next if $line !~ /\S/xms; # every valid line must have a colon (':') # following a key word $idx = index $line, q{:}; if ($idx >= 0) { # ensure the key is lower case my $k = lc substr $line, 0, $idx; # trim ws on both ends $k =~ s{\A \s* | \s* \z}{}gxms; my $val = substr $line, $idx+1; # also needs trimming $val =~ s{\A \s* | \s* \z}{}gxms; # User attributes if ($k eq 'user') { $uid = $val; die 'FATAL: $uid not defined.' if !defined $uid; if ($uid =~ /\D/xms) { say 'ERROR: User ID not an integer.'; ++$err; } elsif ($uid <= 0) { say 'ERROR: User ID not an integer > 0.'; ++$err; } elsif (exists $href->{$uid}) { say 'ERROR: User ID is not unique.'; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if (!defined $uid) { say 'ERROR: User ID is not defined for this user.'; ++$err; } elsif ($k eq 'hobbies') { $href->{$uid}{hobbies} = []; my @h = split q{,}, $val; foreach my $h (@h) { # trim ws on both ends $h =~ s{\A \s* | \s* \z}{}gxms; push @{$href->{$uid}{hobbies}}, $h; } } elsif (exists $keywords{$k}) { $href->{$uid}{$k} = $val; } else { chomp $line; say 'ERROR: Unknown line format:'; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format.'; ++$err; } if ($debug) { chomp $line; say STDERR "DEBUG: line = '$line'"; } if ($err) { chomp $line; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { say <<"HERE"; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help # EOF ========================
#!/usr/bin/env perl6 # file: tutorial-p6.pl # PRELIMS ======================== use v6.0; # not required, but good practice for # maintenance # 'strict' and 'warnings' are the default # Note: Using perl6 -v => # '2015.07.1-66-g0dcbba7 built on MoarVM version 2015.07-8-gb8fdeae' use Data::Dump; my $default_infile = 'tutorial-data.txt'; my $prog = basename($*PROGRAM); my $debug = 0; my $infile = 0; my $usage = "$prog: --go | --infile=<data file name>"; $usage ~= ' | --help | ? [--debug[=N]]'; # '~=' instead of '.=' # ARG/OPTION HANDLING ======================== # See [http://design.perl6.org/S06.html] # for built-in methods similar to Getopts::Long if !@*ARGS.elems { say $usage ~ "\n"; # '~' instead of '.' exit; } for @*ARGS -> $arg is copy { # 'is copy' allows modifying locally my $oarg = $arg; # save original for error handling my $val = Any; # 'Any' instead of 'undef' my $idx = index $arg, '='; if $idx.defined { # index is defined if an index is found $val = substr $arg, $idx+1; # use substr function $arg = substr $arg, 0, $idx; } if ($arg eq '-g' || $arg eq '--go') { $infile = $default_infile; } elsif ($arg eq '-i' || $arg eq '--infile') { $infile = $val; } elsif ($arg eq '-d' || $arg eq '--debug') { $debug = defined $val ? $val : 1; } elsif ($arg eq '-h' || $arg eq '--help' || $arg eq q{?}) { long_help(); } else { die "FATAL: Unknown argument '$oarg'.\n"; } } # MAIN PROGRAM ======================== die "FATAL: No such file '$infile'.\n" if $infile.IO !~~ :f; my %user; my @keywords = <last first job>; my %keywords; %keywords{@keywords} = (); parse_data_file($infile, %user, $debug); if $debug { say "DEBUG: Dumping user hash after loading:"; say Dump(%user); } else { say 'Normal end.'; } #### SUBROUTINES ======================== sub parse_data_file(Str $fname, # declare args #Any $href, %href, Int $debug = 0) { say "Parsing input file '$fname'..."; my $uid = Any; # p6 doesn't use 'undef' my $linenum = 0; for $fname.IO.lines -> $line is copy { ++$linenum; my $err = 0; # remove comments my $idx = index $line, '#', 0; if defined $idx { $line = $line.substr(0, $idx); } # skip blank lines next if $line !~~ /\S/; # '~~' and '!~~' for matching # every valid line must have a colon (':') # following a key word $idx = $line.index(':'); if $idx.defined { # ensure the key is lower case my $k = $line.substr(0, $idx).lc; # trim ws on both ends $k = $k.trim; # string object method my $val = $line.substr($idx+1); # use object method # also needs trimming $val = $val.trim; # User attributes if $k eq 'user' { $uid = $val; die "FATAL: \$uid not defined." if !$uid.defined; if $uid ~~ /\D/ { say "ERROR: User ID not an integer."; ++$err; } elsif $uid <= 0 { say "ERROR: User ID not an integer > 0."; ++$err; } elsif %href{$uid}:exists { # 'exists' adverb say "ERROR: User ID is not unique."; ++$err; } next; } # for the following keys, an exception will be # thrown if $uid is not defined if !$uid.defined { say "ERROR: User ID is not defined for this user."; ++$err; } elsif $k eq 'hobbies' { # literal string keys must be quoted %href{$uid}<<hobbies>> = []; my @h = split ',', $val; for @h -> $h is rw { # trim ws on both ends $h .= trim; # literal string keys must be quoted # use '@()' instead of '@{} push @(%href{$uid}<hobbies>), $h; } } elsif %keywords{$k}:exists { %href{$uid}{$k} = $val; } else { $line .= chomp; say "ERROR: Unknown line format, \$k = '$k'."; say " '$line'"; ++$err; } } else { say 'ERROR: Unknown line format (no key).'; ++$err; } if $debug { $line .= chomp; say "DEBUG: line = '$line'"; } if $err { $line .= chomp; say "FATAL error in file '$fname' at line $linenum:"; say " '$line'"; exit; } } } # parse_data_file sub long_help { # note indent is taken from position of ending token say qq:to/HERE/; Usage (one of the following three): $prog --go (or '-g') $prog --infile=<data file name> (or '-i=') $prog --help (or '-h' or '?') The '--go' option uses the default input file: $default_infile Any of the first two options can use the '-d' (or '--debug') flag for debugging. A debug number may be provided with '-d=N' (or '--debug=N'). HERE exit; } # long_help sub basename(IO::Path $fname) { # no File::Basename module in p6 yet my $idx = rindex $fname, '/'; if $idx { return $fname.substr($idx+1); # use substr method } return $fname; } # basename # EOF ========================

Following is the input data file used in the programs above:

# file: tutorial-data.txt # a data file of users and their attributes # note all valid lines are in format "key: value..." user: 1234 # unique ID (an integer > zero) last: Brown first: Sam job: gunsmith # hobbies may be a comma-separated list hobbies: hunting, Perl Monging user: 2316 last: Doe first: Jane job: financial analyst hobbies: Python open source, bowling

Replies are listed 'Best First'.
Re: RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
by davido (Cardinal) on Aug 06, 2015 at 06:41 UTC

    Thoughtlessly applying techniques effective in one language to another typically leads to awkward, poorly performing, and hard-to-maintain code. Such code is also most frustrating to write because every line of code and every compiler error message reminds the programmer that the language used differs from "the old language."

    -- Stroustrup, The C++ Programming Language, 4th Edition

    I suggest the best approach to teaching Perl5 developers how to use Perl6 is to teach them Perl6 with the expectation that they are programmers, who are capable of picking up new languages. It's not very useful to me to learn how to translate Perl5 idioms to Perl6. Show me Perl6 on its own terms.

    When I pick up a book on Scheme, or JavaScript, or SQL, or C++, I expect to be introduced to a new means of expression in programming, and am glad that I don't have to sift through examples of how to do Perlish things in C++. I (hopefully) get exposed to the new language as a complete entity that needn't compare itself to other relatives no matter how close they are.

    The occasional "In contrast to XXX, YYY." is fine. But think of the best programming books you've read. How many of them focus mostly on comparing and contrasting? The Perl Cookbook doesn't start each chapter by saying, "In C I would do yada yada, how do I do that in Perl?" Mastering Algorithms with Perl doesn't bog us down with example of how graphs were implemented in Java.

    Ok, enough of that.... now for some words of encouragement.

    It appears that Perl6 is on its way to becoming a fairly nifty language, with lots of cool features. It would be great if there were some well written literature to go along with a complete implementation. I look forward to both.


    Dave

      It appears that Perl6 is on its way to becoming a fairly nifty language, with lots of cool features. It would be great if there were some well written literature to go along with a complete implementation. I look forward to both.

      Dave, thanks, but don't expect that here. My goal was merely as stated in the beginning. Getting started with working code for a complete program is a bit of a pain at the moment, so I give this simple real-world example to help one a Perl 5 programmer get started. I leave the in-depth explanations to others. I do agree that I could embellish the code with more comments and references to normative docs sources and will probably do so (after BrowserUK produces an improved version of my Perl 5 code).

      This approach works for me, but if the consensus is my approach isn't useful to others, then I will remove it.

      However, if the approach is found to be useful, I can expand it later to introduce classes and some other Perl 6 features. I also need to add in the introduction (per BrowserUK's comments) a few words on the benefits of Perl 6 over Perl 5.

Re: RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
by Arunbear (Prior) on Aug 07, 2015 at 10:17 UTC

      Okay, will do. Thanks.

        Thank you, but that's not a tutorial, this is a tutorial. Yes, the content is now out of date, but look at the style and presentation.

        He does eventually give a code dump, but it comes at the end, after he has explained what it does, a piece at a time. A tutorial should teach and explain a step at a time, not just throw some code at the reader.

        Just to give you one example, in a tutorial it's not good enough to just say "p6 doesn't use 'undef'" with no further explanation.
Re: RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
by Laurent_R (Canon) on Aug 09, 2015 at 08:17 UTC
    The problem with the exercise of translating a Perl 5 program to Perl 6 is that, unless you really know Perl 6 very well, you'll probably tend not to use all the power of Perl 6 (possibility of strong typing, function signatures, working given/when construct, pairs, junctions, enums, multi subroutines, construction of your own operators, grammars, etc.) and not to use really idiomatic Perl 6 code.

    This is nonetheless quite useful to point out the differences between the two languages.

      ...unless you really know Perl 6 very well, you'll probably tend not to use all the power of Perl 6...

      Thanks. I know that's true, and I will try to improve the Perl 6 code a bit later.

Re: RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
by BrowserUk (Patriarch) on Aug 06, 2015 at 01:17 UTC
    looking for constructive criticism

    204 P5 lines versus 213 P6 lines, all to do nothing useful; and the advantage of P6 is?

      First, the purpose of this tutorial is to show how to translate a real Perl 5 program with typical, often-used statements and code idioms into the equivalent Perl 6 form, and it is not intended to show the advantages of Perl 6. Second, the greater length of the Perl 6 program is due to the extra subroutine required because of a currently non-existent module in the Perl 6 system. Third, I believe the example program's utility, although simplistic, does provide a useful template for many real-world problems.

        Third, I believe the example program's utility, although simplistic, does provide a useful template for many real-world problems.

        I make no claim for being especially conversant with P6.

        But. I think it is clear from my history here that I am reasonably conversant in P5.

        I downloaded your P5 example and ran it. I reformatted it to an acceptable standard. I threw away the superfluous fluff. I trimmed the unnecessary verbosity.

        I arrived at < 50 lines of workaday Perl 5 code and ... could see nothing in it that allowed it to demonstrate a single advantage of P6 over P5. Not one.

        If your purpose is to promote P6; then take council. Choose an example that exercises P6's strengths rather than it weaknesses. Trim it to its bare minimum. Then ...

        Contrast it with the best, most idiomatic, most performent, most clear; most maintainable P5 equivalent you can muster.

        My point is: demonstrating that a P6 solution to a non-problem takes more lines of code than a P5 equivalent; does not serve the purpose of persuading those of us suffering from CP6ES (Chronic Perl 6 Expectation Syndrome), that it is time for us to re-evaluate P6.

        Bad promotion is worse than no promotion. Doubt my words? Ask Gerald Ratner about his £277.5 million per word apercu; then protest my intervention.


        Anyone got any experience of this phone's predecessor?

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
        In the absence of evidence, opinion is indistinguishable from prejudice.
        I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!

      UPDATE: Please ignore this redundant and inadvertently added comment.

      As stated, the subroutine is there because the File::Basename module is not available yet. I'm sure there's a better way to do it in Perl 6 but this works for now.

Re: RFC: (DRAFT Tutorial) A Gentle Introduction to Perl 6
by Anonymous Monk on Aug 10, 2015 at 02:51 UTC

    “Perl 6 is almost upon us, and it promises to cure many of the shortcomings of Perl 5.”

    It’s simply too late to (keep ...) saying things like that.   The biggest mistake that the Perl-6 (sic ...) team did, all those so many years ago now, was to refuse to acknowledge that theirs was, in fact, a project to create an altogether-new programming language.   Had they done that, as Ruby did, they might have been successful, as Ruby was.     Instead of looking at the strengths and weaknesses of “Perl and other languages” at that particular time, and trying to arrive at something really-new that was also really-different and really-better(?) ... as, maybe, Ruby did ... they left us with a fairly-stillborn project that still doesn’t quite seem to know what their language should be, nor even what runtime-engine it should be based upon.

    In the end, they most wanted to be able to boldly say ... use v6.0; ... even though their brainchild has no particular claim to any such provenance.

    During the same period of time, someone else invented use Moose;, and did so entirely within the auspices of the existing interpreter.   Same thing?   Of course not.   A pragmatic improvement?   Yes.

    When I look at these two code-listings side by side, and acknowledging that they are not a particularly good comparison, I simply see no advantages here.   I only see differences in a BNF grammar.   Perl5 is one of a great many programming tools that I use (and encounter) on a very regular basis.   I have yet to see any particular reason to add “this whatever-it-is” to that mix, and I am very frankly tired of hearing about it.

    “You couldah been a contendah ...”   Yeah, but the place where the boxing ring used to be is now a drugstore.   Get over it.

      Your thesis not new, however it is not entirely without merit. Yes Perl6 is still not at 1.0. Yes, perl 5.10 languished for an extended time, seemingly unmaintained at a critical time in the development of the dynamic web.

      Whatever. Those decisions were made and those actions were taken by people doing what they thought was the best thing to do at the time. Maybe they were wrong. Maybe they were right. Maybe somewhere in-between... One thing is certain, stuff happened, it is in the past and won't change.

      As to your criticism that Perl6 has no merits or particular strengths beyond Perl5, I can only assume that you have read only this example of Perl6. Had you read any of the excellent, rapidly evolving docs at http://doc.perl6.org, you would realize that Perl6 has some really nice features.

      I've been barely dabbling in Perl6 for a few months, and the things that stand out to me are:

      • Lazy lists - when combined with nice list comprehension syntax and metaoperators you have immense expressive power.
      • Gradual typing - be strongly typed or be dynamic without having to mess about with templates.
      • UTF8, I hate it, but Perl6 does it well.
      • Concurrency - Perl6 promises, channels and supplies combine with auto-threaded list filters make parallel programming much easier.

      On the down side:

      1. it really is a new language and a big one
      2. Holy crap, there are a billion operators
      3. What slurps where and when?
      4. occasional bits don't work as documented, or are only documented in a Synopsis.
      5. Rakudo codebase is moving really fast. Of course that velocity is a sign that Christmas may actually happen this year.

      I suggest you actually give Perl6 a real try.


      TGI says moo

      looking at the strengths and weaknesses of “Perl and other languages

      This was most definitely done. The comment about Moose suggests further ignorance of the Perl6 design process.

      Without the cachet of "Perl" attached to the project the chances that it would have got anywhere are slim. So, again we have a revisionist complaining that things weren't done in a way that would have made them impossible to do at all.

      Get over it.

      There's nothing to get over. Some monks are interested in Perl6. It's no skin off your as^Wnose if they are or they sink time and effort into it.

        "Without the cachet of "Perl" attached to the project the chances that it would have got anywhere are slim."

        As opposed to what we have now, which is...?

        Oh right, more promises and a conference talk which was an announcement of an announcement. Great work everyone!

      A reply falls below the community's threshold of quality. You may see it by logging in.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://1137601]
Approved by Laurent_R
Front-paged by BrowserUk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (4)
As of 2024-03-29 15:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found