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