]> Dogcows Code - chaz/talk-level-up-your-perl/blob - slides.html
improve notes
[chaz/talk-level-up-your-perl] / slides.html
1 <!DOCTYPE html>
2 <html><head><meta charset="utf-8"><title>Level up your Perl</title><link rel="stylesheet" href="css/common.css"><link rel="stylesheet" href="css/slides.css"></head><body><textarea id="source">
3
4 class: center, middle
5 name: title
6
7 # Level up your Perl
8
9 Charles McGarvey
10
11 ???
12 - Hi. I'm Charles McGarvey.
13 - Been a Perl programmer for a long time...
14
15 ---
16 class: center, middle
17
18 ![The Raptor](img/raptor.png)
19
20 ???
21 - Deciding what to talk on... everything!
22 - List of things that you should know or be aware of...
23 - This image works well (merit badge)...
24
25 ---
26 class: center, middle
27 name: endurance
28
29 ![Endurance](img/endurance.png)
30
31 ### https://jobs.endurance.com/bluehost
32
33 ???
34 - My employer is hiring.
35 - It's a pretty cool employer...
36
37 ---
38 class: center, middle
39
40 ## Use [`B::Deparse`](https://metacpan.org/pod/B::Deparse).
41
42 ???
43 - `B::Deparse` is a backend module for the compiler.
44 - It takes the parse tree after compiling and generates Perl code from it.
45
46 So, why compile Perl only to turn it back into Perl?
47 It is useful for checking that perl and you are both understanding the code the same way.
48
49 ---
50 class: ex-deparse
51
52 ## Example of `B::Deparse`.
53
54 ```bash
55 perl -MO=Deparse,-p -e'$a && not $b && not $c'
56 *($a and not(($b && (!$c))));
57 -e syntax OK
58 ```
59
60 --
61 ```bash
62 perl -MO=Deparse,-p -e'$a && ! $b && ! $c'
63 *(($a and not($b)) and not($c));
64 -e syntax OK
65 ```
66
67 ???
68 - These example snippets demonstrate an actual bug found in real code.
69
70 - The first snippet is mixing high and low-precedence logical operators. Comparing the output of Deparse, it's fairly
71 clear to see that these are not doing the same thing.
72
73 - Deparse supports other flags that may be useful. Read the pod to find out more.
74
75 - Aside: Be careful about mixing high and low-precedence logical operators.
76
77 ---
78 class: center, middle
79
80 ## Know regular expressions.
81
82 ???
83 - Like, really know them.
84 - I meet a lot of people who don't know regexp.
85
86 ---
87 class: center, middle
88
89 ### It's easy.
90
91 ???
92 - But they're easy!
93 - All you have to do in order to read and write regular expressions *without looking at a help resource every time* is
94 know a few basic things.
95
96 ---
97 class: center, middle
98
99 ### Two basic parts:
100
101 # (what to match) (how many to match)
102
103 ???
104 - Regular expressions let you match strings.
105 - Find out "does a string follow a specific pattern".
106
107 ---
108 ### What to match: Literals
109
110 - Match a specific character
111 - `a`
112 - `7`
113 - `~`
114 - `ΓΏ`
115 - `\^`
116 - `\t`
117
118 ---
119 ### What to match: Character classes
120
121 - Match a character within a set
122 - `[a-z-]`
123 - `[^0-9]`
124 - `[q]`
125 - `\h`
126 - `[[:digit:]]`
127 - `.`
128 - `\X`
129
130 ---
131 ### How many to match: Quantifiers
132
133 - Match a certain number of the preceding single character or character class
134 - `*` - zero or more
135 - `+` - one or more
136 - `?` - zero or one
137 - `{2}`
138 - `{2,}`
139
140 ---
141 class: center, middle
142
143 # (what to match) (how many to match)
144
145 ???
146 - That's it!
147
148 ---
149 class: center, middle
150
151 ## Okay, there is more...
152
153 ???
154 - But if you know just those concepts, you can already read a large number of regexp that you'll come across.
155
156 ---
157 ### Boundaries
158
159 - Look for the edges surrounding or between things
160 - `^`
161 - `$`
162 - `\b`
163 - `\b{sb}` - sentence boundary
164 - `\b{gcb}`
165
166 ???
167 I say "look for" instead of "match" because the boundary isn't something that shows up in the results.
168
169 ---
170 ### The pipe
171
172 - Match this or that
173 - `cat|dog`
174
175 ---
176 ### Groups
177
178 - Separate the regexp into logical chunks
179 - `(blah)`
180 - `(?:whatever)` - noncapturing
181
182 ---
183 ### Backreferences
184
185 - Match something again
186 - `\1`
187 - `\2`
188 - etc.
189
190 ---
191 ### Lookaround
192
193 - Require presence of something without actually matching it
194 - `(?=regexp)` and `(?!regexp)` - lookahead
195 - `(?<=regexp)` and `(?<!regexp)` - lookbehind
196
197 ???
198 These are zero-length assertions. Like boundaries, these don't actually match anything; they just make sure something is
199 or isn't present at the position where it exists relative to its surroundings.
200
201 ---
202 class: center, middle
203
204 ## Use [`Regexp::Debugger`](https://metacpan.org/pod/Regexp::Debugger).
205
206 ---
207 class: ex-regexpdebugger
208
209 ```perl
210 use Regexp::Debugger;
211
212 my $not_png_or_jpg = qr/(?<!\.(png|jpg))$/;
213 my $filename = 'log.txt';
214
215 $filename =~ $not_png_or_jpg;
216 ```
217
218 ---
219 class: ex-regexpdebugger
220
221 ```perl
222 *use Regexp::Debugger;
223
224 my $not_png_or_jpg = qr/(?<!\.(png|jpg))$/;
225 my $filename = 'log.txt';
226
227 $filename =~ $not_png_or_jpg;
228 ```
229
230 --
231 ![Regexp::Debugger in action](img/regexp_debugger.png)
232
233 ---
234 class: regexpdebugger-commands
235
236 ## Things you can do with Regexp::Debugger
237
238 --
239 - The basics: step forward ("s") and backwards ("-").
240
241 --
242 - Hit "d" to get a detailed description of the regexp:
243
244 ```text
245 (?<! Match negative lookbehind
246 \. Match a literal '.' character
247 ( The start of a capturing block ($1)
248 png Match a literal sequence ("png")
249 | Or...
250 jpg Match a literal sequence ("jpg")
251 ) The end of $1
252 ) The end of negative lookbehind
253 $ Match only if at end of string (or final newline)
254 ```
255
256 --
257 - Try different modes, like "e" for event log.
258
259 --
260 - Hit "?" for help.
261
262 --
263 - Hit "q" to exit the debugger.
264
265 ---
266 class: center, middle
267
268 ### Also, check out [PPR](https://metacpan.org/pod/PPR).
269
270 ???
271 This module was brought to us by Damian Conway. Speaking of, if your interest in regular expressions continues, check
272 out this module. `PPR` is a packaged regular expression with subpatterns that can match Perl code.
273
274 Really cool stuff.
275
276 ---
277 class: center, middle
278
279 ## Write Vim plugins in Perl.
280
281 ---
282 class: center, middle
283
284 ### It's easy.
285
286 ---
287 class: ex-vimcheck, center, middle
288
289 ### Does your Vim support Perl?
290
291 ```bash
292 vim --version |grep +perl && echo 'Aww yeah!'
293 ```
294
295 ???
296 Some minimal builds of Vim do not have Perl support compiled in.
297 Check with this.
298
299 ---
300 class: ex-vimcheck, center, middle
301
302 ### You'll need this...
303
304 ```bash
305 :h usr_41
306 ```
307
308 Chapter 41 in the Vim manual is all about scripting.
309
310 ---
311 class: ex-vim
312
313 ```perl
314 function! color#random()
315 let l:colorlist = globpath(&rtp, "colors/*.vim")
316 perl <<END
317 my ($result, $colors) = VIM::Eval("l:colorlist");
318 return if $result != 1;
319 my @available_colors = split(/\n/, $colors);
320 my %bad_colors = eval {
321 open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
322 map { chomp; ($_ => 1) } <$fh>;
323 };
324 for (my $tries = 0; $tries < 100; ++$tries) {
325 my $colorpath = $available_colors[int(rand(@available_colors))];
326 my ($color) = $colorpath =~ m!([^/]+)\.vim!;
327 if (!$bad_colors{$color}) {
328 VIM::DoCommand("colorscheme $color");
329 last;
330 }
331 }
332 END
333 endfunction
334 ```
335
336 ---
337 class: ex-vim
338
339 ```perl
340 *function! color#random()
341 * let l:colorlist = globpath(&rtp, "colors/*.vim")
342 * perl <<END
343 my ($result, $colors) = VIM::Eval("l:colorlist");
344 return if $result != 1;
345 my @available_colors = split(/\n/, $colors);
346 my %bad_colors = eval {
347 open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
348 map { chomp; ($_ => 1) } <$fh>;
349 };
350 for (my $tries = 0; $tries < 100; ++$tries) {
351 my $colorpath = $available_colors[int(rand(@available_colors))];
352 my ($color) = $colorpath =~ m!([^/]+)\.vim!;
353 if (!$bad_colors{$color}) {
354 VIM::DoCommand("colorscheme $color");
355 last;
356 }
357 }
358 *END
359 *endfunction
360 ```
361
362 ???
363 This is Vimscript.
364
365 ---
366 class: ex-vim
367
368 ```perl
369 function! color#random()
370 let l:colorlist = globpath(&rtp, "colors/*.vim")
371 perl <<END
372 *my ($result, $colors) = VIM::Eval("l:colorlist");
373 return if $result != 1;
374 my @available_colors = split(/\n/, $colors);
375 my %bad_colors = eval {
376 open(my $fh, '<', "$ENV{HOME}/.vim/color_blacklist.txt");
377 map { chomp; ($_ => 1) } <$fh>;
378 };
379 for (my $tries = 0; $tries < 100; ++$tries) {
380 my $colorpath = $available_colors[int(rand(@available_colors))];
381 my ($color) = $colorpath =~ m!([^/]+)\.vim!;
382 if (!$bad_colors{$color}) {
383 * VIM::DoCommand("colorscheme $color");
384 last;
385 }
386 }
387 END
388 endfunction
389 ```
390
391 ???
392 By the way, Vim supports embedded interpreters for other languages like Python, Ruby, and Lua in similar fashion.
393
394 ---
395 class: center, middle
396
397 ## Document your shell scripts with pod.
398
399 ---
400 class: ex-shellpod
401
402 ```bash
403 #!/bin/sh
404
405 : <<'=cut'
406 =head1 NAME
407
408 therapist.sh - This script can save you a bunch of cash
409
410 =cut
411
412 echo 'Hello. Now, tell me about your problems.'
413
414 while read response
415 do
416 printf "Patient said: %s" "$response" >>therapist_notes.txt
417
418 echo 'And how did that make you feel?'
419 done
420
421 echo "Goodbye! Let's meet again in two weeks."
422 ```
423
424 ---
425 class: ex-shellpod
426
427 ```bash
428 #!/bin/sh
429
430 : <<'=cut'
431 *=head1 NAME
432 *
433 *therapist.sh - This script can save you a bunch of cash
434 *
435 *=cut
436
437 echo 'Hello. Now, tell me about your problems.'
438
439 while read response
440 do
441 printf "Patient said: %s" "$response" >>therapist_notes.txt
442
443 echo 'And how did that make you feel?'
444 done
445
446 echo "Goodbye! Let's meet again in two weeks."
447 ```
448
449 ???
450 It's pod! In a shell script.
451
452 ---
453 class: ex-shellpod
454
455 ```bash
456 #!/bin/sh
457
458 *: <<'=cut'
459 =head1 NAME
460
461 therapist.sh - This script can save you a bunch of cash
462
463 =cut
464
465 echo 'Hello. Now, tell me about your problems.'
466
467 while read response
468 do
469 printf "Patient said: %s" "$response" >>therapist_notes.txt
470
471 echo 'And how did that make you feel?'
472 done
473
474 echo "Goodbye! Let's meet again in two weeks."
475 ```
476
477 ???
478 This is the key right here. Anybody know what this is?
479
480 It's a heredoc.
481
482 The colon command in bourne shell is just noop. Sometimes you'll see the colon used as a type of comment, but unlike
483 a comment the shell does parse the arguments to colon.
484
485 ---
486 class: center, middle
487
488 ## Understand calling context.
489
490 ???
491 - One of the baffling things about Perl5 to newcomers is that subroutines can
492 do different things based on *where* they are used. This is called context.
493
494 ---
495 ## The three main contexts:
496 - Scalar
497 - List
498 - Void
499
500 ---
501 ## The wantarray() function
502 - True if caller called in **list** context.
503 - False if **scalar** context.
504 - `undef` if **void** context.
505
506 ???
507 Unfortunately this function was misnamed. It should have been "wantlist" since
508 there really is no "array context."
509
510 ---
511 class: ex-context
512
513 ## Example: localtime()
514
515 ```perl
516 @time = localtime(); # -> (1, 43, 13, 7, 5, 118, 4, 157, 1)
517 $time = localtime(); # -> "Thu Jun 7 13:43:01 2018"
518 ```
519
520 ---
521 class: ex-context
522
523 ## Operators help determine context.
524
525 --
526 ```perl
527 $thing_one . $thing_two
528 ```
529
530 ???
531 String concatenation is a scalar thing, so the concat operator "creates" a scalar context on either side.
532
533 --
534 ```perl
535 $income - $expenses
536 ```
537
538 ???
539 Numerical and comparison operators typically operator in the same way. So that's easy.
540
541 --
542 ### Scalar context on both sides.
543
544 ---
545 class: ex-context
546
547 ## Operators help determine context.
548
549 ```perl
550 !ready()
551 ```
552
553 ```perl
554 $count++
555 ```
556
557 ### Also evaluated in scalar context.
558
559 ???
560 - Generally the prefix and postfix operators also create scalar context.
561
562 ---
563 class: center, middle
564
565 ## The assignment operator... is different.
566
567 ???
568 What makes it different is that the assignment operator is really two different
569 operators in Perl 5.
570
571 ---
572 class: ex-context2
573
574 ## The scalar assignment operator
575
576 ```perl
577 $scalar = $another_scalar; # copy scalar on the right to the left
578 ```
579
580 --
581 ```perl
582 $scalar = @array;
583 ```
584
585 ---
586 class: ex-context2
587
588 ## The scalar assignment operator
589
590 ```perl
591 $scalar = $another_scalar; # copy scalar on the right to the left
592 ```
593
594 ```perl
595 $scalar = @array; # $scalar => length of @array
596 ```
597
598 ---
599 class: ex-context2
600
601 ## The scalar assignment operator
602
603 ```perl
604 $scalar = $another_scalar; # copy scalar on the right to the left
605 ```
606
607 ```perl
608 $scalar = @array; # $scalar => length of @array
609 ```
610
611 ```perl
612 $scalar = qw(list of things);
613 ```
614
615 ---
616 class: ex-context2
617
618 ## The scalar assignment operator
619
620 ```perl
621 $scalar = $another_scalar; # copy scalar on the right to the left
622 ```
623
624 ```perl
625 $scalar = @array; # $scalar => length of @array
626 ```
627
628 ```perl
629 $scalar = qw(list of things); # $scalar => "things"
630 ```
631
632 --
633 ### Lists and arrays are **not** the same thing!
634
635 ---
636 class: ex-context2
637
638 ## The list assignment operator
639
640 ```perl
641 @array = @another_array; # copy array on the right to the left
642 ```
643
644 --
645 ```perl
646 @array = $scalar;
647 ```
648
649 ---
650 class: ex-context2
651
652 ## The list assignment operator
653
654 ```perl
655 @array = @another_array; # copy array on the right to the left
656 ```
657
658 ```perl
659 @array = $scalar; # $scalar copied; @array has one item
660 ```
661
662 --
663 ```perl
664 @array = qw(list of things); # contents of list copied to @array
665 ```
666
667 ---
668 class: ex-context
669
670 ## Subroutines determine context of their parameters.
671
672 ```perl
673 sub i_can_haz_scalar :prototype($) {
674 say @_;
675 }
676
677 my @arr = qw(foo bar baz);
678 *i_can_haz_scalar(@arr);
679 ```
680
681 ???
682 Not only can subroutines branch and do different things based on the context
683 that calls them -- based on `wantarray()` -- they also control the context of
684 their parameters.
685
686 ---
687 class: ex-context
688
689 ## Subroutines determine context of their parameters.
690
691 ```perl
692 sub i_can_haz_scalar :prototype($) {
693 say @_;
694 }
695
696 my @arr = qw(foo bar baz);
697 *i_can_haz_scalar(@arr); # => 3
698 ```
699
700 ---
701 class: ex-context
702
703 ## Subroutines determine context of their parameters.
704
705 ```perl
706 sub i_can_haz_scalar :prototype($) {
707 say @_;
708 }
709
710 *i_can_haz_scalar(qw{2 4 6 8});
711 ```
712
713 ---
714 class: ex-context
715
716 ## Subroutines determine context of their parameters.
717
718 ```perl
719 sub i_can_haz_scalar :prototype($) {
720 say @_;
721 }
722
723 *i_can_haz_scalar(qw{2 4 6 8}); # => 8
724 ```
725
726 ???
727 Remember: Arrays and lists are no the same thing!
728
729 ---
730 class: ex-context
731
732 ## Be vigilant.
733
734 ```perl
735 my %account_details = (
736 first_name => (split / /, $user_name)[0],
737 job_title => fetch_job_title($user_name),
738 );
739 ```
740
741 ???
742 The reason it is important to understand contexts is because you will get
743 caught by gotchas if you don't.
744
745 Spot any potential problems here?
746
747 ---
748 class: ex-context
749
750 ## Be vigilant.
751
752 ```perl
753 my %account_details = (
754 first_name => (split / /, $user_name)[0],
755 * job_title => fetch_job_title($user_name),
756 );
757 ```
758
759 ```perl
760 sub fetch_job_title {
761 return; # -> ()
762 }
763 ```
764
765 --
766 ### Can use the `scalar` function to force scalar context.
767
768 ```perl
769 job_title => scalar fetch_job_title($user_name),
770 ```
771
772 ---
773 class: ex-context
774
775 ## Be vigilant.
776
777 ```perl
778 my %account_details = (
779 * first_name => (split / /, $user_name)[0],
780 job_title => fetch_job_title($user_name),
781 );
782 ```
783
784 ### `(split /regexp/, $str)[$index]` can evaluate to `()`!
785
786 ???
787 This is surprising, right? Usually when you have a post-circumfix index
788 operator on either a list or an array, even if you go out of bounds you'll get
789 an `undef`.
790
791 I should also mention that not only can things like this cause bugs that are
792 annoying and hard to find, there are security implications. If you're not aware
793 of how all the code within a hash declaration responds to being in list
794 context, you could potentially open the door for crafted user input to
795 overwrite completely unrelated keys in the hash.
796
797 ---
798 class: center, middle
799
800 ## Understand execution phases.
801
802 ---
803 ## Two main phases
804
805 - **Compile** phase
806 - **Run** phase
807
808 ???
809 That's easy enough. What's to know, right?
810
811 Well, it turns out that it's not so straightforward because unlike many other
812 languages, Perl can run code in the compile phase and compile code in the run
813 phase.
814
815 ---
816 class: ex-phases
817
818 ## Example script
819
820 ```perl
821 #!/usr/bin/perl
822
823 print "O hai.\n";
824 ```
825
826 ---
827 class: ex-phases
828
829 ## Example script
830
831 ```perl
832 #!/usr/bin/perl
833
834 *print "O hai.\n";
835 ```
836
837 ???
838 By the time this line executes we are already in the **run** phase.
839
840 So how do you actually run code in the compile phase?
841
842 ---
843 class: ex-phases
844
845 ## Run code in compile phase
846
847 ```perl
848 #!/usr/bin/perl
849
850 print "O hai.\n";
851
852 *BEGIN {
853 * print "Hello.\n";
854 *}
855 ```
856
857 ```
858 Hello.
859 O hai.
860 ```
861
862 ???
863 One way to run code in the compile phase is to create a `BEGIN` block.
864
865 ---
866 class: ex-phases
867
868 ## Run code in compile phase
869
870 ```perl
871 #!/usr/bin/perl
872
873 *use Data::Dumper qw(Dumper);
874
875 print Dumper({
876 picard => 'jean-luc',
877 kirk => 'james',
878 });
879 ```
880
881 ???
882 `use` statements are also fulfilled in the compile phase, so it doesn't matter
883 where they appear within the code.
884
885 Similarly, `no` statements are also performed at compile time.
886
887 --
888 ```perl
889 BEGIN {
890 require Data::Dumper;
891 Data::Dumper->import('Dumper');
892 }
893 ```
894
895 ???
896 A `use` statement is *almost* the equivalent of this here.
897
898 Also worth pointing out, the fact that code can be ran during the compile phase means that using the `-c` flag on an
899 untrusted script is not advised.
900
901 ---
902 class: ex-phases
903
904 ## Compile code in run phase
905
906 --
907 ### String `eval`!
908
909 ```perl
910 my $calculate_answer = eval q[
911 sub {
912 return ] . ($hgttg ? 42 : 7) . q[;
913 }
914 ];
915
916 print "The answer is ", $calculate_answer->(), ".\n";
917 ```
918
919 ???
920 String `eval` both compiles and runs strings as Perl code.
921
922 It gets a bad rap because of its security implications. Yes, generating code to compile and run on the fly, when based
923 on user input, must be done very carefully or not at all.
924
925 This technique is used by many Perl modules to "inline" optimized versions of their subroutines. For example, `Moo` and
926 `Moose` can generate constructors tailored for each class rather than always using one big constructor that can is able
927 to handle all the possibilities.
928
929 ---
930 ## Code blocks associated with execution phases
931
932 - `BEGIN` - Runs the block immediately after it is compiled.
933
934 --
935 - `CHECK` - Runs the block after the main compile phase and before the main run phase.
936
937 --
938 - `CHECKUNIT` - Same, but for each "unit" (file).
939
940 --
941 - `INIT` - Runs the block immediately before the main run phase.
942
943 --
944 - `END` - Runs the block at program end.
945
946 Source: [Know the phases of a Perl program’s execution](https://www.effectiveperlprogramming.com/2011/03/know-the-phases-of-a-perl-programs-execution/) by brian d foy
947
948 ???
949 By the way, it runs the blocks in a defined order, which is nice: `BEGIN` and `INIT` run in top to bottom order, while
950 the others run in the opposite order.
951
952 ---
953 class: center, middle
954
955 ## Know when to be terse and when not to.
956
957 ---
958 class: ex-obfuscated, center, middle
959
960 ```perl
961 @P=split//,".URRUU\c8R";@d=split//,"\nrekcah xinU / lreP rehtona tsuJ";sub p{
962 @p{"r$p","u$p"}=(P,P);pipe"r$p","u$p";++$p;($q*=2)+=$f=!fork;map{$P=$P[$f^ord
963 ($p{$_})&6];$p{$_}=/ ^$P/ix?$P:close$_}keys%p}p;p;p;p;p;map{$p{$_}=~/^[P.]/&&
964 close$_}%p;wait until$?;map{/^r/&&<$_>}%p;$_=$d[$q];sleep rand(2)if/\S/;print
965 ```
966
967 Source: [Just Another Perl / Unix Hacker](http://perl.plover.com/obfuscated/) by Mark Jason Dominus
968
969 ???
970 This is what terse code looks like. At least I think it is... If I knew what it was doing, I would probably conclude
971 that it is in fact terse.
972
973 But actually, it might not be. For all I know this could be a very roundabout and verbose way to accomplish the work
974 it's doing. I can't tell because it's too "obfuscated."
975
976 ---
977 class: center, middle
978
979 # obfuscation β‰  terseness
980
981 ???
982 The concepts of obfuscation and terseness are not materially equivalent.
983
984 Obfuscation is always bad (except in "toy" code like "Just another hacker" snippets and obfuscation challenges).
985 Terseness can be bad (if it's too obfuscated for the audience), but sometimes it can be better.
986
987 ---
988 class: ex-terse
989
990 ## Be terse without obfuscating
991
992 - Be idiomatic.
993
994 ```perl
995 @coordinates = @geodata[2, 3];
996 @coordinates = ($geodata[2], $geodata[3]);
997 $coordinates[0] = $geodata[2]; $coordinates[1] = $geodata[3];
998 ```
999
1000 ???
1001 Some language features are so common, they are idiomatic among users of the language even if the code may be somewhat
1002 perplexing to newcomers.
1003
1004 Here are three more-or-less equivalent ways to do the same thing. The first way, using and array slice, is
1005 definitionally the tersest. Is it too terse? Is it obfuscated?
1006
1007 In my subjective opinion, all three of these statements are equally fine. Array slicing is a language feature of Perl
1008 that doesn't exist in every other language, so it might perplex newcomers for a bit, but I think the intent is pretty
1009 clear even for those new to the syntax.
1010
1011 So this is a great place to be terse.
1012
1013 --
1014 - Terse code can actually be faster for humans to parse.
1015
1016 ???
1017 If only because there's less to read.
1018
1019 --
1020 - Talk to your peers (or downstream "users") and establish expectations.
1021
1022 ???
1023 Some language features and style may just be too perplexing, so pay attention to who will probably be working with your
1024 code in the future.
1025
1026 You don't always have to code for the lowest possible common denominator.
1027
1028 Example: A lot of code could be written in the functional style versus imperatively. Keep in mind that functional code
1029 is easier to read and write for math-minded programmers. Perl can do either, but which one you choose should depend more
1030 on who else is going to be working in your code rather than your own personal preference.
1031
1032 --
1033 - But **never** ever sacrifice clarity of intent for shorter code.
1034
1035 ???
1036 Anyway, I don't have any solid wisdom for you on this topic. Just be mindful.
1037
1038 ---
1039 class: center, middle
1040
1041 ## Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait).
1042
1043 ???
1044 If you have used JavaScript recently, you may have used its "async/await" feature to clean up your non-blocking code.
1045
1046 ---
1047 class: center, middle
1048
1049 ### Yes, Perl can do it, too!
1050
1051 ---
1052 class: ex-asyncawait
1053
1054 ## Without async and await
1055
1056 ```perl
1057 use Future;
1058
1059 sub do_two_things {
1060 return do_first_thing()->then(sub {
1061 my $first = shift;
1062
1063 return do_second_thing($first)->then(sub {
1064 my $second = shift;
1065
1066 return Future->done([$first, $second]);
1067 });
1068 });
1069 }
1070 ```
1071
1072 ---
1073 class: ex-asyncawait
1074
1075 ## With async and await
1076
1077 ```perl
1078 use Future::AsyncAwait;
1079
1080 async sub do_two_things
1081 {
1082 my $first = await do_first_thing();
1083
1084 my $second = await do_second_thing($first);
1085
1086 return [$first, $second];
1087 }
1088 ```
1089
1090 ???
1091 There are caveats: Localized variable assignments don't work, nor anything that has implied local-like behavior.
1092
1093 ---
1094 class: center, middle
1095
1096 ## Write your own boilerplate.
1097
1098 ---
1099 class: ex-boilerplate
1100
1101 ### The boilerplate can get unwieldy...
1102
1103 ```perl
1104 package My::Package;
1105
1106 use utf8;
1107 use warnings FATAL => 'all';
1108 use strict;
1109 use feature ':5.14';
1110 use open qw(:encoding(UTF-8) :std);
1111 use charnames qw(:full :short);
1112
1113 use Encoding qw(decode encode);
1114 use Function::Parameters;
1115 use Locale::TextDomain 'AppName';
1116 use Scalar::Util qw(blessed refaddr reftype weaken unweaken isweak);
1117 use Unicode::Normalize qw(NFC NFC);
1118 ```
1119
1120 In every file.
1121
1122 ---
1123 class: center, middle
1124
1125 ### Solution: Put all that junk in a separate package.
1126
1127 ---
1128 class: ex-boilerplate2
1129
1130 ```perl
1131 package My::boilerplate;
1132
1133 use Import::Into;
1134
1135 sub import {
1136 my $class = shift;
1137 my %args = @_;
1138
1139 my $target = caller;
1140
1141 feature ->import::into($target, qw{:5.14});
1142 strict ->import::into($target);
1143 warnings ->import::into($target, qw{FATAL all});
1144 utf8 ->import::into($target);
1145 open:: ->import::into($target, qw{:encoding(UTF-8) :std});
1146 charnames ->import::into($target, qw{:full :short});
1147
1148 Encode ->import::into($target, qw{decode encode});
1149 Function::Parameters->import::into($target);
1150 Locale::TextDomain ->import::into($target, $args{textdomain} || 'AppName');
1151 Scalar::Util ->import::into($target, qw{blessed refaddr reftype weaken unweaken isweak});
1152 Unicode::Normalize ->import::into($target, qw{NFD NFC});
1153 }
1154
1155 1;
1156 ```
1157
1158 ---
1159 class: ex-boilerplate2
1160
1161 ```perl
1162 package My::boilerplate;
1163
1164 *use Import::Into;
1165
1166 sub import {
1167 my $class = shift;
1168 my %args = @_;
1169
1170 my $target = caller;
1171
1172 feature ->import::into($target, qw{:5.14});
1173 strict ->import::into($target);
1174 warnings ->import::into($target, qw{FATAL all});
1175 utf8 ->import::into($target);
1176 open:: ->import::into($target, qw{:encoding(UTF-8) :std});
1177 charnames ->import::into($target, qw{:full :short});
1178
1179 Encode ->import::into($target, qw{decode encode});
1180 Function::Parameters->import::into($target);
1181 Locale::TextDomain ->import::into($target, $args{textdomain} || 'AppName');
1182 Scalar::Util ->import::into($target, qw{blessed refaddr reftype weaken unweaken isweak});
1183 Unicode::Normalize ->import::into($target, qw{NFD NFC});
1184 }
1185
1186 1;
1187 ```
1188
1189 ---
1190 class: ex-boilerplate
1191
1192 ### Use your boilerplate.
1193
1194 ```perl
1195 package My::Package;
1196
1197 use My::boilerplate;
1198
1199 sub say_hello {
1200 say __"Hello";
1201 }
1202
1203 1;
1204 ```
1205
1206 ???
1207 Now I can use `say` without having to use perl 5.10 in my package, and I can use gettext to translate my greeting.
1208 Warnings and strict are also enabled. All that stuff I need in every module is there.
1209
1210 ---
1211 class: ex-boilerplate
1212
1213 ## Tip: Add this to your project's `.perlcriticrc`.
1214
1215 ```ini
1216 [TestingAndDebugging::RequireUseStrict]
1217 equivalent_modules = My::boilerplate
1218 ```
1219
1220 ---
1221 class: center, middle
1222
1223 ## Write your own debugger.
1224
1225 ???
1226 Perl provides rather convenient mechanisms for hooking into the interpreter.
1227
1228 The idea for this topic, by the way, is from a lightning talk by rjbs in YAPC 2014. His talks are always entertaining,
1229 so look them up.
1230
1231 ---
1232 class: ex-owndebugger1
1233
1234 ```bash
1235 perl -d:MyFancyDebugger program.pl
1236 ```
1237
1238 ???
1239 This does at least two important things.
1240
1241 --
1242 ### `use Devel::MyFancyDebugger;`
1243 ### `$^P = 1855;`
1244
1245 ???
1246 `$^P` is a bitfield that lets you turn on and off various features related to debugging. The value 1855 isn't important;
1247 just know that using this flag turns on a lot of those bits.
1248
1249 ---
1250 class: ex-owndebugger2
1251
1252 ```perl
1253 package Devel::PackageOrder;
1254
1255 my %seen;
1256
1257 {
1258 package DB;
1259 sub DB {
1260 my ($package, $filename, $line) = caller;
1261 return if $seen{$package}++;
1262 print STDERR "Package: $package\n";
1263 }
1264 }
1265
1266 1;
1267 ```
1268
1269 ```bash
1270 perl -d:PackageOrder program.pl
1271 ```
1272
1273 ???
1274 As it happens, the second bit of `$^P` arranges for a subroutine named `DB::DB` to be called per statement.
1275
1276 ---
1277 class: ex-owndebugger2
1278
1279 ```perl
1280 package Devel::PackageOrder;
1281
1282 my %seen;
1283
1284 {
1285 * package DB;
1286 * sub DB {
1287 my ($package, $filename, $line) = caller;
1288 return if $seen{$package}++;
1289 print STDERR "Package: $package\n";
1290 }
1291 }
1292
1293 1;
1294 ```
1295
1296 ```bash
1297 perl -d:PackageOrder program.pl
1298 ```
1299
1300 ???
1301 So, for each statement that gets run in your program, this subroutine is called. My simple example here just does some
1302 simple things. It uses the `caller` function to figure out where the program is at in its execution.
1303
1304 The first item we get off of `caller` is the package name (actually we could also just call `caller` in scalar context
1305 to get just the package). Then, if we've seen the package before, we don't do anything, otherwise we print the name of
1306 the package.
1307
1308 So, this effectively tells us in what order packages
1309
1310 Is this useful? I don't know. I guess it useful at some point because I wrote it. The point is, you can write your own
1311 debuggers to do whatever useful thing you have need of, when you have the need.
1312
1313 And by the way, I've shown you the entirety of the debugger. There is no other code needed. It's really cool.
1314
1315 ---
1316 class: center, middle
1317
1318 ## Don't write your own debugger.
1319
1320 ???
1321 As you can imagine, there are a lot of awesome debuggers on CPAN already.
1322
1323 You should probably check before writing your own.
1324
1325 ---
1326 class: ex-develtrace
1327
1328 ## [`Devel::Trace`](https://metacpan.org/pod/Devel::Trace)
1329
1330 ```bash
1331 perl -d:Trace -e'print scalar localtime, "\n"'
1332 *>> -e:1: print scalar localtime, "\n"
1333 Thu Jun 7 20:43:57 2018
1334 ```
1335
1336 ---
1337 class: ex-develtrace
1338
1339 ## [`Devel::Trace::Syscall`](https://metacpan.org/pod/Devel::Trace::Syscall)
1340
1341 ```bash
1342 perl -d:Trace::Syscall=open -e'print scalar localtime, "\n"'
1343 Thu Jun 7 20:45:59 2018
1344 *open("/etc/localtime", 0x80000, 0666) = 3 at -e line 1.
1345 ```
1346
1347 ---
1348 class: ex-develtrace
1349
1350 ## [`Devel::NYTProf`](https://metacpan.org/pod/Devel::NYTProf)
1351
1352 ```bash
1353 perl -d:NYTProf -e'print scalar localtime, "\n"'
1354 Thu Jun 7 20:53:42 2018
1355 ```
1356
1357 ![NYTProf html report](img/nytprof.png)
1358
1359 ---
1360 class: ex-develtrace
1361
1362 ## [`Devel::Cover`](https://metacpan.org/pod/Devel::Cover)
1363
1364 ```bash
1365 cover -test
1366 ```
1367
1368 .cover-img[
1369 ![Cover html report](img/cover.png)
1370 ]
1371
1372 ---
1373 class: center, middle
1374
1375 ## Know the default perl5 debugger.
1376
1377 ???
1378 Of course those other debuggers are cool, but don't forget that perl also comes with its own general-purpose debugger.
1379 You should know it.
1380
1381 ---
1382 class: ex-debugger
1383
1384 ## `perl5db.pl`
1385
1386 ```bash
1387 perl -d program.pl
1388 Enter h or 'h h' for help, or 'man perldebug' for more help.
1389 DB<1>
1390 ```
1391
1392 --
1393 #### That's about it...
1394
1395 ???
1396 Obviously you can use it to step through code.
1397
1398 Anyway, I don't have much to say about it. Just use it.
1399
1400 ---
1401 class: center, middle
1402
1403 ## Write modern Perl.
1404
1405 ---
1406 class: ex-newfeatures
1407
1408 ## Try some newer perl5 features.
1409
1410 ```perl
1411 use v5.24;
1412 use feature qw(signatures); # available in v5.20
1413 no warnings qw(experimental::signatures);
1414
1415 my $missile_inventory = {
1416 ID => 20,
1417 WY => 25,
1418 CA => 195,
1419 };
1420
1421 sub get_default_silo_id () {
1422 return $_ if 0 < $missile_inventory->{$_} for (sort keys $missile_inventory->%*);
1423 die "No more missiles. :-(\n";
1424 }
1425
1426 sub launch_missile ( $silo_id = get_default_silo_id() ) {
1427 die "Silo is empty.\n" if $missile_inventory->{$silo_id} <= 0;
1428 $missile_inventory->{$silo_id} -= 1;
1429 say "Missile launched from silo $silo_id.";
1430 }
1431 ```
1432
1433 ---
1434 class: ex-newfeatures
1435
1436 ### Postfix dereferencing
1437
1438 ```perl
1439 use v5.24;
1440
1441 my $person = {
1442 name => 'Bob',
1443 associates => [
1444 {
1445 name => 'Karen',
1446 },
1447 {
1448 name => 'Doug',
1449 },
1450 ],
1451 }
1452
1453 my @others = $person->{associates}->@*;
1454 my %associate_attributes = $person->{associates}->@[0]->%*;
1455 ```
1456
1457 ### `@{...}` can be `->@*` at the end
1458 ### `%{...}` can be `->%*` at the end
1459
1460 ---
1461 class: ex-newfeatures2
1462
1463 ### Subroutine signatures
1464
1465 ```perl
1466 use v5.20;
1467 use feature qw(signatures);
1468 no warnings qw(experimental::signatures);
1469
1470 sub only_one_arg($foo) {
1471 }
1472
1473 sub other_args_allowed_and_ignored($foo, @) {
1474 }
1475
1476 sub positional_and_named($args, %other) {
1477 }
1478
1479 # etc.
1480 ```
1481
1482 ---
1483 class: ex-newfeatures2
1484
1485 ### Strip leading space in heredocs
1486
1487 ```perl
1488 use v5.26;
1489
1490 do {
1491 print <<~'HERE';
1492 Hi. The text here is indented in the source code,
1493 but not in the console!
1494 HERE;
1495 };
1496 ```
1497
1498 ---
1499 class: ex-moo
1500
1501 ## Use [`Moo`](https://metacpan.org/pod/Moo) and [`Moose`](https://metacpan.org/pod/Moose).
1502
1503 ```perl
1504 package ToySoldier;
1505
1506 use Function::Parameters;
1507 use Moo;
1508 use namespace::clean;
1509
1510 extends 'Toy';
1511
1512 with qw(HasSpear);
1513
1514 method fight($opponent) {
1515 $self->spear->thrust_at($opponent);
1516 }
1517
1518 1;
1519 ```
1520
1521 ???
1522 - Gives perl5 an improved object model.
1523 - It partially is just syntactic sugar, right? But these modules do provide a lot of value about perl5's own object
1524 model.
1525 - Attributes and a constructor.
1526 - Roles (a.k.a. mixins).
1527 - And if you use Moose, you get the whole metaobject as well.
1528 - The metaobject provides introspection and runtime altering of classes. It's powerful.
1529
1530 I'm not going to go any further into Moo or Moose, but do learn them and use them with a caveat: I don't know how anyone
1531 else feels about this, but I kinda like modules on CPAN that don't depend on Moo or especially Moose, because modules
1532 with fewer dependencies are just easier to work with generally. So, if you are releasing on CPAN, consider not depending
1533 on this. Or at least use Moo and not full Moose if you don't actually need the metaobject. Of course, in your own
1534 non-distributed programs, go all out.
1535
1536 ---
1537 class: center, middle
1538
1539 ## Learn Perl 6.
1540
1541 ![Camelia](img/camelia.png)
1542
1543 ???
1544 - It's easy to install and fun to play with.
1545
1546 ---
1547 class: center, middle
1548
1549 ## Go download it and just start playing around.
1550
1551 ### https://perl6.org/downloads/
1552
1553 (Really, do it.)
1554
1555 ---
1556 class: ex-perl6
1557
1558 ### Meta operators
1559
1560 ```perl
1561 [*] 1, 2, 3, 4, 5
1562 ```
1563
1564 ---
1565 class: ex-perl6
1566
1567 ### Meta operators
1568
1569 ```perl
1570 [*] 1, 2, 3, 4, 5 # -> 120
1571 ```
1572
1573 ???
1574 - This one is called the **reduce** meta operator.
1575 - Also notice that in Perl 6, you don't need to surround a list in parentheses.
1576
1577 --
1578 ```perl
1579 sub some-reducer($a, $b) { $a + $b }
1580
1581 [[&some-reducer]] 1 .. 5 # -> 15
1582 [+] 1 .. 5 # -> 15
1583 ```
1584
1585 ???
1586 - Can reduce using any binary operator.
1587 - Oh yeah, and you can use dashes in subroutine names.
1588
1589 ---
1590 class: ex-perl6
1591
1592 ### Meta operators
1593
1594 ```perl
1595 1, 3 ... 9
1596 2, 4, 8 ... 256
1597 ```
1598
1599 ???
1600 You've seen the dot dot operator, but check out dot dot dot!
1601
1602 ---
1603 class: ex-perl6
1604
1605 ### Meta operators
1606
1607 ```perl
1608 1, 3 ... 9 # -> 1, 3, 5, 7, 9
1609 2, 4, 8 ... 256 # -> 2, 4, 8, 16, 32, 64, 128, 256
1610 ```
1611
1612 --
1613 ```perl
1614 my @fib = 1, 1, -> $a, $b { $a + $b } ... *;
1615
1616 @fib[6] # -> 13
1617 @fib[3 .. 5] # -> 3, 5, 8
1618 @fib[^8] # -> 1, 1, 2, 3, 5, 8, 13, 21
1619 ```
1620
1621 ???
1622 - Of course you can do even awesomer things like create infinite lists with more complicated sequence logic.
1623 - The list elements are evaluated lazily.
1624
1625 ---
1626 class: ex-perl6
1627
1628 ### Create your own operators
1629
1630 ```perl
1631 sub postfix:<!>(Int $n) { [*] 2 .. $n }
1632
1633 5! # -> 120
1634 ```
1635
1636 ???
1637 Lots of languages (even perl5) allows you to override operators, but none come close to perl6 in functionality.
1638
1639 --
1640
1641 Types of operators you can create in Perl 6:
1642
1643 - Prefix (like `!` as in `!True`)
1644 - Postfix (like `++` in `$num++`)
1645 - Infix (like `+` in `1 + 2`)
1646 - Circumfix (like `[]` in `[1, 2]`)
1647 - Post-circumfix (like `[]` in `@array[5]`)
1648
1649 ---
1650 class: ex-perl6
1651
1652 ### Destructure your structures
1653
1654 ```perl
1655 sub salut(% (:name($name), :title($title))) {
1656 say "Hello there, $name the $title!";
1657 }
1658
1659 salut({name => 'Bob', title => 'Consultant'});
1660
1661 my %person = {name => 'Jean Luc', title => 'Captain'};
1662 salut(%person);
1663 ```
1664
1665 ???
1666 I guess the first thing to say is that, yes, Perl 6 has function signatures.
1667
1668 As this example shows, you can also do nifty stuff like destructure.
1669
1670 ---
1671
1672 ### Other cool stuff in Perl 6
1673
1674 - Sigils that make [more] sense.
1675
1676 --
1677 - A real object model.
1678
1679 --
1680 - Types! -- If you want.
1681
1682 --
1683 - Multiple dispatch for subroutines.
1684
1685 --
1686 - Control over passing semantics.
1687
1688 ???
1689 - Args are immutable by default, but can be set to copy or be mutable (like perl5 aliasing).
1690
1691 --
1692 - Lambdas
1693
1694 ---
1695
1696 ## Summary
1697
1698 .col[
1699 - Use [`B::Deparse`](https://metacpan.org/pod/B::Deparse).
1700 - Know regular expressions.
1701 - Use [`Regexp::Debugger`](https://metacpan.org/pod/Regexp::Debugger).
1702 - Write Vim plugins in Perl.
1703 - Document your shell scripts with pod.
1704 - Understand calling context.
1705 - Understand execution phases.
1706 - Know when to be terse and when not to.
1707 ]
1708
1709 .col[
1710 - Use [`Future::AsyncAwait`](https://metacpan.org/pod/Future::AsyncAwait).
1711 - Write your own boilerplate.
1712 - Write your own debugger.
1713 - Don't write your own debugger.
1714 - Know the default perl debugger.
1715 - Write modern Perl.
1716 - Learn Perl 6.
1717 ]
1718
1719 ---
1720
1721 ## Other topics
1722 - Learn XS.
1723 - Learn Unicode.
1724 - Learn another language.
1725 - Learn software design patterns.
1726
1727 ---
1728 class: center, middle
1729 name: conclusion
1730
1731 ## Conclusion:
1732
1733 ### Perl is fun.
1734
1735 ---
1736 class: center, middle
1737 name: last
1738
1739 .col.sep[
1740 ## Thank you
1741
1742 Email me: Charles McGarvey
1743 <chazmcgarvey@brokenzipper.com>
1744
1745 .talkqr.center[
1746 Leave me feedback, if you want:
1747
1748 ![Page on Joind.in](img/talkqr.svg)
1749
1750 <https://joind.in/talk/66955>
1751 ]
1752 ]
1753
1754 .col[
1755 ## Credits
1756
1757 .left[
1758 - Thanks rjbs for your inspiring talks.
1759 - Thanks brian d foy for your instructive articles.
1760 - Thanks Damian Conway, Paul Evans, et al. for writing and sharing cool modules.
1761 - Thanks Larry Wall for Perl.
1762 ]
1763 ]
1764
1765 </textarea><script src="https://gnab.github.io/remark/downloads/remark-latest.min.js"></script><script>var slideshow = remark.create({countIncrementalSlides: true, highlightLanguage: '', highlightLines: true, ratio: '16:9', /*slideNumberFormat: '',*/ navigation: {scroll: false, touch: false, click: false}})</script><script src="js/common.js"></script><script src="js/slides.js"></script></body></html>
1766 <!-- vim: set ts=4 sts=4 sw=4 tw=120 et ft=markdown nowrap: -->
This page took 0.110723 seconds and 4 git commands to generate.