/
js-nutshell.pod6
413 lines (298 loc) · 10.7 KB
/
js-nutshell.pod6
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
=begin pod :tag<convert>
=TITLE Perl 6 from Node.js - Nutshell
=SUBTITLE Learning Perl 6 from Node.js, in a nutshell.
This page attempts to provide a way for users experienced in Node.js to learn
Perl 6. Features shared between the two languages will be explained here, as
well as major differences in syntax and features.
This is not a tutorial for learning Perl 6; this is a reference for users who
are already at an intermediate to advanced skill level with Node.js.
=head1 Basic Syntax
=head2 "Hello, world!"
Let's start with the typical first program when learning new languages. In
Node.js, a hello world program would be written like this:
=begin code :lang<javascript>
console.log('Hello, world!');
=end code
Here are a couple ways to write this in the same way in Perl 6:
=begin code
say('Hello, world!');
say 'Hello, world!';
=end code
Parentheses are optional for function calls in Perl 6. While semicolons are,
for the most part, optional in Node.js, they are mandatory for expressions in
Perl 6.
Now that we've greeted the world, let's greet our good friend, Joe. We'll
start with Node.js again:
=begin code :lang<javascript>
let name = 'Joe';
console.log('What\'s up,' + name + '?');
console.log(`What's up, {name}?`);
console.log("What's up, ", name, "?");
=end code
Since he didn't hear us, let's greet him again, this time in Perl 6:
=begin code
my $name = 'Joe';
say 'What\'s up, ' ~ $name ~ '?';
say "What's up, $name?";
say "What's up, ", $name, "?";
=end code
Here, there are only a couple differences: most variables in Perl 6 have what
are called sigils, which are what the C<$> in front of its name is, and string
concatenation uses the C<~> operator instead of C<+>. What the two languages
share in common here is support for string interpolation.
Now that the basic examples are out of the way, let's explain the similarities
between the two languages in greater detail.
=head2 Variables
Variables in Node.js can be defined like this;
=begin code :lang<javascript>
var foo = 1; // Lexically scoped with functions and modules
let foo = 1; // Lexically scoped with blocks
const foo = 1; // Lexically scoped with blocks; constant
global.foo = 1; // Dynamically scoped; global
foo = 1; // Ditto, but implicit; forbidden in strict mode
=end code
In Perl 6 there is no equivalent to C<var>. An important note to make is that
there is no variable hoisting in Perl 6; variables are defined and assigned
at the line they're on, not defined at the top of its scope and later assigned
at that line.
This is how the equivalent types of variables are defined in Perl 6:
=begin code
my $foo = 1; # Lexically scoped with blocks
our $foo = 1; # Lexically scoped with blocks and modules
constant foo = 1; # Lexically scoped with blocks and modules; constant
my $*foo = 1; # Dynamically scoped with blocks
OUR::<$foo> = 1; # Dynamically scoped with blocks and modules
GLOBAL::<$foo> = 1; # Dynamically scoped; global
=end code
Use C<my> where you'd use C<let>, C<our> for variables you'd define in the
outermost scope needed, and C<constant> where you'd uses C<const>.
Dynamically scoped variables are not referred to in the same way as lexically
scoped ones like they are in Node.js. User-defined ones use either a C<$*>,
C<@*>, C<%*>, or C<&*> twigil. Refer to the documentation on
L<variables|/language/variables> for more information on sigils, twigils, and
variable containers.
Variables in Node.js can override others from outer scopes with the same name
(though linters will usually complain about it depending on how they're
configured):
=begin code :lang<javascript>
let foo = 1;
function logDupe() {
let foo = 2;
console.log(foo);
}
logDupe(2); // 2
console.log(foo); // 1
=end code
Perl 6 also allows this:
=begin code
my $foo = 1;
sub log-dupe {
my $foo = 2;
say $foo;
}
log-dupe; # 2
say $foo; # 1
=end code
=head2 Operators
=head3 Assignment
The C<=> operator works the same across both languages.
The C<:=> operator in Perl 6 binds a value to a variable. Binding a variable
to another variable gives them the same value and container, meaning mutating
attributes of one will mutate the other's as well. Bound variables cannot be
reassigned with C<=> or mutated with C<++>, C<-->, etc. but they can be bound
to another value again:
=begin code
my %map; # This is a hash, roughly equivalent to a JS object or map
my %unbound = %map;
my %bound := %map;
%map<foo> = 'bar';
say %unbound; # {}
say %bound; # {foo => bar}
%bound := %unbound;
say %bound; # {}
=end code
=head3 Equality
Node.js has two equality operators: C<==> and C<===>.
C<==> is the loose equality operator. When comparing operands with the same
type, it will return true if both operands are equal. However, if the
operands are different types, they are both cast to their primitives before
being compared, meaning these will return true:
=begin code :lang<javascript>
console.log(1 == 1); // true
console.log('1' == 1); // true
console.log([] == 0); // true
=end code
Similarly, in Perl 6, both operands are cast to Numeric before comparison if
they don't share the same type:
=begin code
say 1 == 1; # True
say '1' == 1; # True
say [1,2,3] == 3; # True, since the array has three elements
=end code
The inverse of C<==> is C<!=>.
Perl 6 has another operator similar to C<==>: C<eq>. Instead of casting operands
to Numeric if they're different types, C<eq> will cast them to strings:
=begin code
say '1' eq '1'; # True
say 1 eq '1'; # True
=end code
The inverse of C<eq> is C<ne> or C<!eq>.
C<===> is the strict equality operator. This returns true if both operands are
the same value. When comparing objects, this will I<only> return true if they
are the exact same object:
=begin code :lang<javascript>
console.log(1 === 1); // true
console.log('1' === 1); // false
console.log({} === {}); // false
let obj = {};
let obj2 = obj;
console.log(obj === obj2); // true;
=end code
In Perl 6, the operator behaves the same, with one exception: two objects that
have the same value, but different containers, will return false:
=begin code
say 1 === 1; # True
say '1' === 1; # True
say {} === {}; # False
my \hash = {};
my %hash := hash;
say hash === %hash; # False
=end code
The inverse of C<===> is C<!==>.
This is where Perl 6's other equality operators are useful. If the values have
different containers, the C<eqv> operator can be used. This operator can be also
be used to check for deep equality, which you would normally need to use a
library for in Node.js:
=begin code
say {a => 1} eqv {a => 1}; # True;
my \hash = {};
my %hash := hash;
say hash eqv %hash; # True
=end code
In the case you need to check if two variables have the same container and
value, use the C<=:=> operator.
=begin code
my @arr = [1,2,3];
my @arr2 := @arr; # Bound variables keep the container of the other variable
say @arr =:= @arr2; # True
=end code
=head3 Smart Matching
Perl 6 has one last operator for comparing values, but it is not exactly an
equality operator. This is C<~~>, the smart match operator. This has several
uses: it can be used like C<instanceof> in Node.js, to match a regex, and to
check if a value is a key in a hash, bag, set, or map:
=begin code
say 'foo' ~~ Str; # True
my %hash = a => 1;
say 'a' ~~ %hash; # True
my $str = 'abc';
$str ~~ s/abc/def/; # Mutates $str, like foo.replace('abc', 'def')
say $str; # def
=end code
While we are talking about C<instanceof>, the equivalent to C<typeof> or the
C<constructor> property on Node.js objects in Perl 6 is the C<^name> meta-attribute:
=begin code :lang<javascript>
console.log(typeof 'foo'); // string
console.log('foo'.constructor); // String
=end code
=begin code
say 'foo'.^name; # Str
=end code
=head3 Numeric
Node.js has C<+>, C<->, C</>, C<*>, C<%>, and (in ES6) C<**> for numeric
operators. When the operands are different types, similarly to the equality
operators, are cast to their primitives before following through with the
operation, making this possible:
=begin code :lang<javascript>
console.log(1 + 2); // 3
console.log([] + {}); // [object Object]
console.log({} + []); // 0
=end code
In Perl 6, again, they are converted to a Numeric type, as before:
=begin code
say 1 + 2; # 3
say [] + {}; # 0
say {} + [1,2,3]; # 3
=end code
In addition, Perl 6 has C<div> and C<%%>. C<div> behaves like C<int> division in
C, while C<%%> checks if one number is cleanly divisible by another or not:
=begin code
say 4 div 3; # 1
say 4 %% 3; # False
say 6 %% 3; # True
=end code
=head3 Bitwise
Node.js has C<&>, C<|>, C<^>, C<~>, C«<<», C«>>», C«>>>», and C<~> for bitwise
operators:
=begin code :lang<javascript>
console.log(1 << 1); // 2
console.log(1 >> 1); // 0
console.log(1 >>> 1); // 0
console.log(1 & 1); // 1
console.log(0 | 1); // 1
console.log(1 ^ 1); // 0
console.log(~1); // -2
=end code
In Perl 6, there is no equivalent to C«>>>». All bitwise operators are
prefixed with C<+>, however two's complement uses C<+^> instead of C<~>:
=begin code
say 1 +< 1; # 2
say 1 +> 1; # 0
# No equivalent for >>>
say 1 +& 1; # 1
say 0 +| 1; # 1
say 1 +^ 1; # 0
say +^1; # -2
=end code
=head3 Custom Operators and Operator Overloading
Node.js does not allow operator overloading without having to use a Makefile or
build Node.js with a custom version of V8. Perl 6 allows custom operators and
operator overloading natively! Since all operators are subroutines, you can
define your own like so:
=begin code
multi sub infix:<||=>($a, $b) is equiv(&infix:<+=>) { $a || $b }
my $foo = 0;
$foo ||= 1;
say $foo; # 1
=end code
Operators can be defined as C<prefix>, C<infix>, or C<postfix>. The
C<is tighter>, C<is equiv>, and C<is looser> traits optionally define the
operator's precedence. In this case, C<||=> has the same precedence as C<+=>.
Note how C<multi> is used when declaring the operator subroutines. This allows
multiple subroutines with the same name to be declared while also having
different signatures. This will be explained in greater detail in the
L<Functions|#Functions> section. For now, all we need to know is that it allows
us to override any native operator we want:
=begin code
# Using the `is default` trait here forces this subroutine to be chosen first,
# so long as the signature of the subroutine matches.
multi sub prefix:<++>($a) is default { $a - 1 }
my $foo = 1;
say ++$foo; # 0
=end code
=head2 Conditionals
=comment TODO
# TBD
=head2 Control Flow
=comment TODO
# TBD
=head2 Functions
=comment TODO
# TBD
=head2 Types
=comment TODO
# TBD
=head1 Object-Oriented Programming
=comment TODO
# TBD
=head1 The Networking API
=comment TODO
# TBD
=head1 The File System API
=comment TODO
# TBD
=head1 Modules and Packages
=comment TODO
# TBD
=end pod
# vim: expandtab softtabstop=4 shiftwidth=4 ft=perl6