From e336c909b9ed44895b2df7d0b2cdd5b383e9b7fd Mon Sep 17 00:00:00 2001 From: samcv Date: Thu, 20 Oct 2016 06:59:55 -0700 Subject: Perl 6: Make information about Hash tables correct. Rewrite the example for dynamically scoped variables.. (#2475) * Explain that you cannot pass immutable values like integers to subs even if you use $n is rw. * Add myself as a contributor * Remove contributor since I am not a major contributor * Add many more smartmatch examples. Make the ternary operatory clearer and add a code example for it. Make the section for && and || have a working code example and show the output it gives * Fix assigning $a $b and $c values in the && operator section * Rename a few things so they don't conflict with variables in other parts of the code * Remove extra dashes * Move description of smartmatch type checks toward the end of that section * Better names for scoping examples * Redo the example for dynamically scoped variables so the example is better and functions properly when ran (old example did not work properly when running it by itself) * Rename these classes so they aren't named the same as the ones above * Add information about the different twigils in Perl 6. This makes understanding what $. $! and $* are and how they relate. Also complete the renaming in the previous commit * Fix capitalization and indenting here * Using the word interpolate to mean accessing an element of an array is not the proper terminology. Using the word interpolate is usually associated with things such as this: say "@names = { @names.perl }" * Make the wording a little clearer for arrays * Remove incorrect information about hashes. Hashes are not arrays of pairs although Perl 6 makes it easy to use them as such * Make the subroutine text read better * Clean up the Object Model introduction section * Fix the section on interpolating all elements of an array * Use the word attribute instead of field since this is the wording that the perl 6 documentation uses for these objects * Fix column width in a few places * More clearly mark which twigils are used for "normal" variables and which ones are used on "objects". This makes the flow from the # Scoping => # Twigil => # Object Model section smoother * Semi-rewrite the example for object inheritance and use more natural names. Also rename class A to class Attrib-Class * Clean up the scoping introduction a little * Remove a leftover line from rewriting the inheritance example * More gradually introduce exceptions and fix a typo, as well as adding a few examples * Reorder introduction of packages to be more natural. Show how to "use" a package before we show how to create and declare our own modules * Avoid using the word 'use' because we're not refering to the perl keyword 'use' --- perl6.html.markdown | 283 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 172 insertions(+), 111 deletions(-) diff --git a/perl6.html.markdown b/perl6.html.markdown index a69cfe00..d31955f0 100644 --- a/perl6.html.markdown +++ b/perl6.html.markdown @@ -37,11 +37,11 @@ my $str = 'String'; # double quotes allow for interpolation (which we'll see later): my $str2 = "String"; -# variable names can contain but not end with simple quotes and dashes, -# and can contain (and end with) underscores : +# Variable names can contain but not end with simple quotes and dashes, +# and can contain (and end with) underscores : # my $weird'variable-name_ = 5; # works ! -my $bool = True; # `True` and `False` are Perl 6's boolean +my $bool = True; # `True` and `False` are Perl 6's boolean values. my $inverse = !$bool; # You can invert a bool with the prefix `!` operator my $forced-bool = so $str; # And you can use the prefix `so` operator # which turns its operand into a Bool @@ -56,28 +56,32 @@ my @array = 1, 2, 3; say @array[2]; # Array indices start at 0 -- This is the third element -say "Interpolate an array using [] : @array[]"; -#=> Interpolate an array using [] : 1 2 3 +say "Interpolate all elements of an array using [] : @array[]"; +#=> Interpolate all elements of an array using [] : 1 2 3 @array[0] = -1; # Assign a new value to an array index @array[0, 1] = 5, 6; # Assign multiple values my @keys = 0, 2; -@array[@keys] = @letters; # Assign using an array +@array[@keys] = @letters; # Assignment using an array containing index values say @array; #=> a 6 b ## * Hashes, or key-value Pairs. -# Hashes are actually arrays of Pairs -# (you can construct a Pair object using the syntax `Key => Value`), -# except they get "flattened" (hash context), removing duplicated keys. +# Hashes are pairs of keys and values. +# You can construct a Pair object using the syntax `Key => Value`. +# Hash tables are very fast for lookup, and are stored unordered. +# Keep in mind that keys get "flattened" in hash context, and any duplicated +# keys are deduplicated. my %hash = 1 => 2, 3 => 4; my %hash = foo => "bar", # keys get auto-quoted "some other" => "value", # trailing commas are okay ; -my %hash = ; # you can also create a hash - # from an even-numbered array -my %hash = key1 => 'value1', key2 => 'value2'; # same as this +# Even though hashes are internally stored differently than arrays, +# Perl 6 allows you to easily create a hash from an even numbered array: +my %hash = ; + +my %hash = key1 => 'value1', key2 => 'value2'; # same result as above # You can also use the "colon pair" syntax: # (especially handy for named parameters that you'll see later) @@ -92,7 +96,8 @@ say %hash{'key1'}; # You can use {} to get the value from a key say %hash; # If it's a string, you can actually use <> # (`{key1}` doesn't work, as Perl6 doesn't have barewords) -## * Subs (subroutines, or functions in most other languages). +## * Subs: subroutines or functions as most other languages call them are +# created with the `sub` keyword. sub say-hello { say "Hello, world" } sub say-hello-to(Str $name) { # You can provide the type of an argument @@ -619,66 +624,95 @@ multi with-or-without-you { ### Scoping -# In Perl 6, contrarily to many scripting languages (like Python, Ruby, PHP), -# you are to declare your variables before using them. You know `my`. -# (there are other declarators, `our`, `state`, ..., which we'll see later). +# In Perl 6, unlike many scripting languages, (such as Python, Ruby, PHP), +# you must declare your variables before using them. The `my` declarator +# you have learned uses "lexical scoping". There are a few other declarators, +# (`our`, `state`, ..., ) which we'll see later. # This is called "lexical scoping", where in inner blocks, # you can access variables from outer blocks. -my $foo = 'Foo'; -sub foo { - my $bar = 'Bar'; - sub bar { - say "$foo $bar"; +my $file_scoped = 'Foo'; +sub outer { + my $outer_scoped = 'Bar'; + sub inner { + say "$file_scoped $outer_scoped"; } - &bar; # return the function + &inner; # return the function } -foo()(); #=> 'Foo Bar' +outer()(); #=> 'Foo Bar' -# As you can see, `$foo` and `$bar` were captured. +# As you can see, `$file_scoped` and `$outer_scoped` were captured. # But if we were to try and use `$bar` outside of `foo`, # the variable would be undefined (and you'd get a compile time error). -# Perl 6 has another kind of scope : dynamic scope. -# They use the twigil (composed sigil) `*` to mark dynamically-scoped variables: -my $*a = 1; -# Dyamically-scoped variables depend on the current call stack, -# instead of the current block depth. -sub foo { - my $*foo = 1; - bar(); # call `bar` in-place +### Twigils + +# There are many special `twigils` (composed sigil's) in Perl 6. +# Twigils define the variables' scope. +# The * and ? twigils work on standard variables: +# * Dynamic variable +# ? Compile-time variable +# The ! and the . twigils are used with Perl 6's objects: +# ! Attribute (class member) +# . Method (not really a variable) + +# `*` Twigil: Dynamic Scope +# These variables use the`*` twigil to mark dynamically-scoped variables. +# Dynamically-scoped variables are looked up through the caller, not through +# the outer scope + +my $*dyn_scoped_1 = 1; +my $*dyn_scoped_2 = 10; + +sub say_dyn { + say "$*dyn_scoped_1 $*dyn_scoped_2"; } -sub bar { - say $*foo; # `$*foo` will be looked in the call stack, and find `foo`'s, - # even though the blocks aren't nested (they're call-nested). - #=> 1 + +sub call_say_dyn { + my $*dyn_scoped_1 = 25; # Defines $*dyn_scoped_1 only for this sub. + $*dyn_scoped_2 = 100; # Will change the value of the file scoped variable. + say_dyn(); #=> 25 100 $*dyn_scoped 1 and 2 will be looked for in the call. + # It uses he value of $*dyn_scoped_1 from inside this sub's lexical + # scope even though the blocks aren't nested (they're call-nested). } +say_dyn(); #=> 1 10 +call_say_dyn(); #=> 25 100 + # Uses $*dyn_scoped_1 as defined in call_say_dyn even though + # we are calling it from outside. +say_dyn(); #=> 1 100 We changed the value of $*dyn_scoped_2 in call_say_dyn + # so now its value has changed. ### Object Model -# You declare a class with the keyword `class`, fields with `has`, -# methods with `method`. Every attribute that is private is named `$!attr`. -# Immutable public attributes are named `$.attr` +# To call a method on an object, add a dot followed by the method name: +# => $object.method +# Classes are declared with the `class` keyword. Attributes are declared +# with the `has` keyword, and methods declared with `method`. +# Every attribute that is private uses the ! twigil for example: `$!attr`. +# Immutable public attributes use the `.` twigil. # (you can make them mutable with `is rw`) +# The easiest way to remember the `$.` twigil is comparing it to how methods +# are called. # Perl 6's object model ("SixModel") is very flexible, # and allows you to dynamically add methods, change semantics, etc ... -# (this will not be covered here, and you should refer to the Synopsis). +# (these will not all be covered here, and you should refer to: +# https://docs.perl6.org/language/objects.html. -class A { - has $.field; # `$.field` is immutable. - # From inside the class, use `$!field` to modify it. - has $.other-field is rw; # You can mark a public attribute `rw`. - has Int $!private-field = 10; +class Attrib-Class { + has $.attrib; # `$.attrib` is immutable. + # From inside the class, use `$!attrib` to modify it. + has $.other-attrib is rw; # You can mark a public attribute `rw`. + has Int $!private-attrib = 10; method get-value { - $.field + $!private-field; + $.attrib + $!private-attrib; } - method set-value($n) { - # $.field = $n; # As stated before, you can't use the `$.` immutable version. - $!field = $n; # This works, because `$!` is always mutable. + method set-value($param) { # Methods can take parameters + $!attrib = $param; # This works, because `$!` is always mutable. + # $.attrib = $param; # Wrong: You can't use the `$.` immutable version. - $.other-field = 5; # This works, because `$.other-field` is `rw`. + $.other-attrib = 5; # This works, because `$.other-attrib` is `rw`. } method !private-method { @@ -686,33 +720,44 @@ class A { } }; -# Create a new instance of A with $.field set to 5 : -# Note: you can't set private-field from here (more later on). -my $a = A.new(field => 5); -$a.get-value; #=> 15 -#$a.field = 5; # This fails, because the `has $.field` is immutable -$a.other-field = 10; # This, however, works, because the public field - # is mutable (`rw`). - -## Perl 6 also has inheritance (along with multiple inheritance) - -class A { - has $.val; - - submethod not-inherited { - say "This method won't be available on B."; - say "This is most useful for BUILD, which we'll see later"; +# Create a new instance of Attrib-Class with $.attrib set to 5 : +# Note: you can't set private-attribute from here (more later on). +my $class-obj = Attrib-Class.new(attrib => 5); +say $class-obj.get-value; #=> 15 +#$class-obj.attrib = 5; # This fails, because the `has $.attrib` is immutable +$class-obj.other-attrib = 10; # This, however, works, because the public + # attribute is mutable (`rw`). + +## Object Inheritance +# Perl 6 also has inheritance (along with multiple inheritance) +# While `method`'s are inherited, `submethod`'s are not. +# Submethods are useful for object construction and destruction tasks, +# such as BUILD, or methods that must be overriden by subtypes. +# We will learn about BUILD later on. + +class Parent { + has $.age; + has $.name; + # This submethod won't be inherited by Child. + submethod favorite-color { + say "My favorite color is Blue"; } - - method bar { $.val * 5 } + # This method is inherited + method talk { say "Hi, my name is $!name" } } -class B is A { # inheritance uses `is` - method foo { - say $.val; - } - - method bar { $.val * 10 } # this shadows A's `bar` +# Inheritance uses the `is` keyword +class Child is Parent { + method talk { say "Goo goo ga ga" } + # This shadows Parent's `talk` method, This child hasn't learned to speak yet! } +my Parent $Richard .= new(age => 40, name => 'Richard'); +$Richard.favorite-color; #=> "My favorite color is Blue" +$Richard.talk; #=> "Hi, my name is Richard" +# # $Richard is able to access the submethod, he knows how to say his name. + +my Child $Madison .= new(age => 1, name => 'Madison'); +$Madison.talk; # prints "Goo goo ga ga" due to the overrided method. +# $Madison.favorite-color does not work since it is not inherited # When you use `my T $var`, `$var` starts off with `T` itself in it, # so you can call `new` on it. @@ -720,11 +765,7 @@ class B is A { # inheritance uses `is` # `$a .= b` is the same as `$a = $a.b`) # Also note that `BUILD` (the method called inside `new`) # will set parent properties too, so you can pass `val => 5`. -my B $b .= new(val => 5); -# $b.not-inherited; # This won't work, for reasons explained above -$b.foo; # prints 5 -$b.bar; #=> 50, since it calls B's `bar` ## Roles are supported too (also called Mixins in other languages) role PrintableVal { @@ -739,8 +780,8 @@ class Item does PrintableVal { has $.val; # When `does`-ed, a `role` literally "mixes in" the class: - # the methods and fields are put together, which means a class can access - # the private fields/methods of its roles (but not the inverse !): + # the methods and attributes are put together, which means a class can access + # the private attributes/methods of its roles (but not the inverse !): method access { say $!counter++; } @@ -757,34 +798,48 @@ class Item does PrintableVal { ### Exceptions # Exceptions are built on top of classes, in the package `X` (like `X::IO`). -# Unlike many other languages, in Perl 6, you put the `CATCH` block *within* the -# block to `try`. By default, a `try` has a `CATCH` block that catches -# any exception (`CATCH { default {} }`). +# You can access the last exception with the special variable `$!` +# (use `$_` in a `CATCH` block) Note: This has no relation to $!variables. + +# You can throw an exception using `die`: +open 'foo' or die 'Error!'; #=> Error! +# Or more explicitly: +die X::AdHoc.new(payload => 'Error!'); + +## Using `try` and `CATCH` +# By using `try` and `CATCH` you can contain and handle exceptions without +# disrupting the rest of the program. +# Unlike many other languages, in Perl 6, you put the `CATCH` block *within* +# the block to `try`. By default, a `try` has a `CATCH` block that catches +# any exception (`CATCH { default {} }`). + +try { my $a = (0 %% 0); CATCH { say "Something happened: $_" } } + #=> Something happened: Attempt to divide by zero using infix:<%%> + # You can redefine it using `when`s (and `default`) -# to handle the exceptions you want: +# to handle the exceptions you want: try { open 'foo'; - CATCH { - when X::AdHoc { say "unable to open file !" } + CATCH { # In the `CATCH` block, the exception is set to $_ + when X::AdHoc { say "Error: $_" } + #=>Error: Failed to open file /dir/foo: no such file or directory + # Any other exception will be re-raised, since we don't have a `default` - # Basically, if a `when` matches (or there's a `default`) marks the exception as - # "handled" so that it doesn't get re-thrown from the `CATCH`. + # Basically, if a `when` matches (or there's a `default`) marks the + # exception as + # "handled" so that it doesn't get re-thrown from the `CATCH`. # You still can re-throw the exception (see below) by hand. } } -# You can throw an exception using `die`: -die X::AdHoc.new(payload => 'Error !'); - -# You can access the last exception with `$!` (use `$_` in a `CATCH` block) - -# There are also some subtelties to exceptions. Some Perl 6 subs return a `Failure`, -# which is a kind of "unthrown exception". They're not thrown until you tried to look -# at their content, unless you call `.Bool`/`.defined` on them - then they're handled. -# (the `.handled` method is `rw`, so you can mark it as `False` back yourself) +# There are also some subtleties to exceptions. Some Perl 6 subs return a +# `Failure`, which is a kind of "unthrown exception". They're not thrown until +# you tried to look at their content, unless you call `.Bool`/`.defined` on +# them - then they're handled. +# (the `.handled` method is `rw`, so you can mark it as `False` back yourself) # -# You can throw a `Failure` using `fail`. Note that if the pragma `use fatal` is on, -# `fail` will throw an exception (like `die`). +# You can throw a `Failure` using `fail`. Note that if the pragma `use fatal` +# is on, `fail` will throw an exception (like `die`). fail "foo"; # We're not trying to access the value, so no problem. try { fail "foo"; @@ -804,22 +859,26 @@ try { # and `enum`) are actually packages. (Packages are the lowest common denominator) # Packages are important - especially as Perl is well-known for CPAN, # the Comprehensive Perl Archive Network. -# You're not supposed to use the package keyword, usually: -# you use `class Package::Name::Here;` to declare a class, -# or if you only want to export variables/subs, you can use `module`: + +# You can use a module (bring its declarations into scope) with `use` +use JSON::Tiny; # if you installed Rakudo* or Panda, you'll have this module +say from-json('[1]').perl; #=> [1] + +# Declare your own packages like this: +# `class Package::Name::Here;` to declare a class, or if you only want to +# export variables/subs, you can use `module`. If you're coming from Perl 5 +# please note you're not usually supposed to use the `package` keyword. + module Hello::World { # Bracketed form # If `Hello` doesn't exist yet, it'll just be a "stub", # that can be redeclared as something else later. # ... declarations here ... } unit module Parse::Text; # file-scoped form + grammar Parse::Text::Grammar { # A grammar is a package, which you could `use` } -# You can use a module (bring its declarations into scope) with `use` -use JSON::Tiny; # if you installed Rakudo* or Panda, you'll have this module -say from-json('[1]').perl; #=> [1] - # As said before, any part of the six model is also a package. # Since `JSON::Tiny` uses (its own) `JSON::Tiny::Actions` class, you can use it: my $actions = JSON::Tiny::Actions.new; @@ -1128,10 +1187,11 @@ sub add($a, $b) { $a + $b } say [[&add]] 1, 2, 3; #=> 6 ## * Zip meta-operator -# This one is an infix meta-operator than also can be used as a "normal" operator. -# It takes an optional binary function (by default, it just creates a pair), -# and will pop one value off of each array and call its binary function on these -# until it runs out of elements. It returns an array with all of these new elements. +# This one is an infix meta-operator than also can be used as a "normal" +# operator. It takes an optional binary function (by default, it just creates +# a pair), and will pop one value off of each array and call its binary function +# on these until it runs out of elements. It returns an array with all of these +# new elements. (1, 2) Z (3, 4); # ((1, 3), (2, 4)), since by default, the function makes an array 1..3 Z+ 4..6; # (5, 7, 9), using the custom infix:<+> function @@ -1205,7 +1265,8 @@ say so 'a' ~~ / a /; # More readable with some spaces! # returning a `Match` object. They know how to respond to list indexing, # hash indexing, and return the matched string. # The results of the match are available as `$/` (implicitly lexically-scoped). -# You can also use the capture variables (`$0`, `$1`, ... starting at 0, not 1 !). +# You can also use the capture variables which start at 0: +# `$0`, `$1', `$2`... # # You can also note that `~~` does not perform start/end checking # (meaning the regexp can be matched with just one char of the string), -- cgit v1.2.3