-
Notifications
You must be signed in to change notification settings - Fork 0
/
01-intro-to-julia.jl
1315 lines (928 loc) · 34.9 KB
/
01-intro-to-julia.jl
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
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
### A Pluto.jl notebook ###
# v0.20.3
using Markdown
using InteractiveUtils
# ╔═╡ 1f443df9-619d-40c7-9e08-497ae1a08b5d
import Pkg; Pkg.activate(Base.current_project(), io=devnull)
# ╔═╡ 1e47e383-b735-4c57-a300-2afe8491b49a
using PlutoUI; TableOfContents()
# ╔═╡ 40abc83f-b4bd-479f-8671-189cc712d792
using Measurements
# ╔═╡ 88ca2a73-6203-447c-afcc-9e370a82076b
using Unitful
# ╔═╡ d1366a55-b4fc-4ddb-b5c2-5f3381c48b49
html"<button onclick='present()'>present</button>"
# ╔═╡ 12b0d664-3182-4e79-bdd4-4f6d85c51e5f
md"""
## Introduction
"""
# ╔═╡ 9186f984-7ab4-48b3-aef4-4d17505b9a74
md"""
### Historical Context
Twenty-six years ago at ADASS VI, Harrington and Barrett hosted a Birds-of-a-Feather session entitled "Interactive Data Analysis Environments". Based on their review of over a dozen interpreted programming languages such as Glish, GUILE, IDL, IRAF, Matlab, Perl, Python, and Tcl; they recommended that Python be considered the primary language for astronomical data analysis. The primary reasons were that the language was simple to learn, yet powerful; well supported by the programming community; and had FORTRAN-like arrays. However, for good performance, the multi-dimensional arrays needed to be written in a compiled language, namely C. So Numerical Python suffered from the "two language problem".
"""
# ╔═╡ 5b0d92aa-617e-48ae-8633-29c44bd809e0
md"""
### Why Julia?
In about 2009, four faculty members at MIT, who were not satisfied with the state of scientific computing, decided to develop a high performance, scientific programming language. After ten years of development, they release Julia Version 1.0 on August 8, 2018. Their aims were to create an open-source interpreted language that was concise, extensible, and high performance.
"""
# ╔═╡ 473d902f-3555-4306-b2c0-6fcddb6ecb59
md"""
### What Differentiates Julia From Other Languages?
* Julia is **composable**.
* Julia is **concise**.
* Julia is **high performance**.
* Julia is **productive**.
* Julia is **easy to maintain**.
* Julia is **free and open-source**.
"""
# ╔═╡ 09193424-25b9-45ce-840f-f24bbcc46c9d
md"""
### Why Have I migrated to Julia?
Although an early advocate and developer of Numerical Python, I knew its limitations, namely, the two language problem. Therefore, once a better scientific programming language came along, I was prepared to migrate to it. Julia is that language.
"""
# ╔═╡ b1ed2c4e-f5fa-4e5e-87d8-7af6f80a83ca
md"""## Getting Started"""
# ╔═╡ 7f3357bc-4103-4a35-af21-9c86f5a0ec2f
md"""
**===================================================================================**
### Starting Julia
Enter `julia` at the terminal prompt. Set the number of threads to `auto`. Threads will be discussed later in Parallel Computing.
```
> julia --threads=auto
_
_ _ _(_)_ | Documentation: https://docs.julialang.org
(_) | (_) (_) |
_ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help.
| | | | | | |/ _` | |
| | |_| | | | (_| | | Version 1.10.0 (2023-12-25)
_/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release
|__/ |
julia>
```
!!! tip
The command line option "-q" can be used to remove the start-up banner.
"""
# ╔═╡ 7475c896-d1b1-4429-9ba8-8e78de41e0b0
md"""
**===================================================================================**
### Stopping Julia
To exit Julia, enter `<Ctrl-D>` or `exit()`
```julia-repl
julia> <Ctrl-D>
```
!!! tip
Don't do this now!
"""
# ╔═╡ 5df8264e-6e37-4674-abdf-2b05c530787f
md"""
**===================================================================================**
### The command line or REPL (Read-Eval-Print-Loop)"""
# ╔═╡ f646ca14-c01e-47ee-8e2b-052d9db0985b
md"""
Our first command:
```julia
println("Hello World")
```
"""
# ╔═╡ 4a404280-2845-4deb-8eee-2dcdcb9aed27
# ╔═╡ 7813824a-cae9-4b97-ac90-e542fbd630d5
md"""
!!! note
Unlike Jupyter and the REPL, Pluto prints the result above the line, not below.
Our first calculation
```julia
a = 4
```
"""
# ╔═╡ 6ac51e87-87a2-4ccc-9f08-0028700b3cda
# ╔═╡ 27208179-35c3-43c1-9548-3620c8aa7680
md"""
```julia
b = 2
```
"""
# ╔═╡ 40d8d18c-3713-4e77-812d-9d77a4e1ac50
# ╔═╡ aa3e9db7-49d1-40f8-b745-6c4faa2197e1
md"""
```julia
a + b
```
"""
# ╔═╡ 756d3f69-a5b2-4ee6-bae6-94c513baae6c
# ╔═╡ 419a6dec-1db0-477f-911f-049223b5674f
md"""
**===================================================================================**
### Other REPL Modes
#### Help, '?'
For help mode,
```julia-repl
julia> ?
help?> println
search: println printstyled print sprint isprint
println([io::IO], xs...)
Print (using print) xs to io followed by a newline. If io is not supplied, prints to the default output stream stdout.
See also printstyled to add colors etc
Examples
≡≡≡≡≡≡≡≡≡≡
julia> println("Hello, world")
Hello, world
julia> io = IOBuffer();
julia> println(io, "Hello", ',', " world.")
julia> String(take!(io))
"Hello, world.\n"
```
Enter 'delete' or 'backspace' to exit help"""
# ╔═╡ 98340265-f51e-47a0-95d2-df179b87f54b
# ╔═╡ 8ee7f43d-bf75-4975-ac64-54c2d5a0174a
md"""
#### Shell, ';'
For shell mode,
```julia-repl
julia> ;
shell> pwd
/Users/myhomedir
```
Enter 'delete' or 'backspace' to exit shell
"""
# ╔═╡ d4368e22-60c6-456a-94a5-56e6dfdb26d7
# ╔═╡ d1e9c51c-efb9-4dcb-9d28-8c54a235fbb4
md"""
#### Package Manager, `]`
```julia-repl
julia> ]
pkg>
```
For package manager help,
```julia-repl
pkg> ? `return`
```
Returns a brief summary of package commands
To add a package,
```julia-repl
pkg> add <package>
pkg> add <package1> <package2>
```
When adding a package, the Julia on-line repository will be searched. The package and its dependencies will then be downloaded, compiled, and installed. This may take anywhere from a few seconds to a few minutes depending on the size of the package and its dependencies.
To use or load a package (after it has been added),
```julia-repl
julia> using <package>
julia> using <package1>, <package2>
```
A feature of the 'using' command is that it will add the package, if it hasn't alaredy been added.
"""
# ╔═╡ 948b4044-aee8-4b21-b9a5-4949adb9e01e
# ╔═╡ b27578b2-f5f5-4e46-82e6-0007be187ba6
md"""
To check the manifest:
```julia-repl
pkg> status
```
or
```julia-repl
pkg> st
```
"""
# ╔═╡ 1a95f9e5-77a3-46d0-9d4d-b28fbb0abf26
# ╔═╡ 065265a5-c9ad-4a39-b14d-f4e2e49d3f7a
md"""
To update a package in the manifest:
```julia-repl
pkg> update <package>
```
or
```julia-repl
pkg> up <package>
```
To update all packages in the manifest,
```julia-repl
pkg> up
```
To garbage collect packages not used for a significant time,
```julia-repl
pkg> gc
```
"""
# ╔═╡ 563f07ad-6aed-495e-85fb-bae4a1755ac2
md"""
-----------------------------------------------------------------------------------
The Measurements package enables variables to have both values and errors.
Let's add the Measurements package using the `using` statement.
"""
# ╔═╡ 297cd86c-5e9d-4f70-b11a-cbae8fa96d1e
md"""
Let's do some more calculations.
```julia
m1 = measurement(4.5, 0.1)
```
"""
# ╔═╡ 8f016c75-7768-4418-8c57-100db3073c85
# ╔═╡ 094b6f30-cbd6-46b1-8e0c-3fdb1ef18261
md"""Typing 'measurements' is rather awkward. There must be a better way. How about the following?
```julia
m2 = 15 ± 0.3
```
where the plus-minus character is entered using LaTeX syntax followed by tab, i.e., \pm<tab>.
"""
# ╔═╡ 7ba8dc19-e0ca-40de-a778-7583ca70978d
# ╔═╡ 668abc35-fdc3-430f-8c90-de3c2c2cd77b
md"""
One of the features of Julia is that it understands unicode. For example, expressions in a printed document that contain greek characters can be entered as greek characters in your code. Let's calculate the following expression.
```julia
α = m1 + m2
```
"""
# ╔═╡ 232cc444-03b7-442a-8737-8b7725b43421
# ╔═╡ d2a2d0bc-e883-439f-8e34-166e2369caef
md"""
!!! note
Notice that the error of the result α has been propogated correctly.
Let's add another package called Unitful, which enables attaching units to variables.
"""
# ╔═╡ c24f1ddd-5e31-4073-a627-86cedb1d44c2
md"""
Now let's create two new values `m3` and `m4` with units attached, and then multiply them together to create a third variable `β`.
```julia
m3 = (32 ± 0.1)u"m/s"
```
```julia
m4 = (9.8 ± 0.3)u"s"
```
```julia
β = m3 * m4
```
"""
# ╔═╡ 63a4b27a-5361-4d95-8787-ae31ca7987fe
# ╔═╡ 15674bb0-2fe1-40b1-a6c0-3a5a64a6a5c3
# ╔═╡ 70f08712-002c-4adc-84b1-73a8655d8a44
# ╔═╡ 3fa06ac2-20f3-4df4-8ce3-b0e1c21ca842
2pi
# ╔═╡ cf4a0e8f-9210-4f1e-84d4-ee7ff09aaf61
md"""
The variable `β`'s value now has an associated error and unit.
Let's see if this works with one dimensional arrays or vectors.
```julia
γ = [10 ± 0.1, 20 ± 0.2, 30 ± 0.3]u"m/s" .* [15 ± 0.01, 25 ± 0.02, 25 ± 0.03]u"s"
```
Note the dot '`.`' before the multiplication character '`*`'. This means element-wise multiplication. Whereas the multiplication character '`*`' by itself means matrix multiplication. If you are coming from Python, this difference may take a little time.
"""
# ╔═╡ e00b826d-1bbb-4413-a907-eb181369526b
# ╔═╡ b56255c6-9d3b-4e2f-a9a0-c6fe69990f3d
md"""
!!! note
What have we learned about the Julia command line and features?
* Julia has four command line modes: **REPL**, **help**, **shell**, and **package manager**.
* Julia understands **unicode**.
* Julia packages are **composable**. It means that independent packages are compatible and work together without modification, as demonstrated by the Measurements and Unitful packages.
"""
# ╔═╡ 5cd072cb-5d71-4a08-8e41-4eaaa7faaa5c
md"""
**===================================================================================**
## Language Basics
Because of Julia's multiple dispatch, types and functions are loosely bound. Thus, it is not a true object-oriented language, where functions are selected for execution using single dispatch. Multi-dispatch will be explained later when we dicsuss functions.
"""
# ╔═╡ f37bc13e-fa91-4166-983b-fd13a8493435
md"""
**===================================================================================**
### Comments
A comment string begins with a "`#`" and extends to the end of the line.
A comment block begins with "`#=`" and ends with "`=#`".
"""
# ╔═╡ 0d0c11c0-d39f-462c-9fb6-ab90ca98d230
md"""
**===================================================================================**
### Types
The optional type operator "::" is used to specify a type to expressions and variables, especially when writing functions. If no type is specified, Julia will infer the type based on context.
There are two primary reasons for type annotation:
1. As an assertion to confirm that the code is working properly, and
2. To provide extra type information to the compiler to improve performance.
"""
# ╔═╡ a02bbbbb-6b3f-47ef-a11f-1db9b802db6f
md"""
```julia
(1+2)::Float32
```
```julia
(1+2)::Int
```
Let's see how this works. Try the above examples.
"""
# ╔═╡ 2262c860-c06c-4293-8e6d-b616228cb301
# ╔═╡ 68e64f74-8a6b-403e-a404-52fb9cdea54b
# ╔═╡ 0887eca0-6760-4d9b-b44e-d1a14059aede
md"""Julia has various categories of types within a type-hierarchy. The following are some of the more common types.
!!! note
Types should be capitalized.
"""
# ╔═╡ 0ad9aa76-f6c7-4368-8ae4-58daa548e065
md"""
#### Abstract Types
"`abstract type`" declares a type that cannot be instantiated, and serves only as a node in the type graph, thereby describing sets of related concrete types.
Let's create an abstract type.
```julia
abstract type Widget end
```
"""
# ╔═╡ 1bc3da9e-143c-489c-b8de-a29dc48f17cb
# ╔═╡ f00dd72a-8705-426b-9eb4-b91cf1ea95d4
md"""
And some Widget subtypes using the subtype operator "`<:`".
```julia
abstract type Round <: Widget end
abstract type Square <: Widget end
```
"""
# ╔═╡ d308df6b-14ec-49ec-8270-a3b9efd88517
# ╔═╡ 01805f02-f9f6-4e3e-8e93-a0628753130f
# ╔═╡ a90b9011-714e-41d1-b7a3-fb3eb9dc56da
md"""
The subtype and supertype of a type can be shown using the functions "subtype" and "supertype".
Show the supertype and subtypes of Widget.
"""
# ╔═╡ 5f19b06a-1fe5-45d7-9996-b073394c91af
md"""
```julia
supertype(Round)
```
"""
# ╔═╡ b8325403-9744-4a9d-ae64-be88671da89b
# ╔═╡ dd9d05aa-9150-4a3a-9336-86aa74ee6e39
md"""
```julia
subtypes(Widget)
```
"""
# ╔═╡ 4879dae5-442e-4dc6-90c9-366ff76912bb
# ╔═╡ e2e57f49-f848-468a-a6f5-482b6e1ad4ba
typeof(1)
# ╔═╡ 4c278c5a-3324-4245-8ddf-f5390167168f
md"""
!!! note
The "Any" type is at the top of the hierarchy. It is the union of all types. In other words, it is the root node.
When the type of an expression or variable cannot be inferred from the context, the type defaults to "Any".
"""
# ╔═╡ 3772a828-561d-4600-8e67-49a28cc6cf09
md"""
#### Primitive Types
A primitive type is a concrete type whose data consists of plain old bits. Classic examples of primitive types are integers and floating-point values. Unlike most languages, Julia lets you declare your own primitive types, rather than providing only a fixed set of built-in ones.
Let's see what primitive types Integer and AbstractFloat contain.
```julia
subtypes(Integer)
```
"""
# ╔═╡ aa4a7ec0-a270-482b-abeb-7168de767938
# ╔═╡ b8e3b72a-e501-4164-b06c-cbb3282d9d11
md"""
```julia
subtypes(Signed)
```
"""
# ╔═╡ d9aa9f5e-31b6-49a3-bae8-a9b149e6ab91
# ╔═╡ 15b0159b-9c8c-4327-b73d-d7e19decde2a
md"""
```julia
subtypes(AbstractFloat)
```
"""
# ╔═╡ 5d5b1283-043b-437a-afda-75801808acc9
# ╔═╡ 6a6b2a0a-6bb6-4a67-b4c1-46631503918d
md"""Theoretically, a primitive type can have any number of bits, e.g., 5 or 17. Practically, the number of bits is constrained to multiples of 8. This is a limitation of the LLVM compiler, not Julia. So the Bool type is 8 bits, not 1 bit.
"""
# ╔═╡ 877faa74-7490-44a3-9e97-b36b36050796
md"""
#### Characters (`' '`) vs. Strings (`" "`)
Unlike Python, single and double quotes have different meanings. Single quotes create characters. Double quotes create strings. The reason for this is Unicode.
```julia
'j'
```
"""
# ╔═╡ bba18435-d355-4fca-a6f5-10dacde17413
# ╔═╡ d9e911a8-13f9-41e5-ac36-4aee3ec24c59
md"""
```julia
Char(167)
```
Or
```julia
'\u00A7'
```
"""
# ╔═╡ 5f72777b-a174-453c-8b18-ebf1f4bebe0d
# ╔═╡ 734a4185-4001-410f-affc-71b33e339339
# ╔═╡ c349f7b8-bdf0-4b94-b412-06c5e7f3cbc5
md"""
```julia
"This is a string"
```
"""
# ╔═╡ d8be9383-fb60-4938-9376-f91d59f21559
# ╔═╡ 31dfb05b-ed87-48f9-a74c-0055e46de160
md"""
Triple quotes work the same as in Python.
```julia
\"""
This is line 1.
This is line 2.
\"""
```
Try it.
"""
# ╔═╡ d2ada743-b82d-47c8-9b1d-4bd56de76e62
# ╔═╡ ea15815e-0ae3-4f22-9dce-a17cb3a0560b
md"""
#### Composite Types
Composite types are called records, structs, or objects in various languages. A composite type is a collection of named fields, an instance of which can be treated as a single value.
In mainstream object oriented languages, such as C++, Java, Python and Ruby, composite types also have named functions associated with them, and the combination is called an "object". In Julia, all types are objects, but the objects have no bound functions. This is necessary because Julia selects the function/method using multiple dispatch, meaning that all argument types of a function are used to select the method, not just the first argument type.
Composite types are defined using the "struct" keyword followed by a block of field names. They are immutable (for performance reasons), unless modified by the "mutable" keyword.
```julia
struct Longday
day::Int64
frac::Float64
end
```
An instance of Longday is created as follows.
```julia
day1 = Longday(1, 0.5)
```
Let's create a Longday type and an instance of it.
"""
# ╔═╡ be09f5d0-daea-4f47-8dc8-33c875fca843
# ╔═╡ 10ec3b0d-1add-4f92-8f4c-b594ab3f0e68
# ╔═╡ 6ee4665d-c5b9-4881-ad65-15c6a8229f3f
md"""
The field can be access using "dot" notation as follows:
```julia
day1.day
```
```julia
day1.frac
```
"""
# ╔═╡ f5596a05-04de-4955-9575-4c035e0f1495
# ╔═╡ a1b4f7bb-8238-40d6-81cb-6d5e6c737134
# ╔═╡ 3b8e773f-df6e-4b59-9f5d-e14366d02754
md"""
#### Type Union
A type union is an abstract type that includes all instances of any of its argument types. The empty union `Union{}` is the leaf node of all Julia types.
```julia
Union{Int, Nothing}
```
The variable "nothing" is the singleton instance of the type "Nothing".
Try it.
"""
# ╔═╡ 91f35db2-6a17-42aa-8580-1dea220b8c11
# ╔═╡ a631464d-e08a-4a89-8c47-fd5a7b2dee16
md"""
#### Symbol Type
A type used to represent identifiers in parsed Julia code, namely the Abstract Syntax Trees (ASTs). Also often used as a name or label to identify an entity (e.g., as a dictionary key). Symbols are created using the colon prefix operator ":".
Symbols can be confusing when you first meet them in Julia code.
```julia
:symbol
```
```julia
typeof(:symbol)
```
"""
# ╔═╡ 7a8faa02-34b1-4416-beab-2909fb56c767
# ╔═╡ 6e1a3b46-05f0-487d-933a-6ff0d9d43a2b
# ╔═╡ 05adfd23-c809-4706-9bf2-1a0a2445748b
md"""
#### Using Types
The type hierarchy allows variables and functions to be constrained to a particular set of types. Let's try a simple example.
Enter the following expressions.
```julia
arg1::Float32 = 12.3
```
"""
# ╔═╡ 67a4ff9f-c75f-444c-9091-e9b5c17ee773
# ╔═╡ 67ad1d30-498e-414a-83d5-12e020c92741
md"""
```julia
typeof(arg1) <: Integer
```
"""
# ╔═╡ cfd93268-174f-4a7e-9f98-3d5787c9392c
# ╔═╡ 73be3ec3-2668-44a0-bed9-242796bf5f08
md"""
```julia
typeof(arg1) <: AbstractFloat
```
"""
# ╔═╡ a96dd069-09aa-4add-baba-99ffae36bfe8
# ╔═╡ 8a3aa0d3-1ade-4961-975d-b39899731ffe
md"""
!!! note
What new things have we learned about Julia?
* Julia has a type hierarchy with the type "Any" at the top.
* Julia defines characters and strings using single and double quotes, respectively.
* Julia defines composite types using the "struct" keyword.
* Julia allows a set of types to be defined using the "Union" type.
"""
# ╔═╡ 62edc512-89e6-4b29-b96e-f43b253654b9
md"""
**===================================================================================**
### Functions
In Julia, a function is an object that maps a tuple of argument values to a return value.
There are three syntaxes for defining a function. The first two are named functions and the third is an anonymous function. If the return value is the last statement, then the "return" keyword is optional.
"""
# ╔═╡ 178be175-bc41-4f15-a56b-18b22ea429ba
md"""
Standard function definition:
```julia
function myadd(x::Int, y::Int)
x + y
end
```
"""
# ╔═╡ c696f779-ff9f-42c3-b22d-77ffc56b0bd9
md"""
One-line function definition:
```julia
myadd(x::Float64, y::Float64) = x + y
```
"""
# ╔═╡ e5db3490-9574-4a76-99ed-c8c37af7c1f4
md"""
Anonymous function definition:
```julia
x, y -> x + y
```
Anonymous functions are often used when a function argument expects a function, e.g., the `filter` method that expects a Boolean comparison function.
"""
# ╔═╡ 2e2ce11c-70ab-4c32-9f99-29dfe96f2ddb
md"""
Let's define the above `myadd` function.
"""
# ╔═╡ 771dee9c-1615-435a-884f-7d274172191c
# ╔═╡ c0c8fde0-1526-4e8a-896a-67c226b0badf
# ╔═╡ c3b1713c-1207-427f-bc2b-7ff973f5e35e
md"""
Notice that the function "myadd" now has two methods; one for Ints and one for Float64s.
Try adding an Int and Float64 using the "myadd" function.
```julia
myadd(2, 3.1)
```
"""
# ╔═╡ c7b43469-232a-46a0-8bb6-c7a928e6d2f2
# ╔═╡ cc19d021-1f25-4469-8239-9924cc01f883
md"""
The compiler returns a MethodError because their is no method that adds a Int and Float64. We can fix this by defining a generic "myadd" function.
```julia
myadd(x, y) = x + y
```
"""
# ╔═╡ e967114e-14ef-42e4-a1cd-dcfda5f19ca3
myadd
# ╔═╡ 43b6afe5-8c9d-412a-ae68-c190b93c74e6
# ╔═╡ 02296dd4-ddca-4acb-929f-61ef5d9f755f
md"""
!!! note
Now look at the result above of adding an Int and a Float64 using "myadd".
In many cases, a function with generic arguments is sufficiently performant. But in those cases where extreme performance is needed, defining methods with specific argument types may be necessary.
!!! note
One-line functions are usually inlined by the compiler. So, there is usually no performance penalty for using them. Multi-lined functions may also be inlined.
"""
# ╔═╡ 197727b0-f566-4953-94fd-9062f8d4e828
md"""#### Optional Arguments
Functions can often take sensible default values. Julia allows the default values to be defined in the function definition.
```julia
optargs(y::Int, m::Int=1, d::Int=1) = "$y-$m-$d"
```
Define the above function and execute it with a variable number of arguments.
Note how many methods are created when the function is defined.
"""
# ╔═╡ 5639ea0c-c911-4e17-892d-2baf3613c682
optargs(y::Int, m::Int=1, d::Int=1) = "$y-$m-$d"
# ╔═╡ c463427e-1584-4eb7-aefe-0eb24a9c01ba
optargs(2, 2, 2)
# ╔═╡ 3ddf7fd7-9ebd-4f63-a4ac-c6cea8973478
md"""#### Keyword Arguments
Some functions have a large number of arguments or a large number of behaviors. Remembering how to call such functions can be annoying. Keyword arguments can make these functions easier to use and extend by allowing arguments to be identified by name instead of only by position.
Keyword arguments are listed after the required and optional arguments. They are delimited by a semicolon in the argument list.
```julia
kwfunc(arg1, arg2=1; kwd1="blue", kwd2="red")
```
!!! note
Don't confuse keyword arguments and optional arguments. Optional arguments are positional arguments with default values. Keyword arguments are positionless arguments, which may or may not have default values.
"""
# ╔═╡ f997567b-b403-4e21-a87f-063b59dcc5a6
md"""#### Functors
Functors are anonymous functions that are defined only by their argument signature. They are synonymous with callable objects in Python.
```julia
begin
struct Polynomial{R}
coeffs::Vector{R}
end
function (p::Polynomial)(x)
v = p.coeffs[end]
for i = (length(p.coeffs)-1):-1:1
v = v*x + p.coeffs[i]
end
return v
end
end
```
```julia
p = Polynomial([1,10,100])
```
```julia
p(5)
```
Define the Polynomial type and the functor by placing the struct and function in a begin-end block.
"""
# ╔═╡ 802d9fbf-8a1c-4bb3-aa2d-cd9bab659115
# ╔═╡ 679a571e-d866-4005-a047-028c426fb167
md"""Create a polynomial"""
# ╔═╡ 1e8b04e8-ea02-41d1-94e1-42b02bbafdcc
# ╔═╡ 3ffc37d1-8fd2-4436-bb8d-4bd82291c174
md"""Evaluate the polynomial"""
# ╔═╡ fad1263d-6a0a-435e-a6b5-2e2d394307be
# ╔═╡ 7a35a96c-be9e-4e6e-ba70-7fb9b84a609f
md"""
!!! note
What have we learned about functions?
* Julia uses the argument signature, called multiple dispatch, to select the executable function.
* Julia has two syntaxes for defining functions: one is for many-line functions and the other for one-line functions.
* Julia has named functions and anonymous functions.
* Julia function signatures have arguments and keywords. Arguments are required and listed first, but can have optional default values. Whereas, keywords are listed last and are optional.
* Julia has anonymous functions called "functors" that are defined by their argument signature.
"""
# ╔═╡ 33105044-e651-40a5-b928-592032c68e42
md"""
**===================================================================================**
## Multi-dimensional Arrays
The array library is implemented almost completely in Julia itself, and derives its performance from the compiler. All arguments to functions are passed by sharing (i.e. by pointers). By convention, a function name ending with a "!" indicates that it will mutate or destroy the value of one or more of its arguments (compare, for example, "sort" and "sort!").
Two characteristics of Julia arrays are:
* Column-major indexing
* One-based indexing
Both column-major indexing and one-base indexing follow the matrix convention of vectors being column arrays and the first index being 1. This is the same as FORTRAN and Matlab, and, of course, unlike Python.
!!! tip
Just remember that the first index varies fastest.
"""
# ╔═╡ b3c2831f-1de1-47f4-ba4a-1cc30c30d510
md"""
**===================================================================================**
### Array Construction and Initialization
There several ways to create and initialize a new array:
```julia
Array{T}(undef, dims...) # an unitialized dense array
ones(T, dims...) # an array of zeros