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