summaryrefslogtreecommitdiffhomepage
path: root/pt-br/julia-pt.html.markdown
blob: 70c135514adc93f6d2453411c461a79385196e4a (plain)
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
---
language: Julia
filename: learnjulia-pt.jl
contributors:
    - ["Leah Hanson", "http://leahhanson.us"]
translators:
    - ["Davidson Mizael", "https://github.com/davidsonmizael"]
lang: pt-br
---

Julia é uma linguagem homoicônica funcional focada na computação técnica. Ao mesmo tempo que ela tem todo o poder dos macros homoicônicos, funções de primeira classe, e controle de baixo nível, Julia é tão fácil para aprender e usar quanto Python.

Este tutorial é baseado no Julia 0.3.

```julia
# Linhas únicas de comentários começam com o simbolo hash(jogo da velha).
#= Comentários de multiplas linhas podem ser escritos
   colocando '#=' antes do texto e '=#'
   após o texto. Eles também podem ser agrupados
=#

####################################################
## 1. Tipos primitivos e operadores
####################################################

# Tudo em Julia é uma expressão.

# Há muitos tipos básicos de numeros.
3 # => 3 (Int64)
3.2 # => 3.2 (Float64)
2 + 1im # => 2 + 1im (Complex{Int64})
2//3 # => 2//3 (Rational{Int64})

# Todos os operadores inseguros normais estão disponiveis.
1 + 1 # => 2
8 - 1 # => 7
10 * 2 # => 20
35 / 5 # => 7.0
5 / 2 # => 2.5 # dividir um Int por um Int resulta em um float
div(5, 2) # => 2 # para um restultado truncado, use div
5 \ 35 # => 7.0
2 ^ 2 # => 4 # elevado,não o opeardor binário xor
12 % 10 # => 2

# Impõe a priodidade nos parenteses
(1 + 3) * 2 # => 8

# Operadores binarios
~2 # => -3   # not
3 & 5 # => 1 # and
2 | 4 # => 6 # or
2 $ 4 # => 6 # xor
2 >>> 1 # => 1 # deslocamento lógico de bits a direita
2 >> 1  # => 1 # deslocamento aritmético de bits a direita
2 << 1  # => 4 # deslocamento lógico/aritmético de bits a esquerda

# Você pode usar a função bits para ver a representação binária de um numero.
bits(12345)
# => "0000000000000000000000000000000000000000000000000011000000111001"
bits(12345.0)
# => "0100000011001000000111001000000000000000000000000000000000000000"

# Valores booleanos são primitivos.
true
false

# Operadores booleanos
!true # => false
!false # => true
1 == 1 # => true
2 == 1 # => false
1 != 1 # => false
2 != 1 # => true
1 < 10 # => true
1 > 10 # => false
2 <= 2 # => true
2 >= 2 # => true
# Comparações podem ser encadeadas
1 < 2 < 3 # => true
2 < 3 < 2 # => false

# Strings são criadas com  "
"Isso é uma String."

# Caracteres literais são escritos com '
'a'

# Uma string pode ser indexada como um vetor de caracteres
"Isso é uma string"[1] # => 'I' # Julia começa a indexar a partir do 1
# Porém isso não funcionará direito com strings em UTF8,
# portanto é recomendado usar iterações sobre uma string (map, loops com for, etc).

# $ pode ser usado para interpolação de string:
"2 + 2 = $(2 + 2)" # => "2 + 2 = 4"
# Você pode usar qualquer expressão Julia dentro dos parenteses.

# Outro jeito de formatar strings é com um macro no printf.
@printf "%d é menor que %f" 4.5 5.3 # 5 é menor que 5.300000

# Escrever na tela é fácil
println("Eu sou Julia. Prazer em conhece-lo!")

####################################################
## 2. Variáveis e coleções
####################################################

#Você não declara variáveis antes de atribui-las.
some_var = 5 # => 5
some_var # => 5

# Acessando a variável anterior não iniciada é um erro
try
    some_other_var # => ERROR: some_other_var não definida
catch e
    println(e)
end

# Nomes de variáveis começam com uma letra.
# Depois disso, você pode usar letras, digitos, underscores e pontos de exclamação.
SomeOtherVar123! = 6 # => 6

# Você também pode usar caractéres unicode
☃ = 8 # => 8
# Estes são especialmente reservados para notações matemáticas.
2 * π # => 6.283185307179586

# Uma nota na convenção de nomes em Julia:
#
# * A separação de palavras pode ser feita por underscores ('_'), mas o uso
#   de underscore é desencorajado a menos que o nome da variável seja dificil
#   de ler.
#
# * Os nomes de tipos começam com letra maiúscula e a separação de letras é
#   feita a partir de CamelCase no lugar de underscores.
#
# * Nomes de funções e macros são em minúsculo, sem underscore.
#
# * Funções que modificam a própria entrada tem nomes que terminam em !. Estas
#   funções são chamadas as vezes de funções de mutação ou função in-place.

# Vetores armazenam uma sequencia de valores indexados por integer de 1 a n:
a = Int64[] # => 0-element Int64 Array

# 1-Vetores dimensionais literais podem ter seus valores separados por virgula.
b = [4, 5, 6] # => 3-element Int64 Array: [4, 5, 6]
b[1] # => 4
b[end] # => 6

# 2-Vetores dimensionais usam espaço para separar valores e ponto e virgula para linhas.
matrix = [1 2; 3 4] # => 2x2 Int64 Array: [1 2; 3 4]

# Adiciona-se coisas ao final de uma lista com push! e append!
push!(a,1)     # => [1]
push!(a,2)     # => [1,2]
push!(a,4)     # => [1,2,4]
push!(a,3)     # => [1,2,4,3]
append!(a,b) # => [1,2,4,3,4,5,6]

# Remove-se do final com pop!
pop!(b)        # => 6 e 'b' agora é [4,5]

# Vamos coloca-lo de novo
push!(b,6)   # 'b' agora é [4,5,6] de novo.

a[1] # => 1 # lembre-se que Julia indexa a partir de 1, não 0.

# end é um atalho para a ultima posição. Pode ser usada em qualquer
# expressão indexada.
a[end] # => 6

# nós também temos shift e unshift
shift!(a) # => 1 e 'a' agora é [2,4,3,4,5,6]
unshift!(a,7) # => [7,2,4,3,4,5,6]

# Funções que terminam com ponto de exclamação indicam que elas modificam
# seus argumentos.
arr = [5,4,6] # => 3-element Int64 Array: [5,4,6]
sort(arr) # => [4,5,6]; 'arr' continua [5,4,6]
sort!(arr) # => [4,5,6]; 'arr' agora é [4,5,6]

# Olhar além dos limites é um BoundsError
try
    a[0] # => ERROR: BoundsError() in getindex at array.jl:270
    a[end+1] # => ERROR: BoundsError() in getindex at array.jl:270
catch e
    println(e)
end

# Erros listam a linha e o nome do arquivo que ele está, mesmo se for uma
# biblioteca padrão. Se você construiu Julia pelo source, você pode olhar na
# pasta base dentro da pasta do Julia para encontrar esses arquivos.

# Você pode inicializar vetores com limites
a = [1:5;] # => 5-element Int64 Array: [1,2,3,4,5]

# Você pode ver até um limite com a sintaxe separada
a[1:3] # => [1, 2, 3]
a[2:end] # => [2, 3, 4, 5]

# Remova elementos de um array pelo index com splice!
arr = [3,4,5]
splice!(arr,2) # => 4 ; arr is now [3,5]

# Concatene listas com append!
b = [1,2,3]
append!(a,b) # 'a' agora é [1, 2, 3, 4, 5, 1, 2, 3]

# Cheque se um valor existe me uma lista com in
in(1, a) # => true

# Veja o tamanho com lenght
length(a) # => 8

# Tuples não podem ser mudados.
tup = (1, 2, 3) # => (1,2,3) # um tuple (Int64,Int64,Int64).
tup[1] # => 1
try:
    tup[1] = 3 # => ERROR: não há metodo setindex!((Int64,Int64,Int64),Int64,Int64)
catch e
    println(e)
end

# Muitas litas de funções também trabalham com tuples
length(tup) # => 3
tup[1:2] # => (1,2)
in(2, tup) # => true

#Você pode desempacotar tuples para variáveis.
a, b, c = (1, 2, 3) # => (1,2,3)  # 'a' agora é 1, 'b' agora é 2 e 'c' agora é 3

# Tuplas são criados mesmo se você deixar fora dos parenteses
d, e, f = 4, 5, 6 # => (4,5,6)

# Uma tupla de um elemento é diferente do valor que ele contém
(1,) == 1 # => false
(1) == 1 # => true

# Olhe como é facil pra trocar dois valores
e, d = d, e  # => (5,4) # 'd' agora é 5 e 'e' agora é 4

# Dicionários armazenam mapeamentos
empty_dict = Dict() # => Dict{Any,Any}()

# Você pode criar um dicionário usando um literal
filled_dict = ["one"=> 1, "two"=> 2, "three"=> 3]
# => Dict{ASCIIString,Int64}

# Veja os valores com []
filled_dict["one"] # => 1

# Pegue todas as chaves
keys(filled_dict)
# => KeyIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
# Nota - as chaves dos dicionários não são ordenadas nem estão na ordem que você as inseriu.

# Pegue todos os valores
values(filled_dict)
# => ValueIterator{Dict{ASCIIString,Int64}}(["three"=>3,"one"=>1,"two"=>2])
# Nota - A mesma coisa que na nota acima sobre a ordenação das chaves.

# Cheque pela existencia de chaves em um dicionário com in e haskey
in(("one", 1), filled_dict) # => true
in(("two", 3), filled_dict) # => false
haskey(filled_dict, "one") # => true
haskey(filled_dict, 1) # => false

# Procurar por uma chave não existente irá gerar um erro
try
    filled_dict["four"] # => ERROR: key not found: four in getindex at dict.jl:489
catch e
    println(e)
end

# Use o método get para escapar desse erro passando um valor padrão
# get(dictionary,key,default_value)
get(filled_dict,"one",4) # => 1
get(filled_dict,"four",4) # => 4

# Use sets para representar coleções de valores unicos e não ordenados
empty_set = Set() # => Set{Any}()
# Inicialize um set com valores
filled_set = Set(1,2,2,3,4) # => Set{Int64}(1,2,3,4)

# Adicione mais valores para um set
push!(filled_set,5) # => Set{Int64}(5,4,2,3,1)

# Cheque se um valor está no set
in(2, filled_set) # => true
in(10, filled_set) # => false

# Não há funções para interseção de set, união e diferença.
other_set = Set(3, 4, 5, 6) # => Set{Int64}(6,4,5,3)
intersect(filled_set, other_set) # => Set{Int64}(3,4,5)
union(filled_set, other_set) # => Set{Int64}(1,2,3,4,5,6)
setdiff(Set(1,2,3,4),Set(2,3,5)) # => Set{Int64}(1,4)

####################################################
## 3. Controle de fluxo
####################################################

# Vamos fazer uma variável
some_var = 5

# Aqui está um if. Identação nao é importante em Julia.
if some_var > 10
    println("some_var é totalmente maior que 10.")
elseif some_var < 10    # Essa clausula elseif é opcional.
    println("some_var é menor que 10.")
else                    # A clausula else é opcional também.
    println("some_var é literalmente 10.")
end
# => exibe "some_var é menor que 10"

# Loops for repetem sobre variaveis iteráveis.
# Tipos iterativos incluem Range, Array, set Dict e String.
for animal=["dog", "cat", "mouse"]
    println("$animal is a mammal")
    # Você pode interpolar variáveis usando $ ou expressões em strings
end
# exibe:
#    dog is a mammal
#    cat is a mammal
#    mouse is a mammal

# Você pode usar 'in' no lugar de '='.
for animal in ["dog", "cat", "mouse"]
    println("$animal is a mammal")
end
# exibe:
#    dog is a mammal
#    cat is a mammal
#    mouse is a mammal

for a in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"]
    println("$(a[1]) is a $(a[2])")
end
# exibe:
#    dog is a mammal
#    cat is a mammal
#    mouse is a mammal

for (k,v) in ["dog"=>"mammal","cat"=>"mammal","mouse"=>"mammal"]
    println("$k is a $v")
end
# exibe:
#    dog is a mammal
#    cat is a mammal
#    mouse is a mammal

# Loops while circulam enquanto a condição é true
x = 0
while x < 4
    println(x)
    x += 1  # Abreveação para x = x + 1
end
# exibe:
#   0
#   1
#   2
#   3

# Trate exceções com um bloco try/catch
try
   error("help")
catch e
   println("caught it $e")
end
# => caught it ErrorException("help")


####################################################
## 4. Funções
####################################################

# A palavra chave 'function' cria novas funções
#function name(arglist)
#  corpo...
#end
function add(x, y)
    println("x is $x and y is $y")

    # Funções retornam o valor da sua ultima declaração
t    x + y
end

add(5, 6) # => 11 after printing out "x is 5 and y is 6"

# Você pode definir funções que tomam um numero incerto de
# argumentos
function varargs(args...)
    return args
    # use a palavra chave return para retornar um valor em qualquer parte da função
end
# => varargs (generic function with 1 method)

varargs(1,2,3) # => (1,2,3)

# O ... é chamado de splat.
# Nós apenas o usamos na definição de uma função.
# Também pode ser usado na chamada de uma função,
# onde ela vai abrir um Array ou o conteúdo de um Tuple na lista de argumentos.
Set([1,2,3])    # => Set{Array{Int64,1}}([1,2,3]) # produz um Set de Arrays
Set([1,2,3]...) # => Set{Int64}(1,2,3) # isso é equivalente a Set(1,2,3)

x = (1,2,3)     # => (1,2,3)
Set(x)          # => Set{(Int64,Int64,Int64)}((1,2,3)) # um Set de Tuples
Set(x...)       # => Set{Int64}(2,3,1)

# Você pode definir funções com argumentos posicionais opcionais.
function defaults(a,b,x=5,y=6)
    return "$a $b and $x $y"
end

defaults('h','g') # => "h g and 5 6"
defaults('h','g','j') # => "h g and j 6"
defaults('h','g','j','k') # => "h g and j k"
try
    defaults('h') # => ERROR: no method defaults(Char,)
    defaults() # => ERROR: no methods defaults()
catch e
    println(e)
end

# Você pode definir funções que tomam argumentos como palavras chaves
function keyword_args(;k1=4,name2="hello") # note the ;
    return ["k1"=>k1,"name2"=>name2]
end

keyword_args(name2="ness") # => ["name2"=>"ness","k1"=>4]
keyword_args(k1="mine") # => ["k1"=>"mine","name2"=>"hello"]
keyword_args() # => ["name2"=>"hello","k1"=>4]

# Você pode combinar todos os tipos de argumentos em uma só função
function all_the_args(normal_arg, optional_positional_arg=2; keyword_arg="foo")
    println("normal arg: $normal_arg")
    println("optional arg: $optional_positional_arg")
    println("keyword arg: $keyword_arg")
end

all_the_args(1, 3, keyword_arg=4)
# exibe:
#   normal arg: 1
#   optional arg: 3
#   keyword arg: 4

# Julia tem funções de primeira classe
function create_adder(x)
    adder = function (y)
        return x + y
    end
    return adder
end

# Isso é "sintexe furiosa de lambda" pra criar funções anônimas.
(x -> x > 2)(3) # => true

#Esta função é identica a implementação da create_adder acima.
function create_adder(x)
    y -> x + y
end

# Você também pode nomear funções internas, se você quiser
function create_adder(x)
    function adder(y)
        x + y
    end
    adder
end

add_10 = create_adder(10)
add_10(3) # => 13


# Há
# There are built-in higher order functions
map(add_10, [1,2,3]) # => [11, 12, 13]
filter(x -> x > 5, [3, 4, 5, 6, 7]) # => [6, 7]

# Nós podemos usar listas de compreensão para melhores mapeamentos
[add_10(i) for i=[1, 2, 3]] # => [11, 12, 13]
[add_10(i) for i in [1, 2, 3]] # => [11, 12, 13]

####################################################
## 5. Tipos
####################################################

#Julia tem um sistema de tipos.
# Todo valor tem um tipo. Variaveis não tem tipos próprios.
# Você pode usar a função 'typeof' para pegar o valor.
typeof(5) # => Int64

# Tipos são valores de primeira classe.
typeof(Int64) # => DataType
typeof(DataType) # => DataType
# DataType é o tipo que representa tipos, incluindo ele mesmo.

# Tipos são usados para documentação, optimização e envio
# Eles não são estaticamente checados.

# Usuários podem definir tipos
# Eles são como records ou structs em outras linguagens.
# Novos tipos são definidos usando a palavra chave 'type'

# type Name
#   field::OptionalType
#   ...
# end
type Tiger
  taillength::Float64
  coatcolor # não incluindo uma notação type é o mesmo que '::Any'
end

# Os argumentos padrões de um construtor são as propriedades
# do tipo na ordem que eles são listados na definição.
tigger = Tiger(3.5,"orange") # => Tiger(3.5,"orange")

# O tipo double como construtor de função para valores desse tipo
# The type doubles as the constructor function for values of that type
sherekhan = typeof(tigger)(5.6,"fire") # => Tiger(5.6,"fire")

# Esses tipos no estilo struct são chamados tipos concretos
# Eles podem ser instanciados, mas não podem ter subtipos.
# O outro tipo de tipos são os tipos abstratos.

# abstract Name
abstract Cat # apenas um nome e um ponto na hierarquia de tipo

# Tipos abstratos podem ser instanciados, mas não podem ter subtipos.
# Por exemplo, Number é um tipo abstrato
subtypes(Number) # => 6-element Array{Any,1}:
                 #     Complex{Float16}
                 #     Complex{Float32}
                 #     Complex{Float64}
                 #     Complex{T<:Real}
                 #     ImaginaryUnit
                 #     Real
subtypes(Cat) # => 0-element Array{Any,1}

# Todo tipo tem um super tipo; use a função 'super' para pegá-lo.
typeof(5) # => Int64
super(Int64) # => Signed
super(Signed) # => Real
super(Real) # => Number
super(Number) # => Any
super(super(Signed)) # => Number
super(Any) # => Any
# Todos esss tipos, exceto o Int64, são abstratos.

# <: é o operador de subtipagem
type Lion <: Cat # Lion é um subtipo de Cat
  mane_color
  roar::String
end

# Você pode definir mais construtores para seu tipo
# É só definir uma função com o mesmo nome do tipo
# e chamar um construtor existente para pegar o valor do tipo correto
Lion(roar::String) = Lion("green",roar)
# Isso é um construtor externo porque ele está fora da definição do tipo

type Panther <: Cat # Panther também é um subtipo de Cat
  eye_color
  Panther() = new("green")
# Panthers terão apenas esse construtor, e não construtor padrão.
end
# Usando construtores internos, como Panther faz, lhe da o controle
# sobre como os valores dos tipos são criados.
# Quando possivel, você deve usar construtores externos mais do que internos.

####################################################
## 6. Multiple-Dispatch
####################################################


# Em Julia todas as funções nomeadas são funções genericas
# Isso significa que elas são construidas de muitos métodos pequenos
# Cada construtor para Lion é um metodo da função genérica Lion.Lion.

# Para um exemplo sem construtor, vamos fazer a função meow

# Definição para Lion, Panther e Tiger
function meow(animal::Lion)
  animal.roar #propriedades do tipo de acesso usando a notação ponto '.'
end

function meow(animal::Panther)
  "grrr"
end

function meow(animal::Tiger)
  "rawwwr"
end

# Testando a função meow
meow(tigger) # => "rawwr"
meow(Lion("brown","ROAAR")) # => "ROAAR"
meow(Panther()) # => "grrr"

# Revendo o tipo local de hierarchy
issubtype(Tiger,Cat) # => false
issubtype(Lion,Cat) # => true
issubtype(Panther,Cat) # => true

# Definindo uma função que recebe Cats
function pet_cat(cat::Cat)
  println("The cat says $(meow(cat))")
end

pet_cat(Lion("42")) # => exibe "The cat says 42"
try
    pet_cat(tigger) # => ERROR: no method pet_cat(Tiger,)
catch e
    println(e)
end

# Em linguagens orientadas a objeto, envio unico é comúm
# isso significa que o método é selecionado baseado no tipo do seu primeiro argumento
# Em Julia todos os tipos de argumentos contribuem na seleção do melhor método


# Vamos definir uma função com mais argumentos, então poderemos ver a diferença
function fight(t::Tiger,c::Cat)
  println("The $(t.coatcolor) tiger wins!")
end
# => fight (generic function with 1 method)

fight(tigger,Panther()) # => exibe The orange tiger wins!
fight(tigger,Lion("ROAR")) # => exibir The orange tiger wins!

# Vamos mudar o comportamento quando o gato é especificamente um leão
fight(t::Tiger,l::Lion) = println("The $(l.mane_color)-maned lion wins!")
# => fight (generic function with 2 methods)

fight(tigger,Panther()) # => exobe The orange tiger wins!
fight(tigger,Lion("ROAR")) # => exobe The green-maned lion wins!

# Nós não precisamos de um tigre para brigar
fight(l::Lion,c::Cat) = println("The victorious cat says $(meow(c))")
# => fight (generic function with 3 methods)

fight(Lion("balooga!"),Panther()) # => exibe The victorious cat says grrr
try
  fight(Panther(),Lion("RAWR")) # => ERROR: no method fight(Panther,Lion)
catch
end

# Aliás, vamos deixar o gato ir primeiro
fight(c::Cat,l::Lion) = println("The cat beats the Lion")
# => Warning: New definition
#    fight(Cat,Lion) at none:1
# is ambiguous with
#    fight(Lion,Cat) at none:2.
# Make sure
#    fight(Lion,Lion)
# is defined first.
#fight (generic function with 4 methods)

# Este aviso é porque não está claro qual método fight será chamado em:
fight(Lion("RAR"),Lion("brown","rarrr")) # => exibe The victorious cat says rarrr
# O resultado pode ser diferente em outras versões de Julia

fight(l::Lion,l2::Lion) = println("The lions come to a tie")
fight(Lion("RAR"),Lion("brown","rarrr")) # => exibe The lions come to a tie


# Embaixo dos panos
# Você pode olhar o llvm e o código assembly gerado.

square_area(l) = l * l      # square_area (generic function with 1 method)

square_area(5) #25

# O que acontece quando alimentamos square_area com um inteiro?
# What happens when we feed square_area an integer?
code_native(square_area, (Int32,))
    #       .section    __TEXT,__text,regular,pure_instructions
    #   Filename: none
    #   Source line: 1              # Prólogo
    #       push    RBP
    #       mov RBP, RSP
    #   Source line: 1
    #       movsxd  RAX, EDI        # Busca l na memoria?
    #       imul    RAX, RAX        # Faz o quadrado de l e armazena o resultado em RAX
    #       pop RBP                 # Restaura o ponteiro de base antigo
    #       ret                     # O resultado continua em RAX

code_native(square_area, (Float32,))
    #       .section    __TEXT,__text,regular,pure_instructions
    #   Filename: none
    #   Source line: 1
    #       push    RBP
    #       mov RBP, RSP
    #   Source line: 1
    #       vmulss  XMM0, XMM0, XMM0  # Múltiplicação escalar unica de precisão (AVX)
    #       pop RBP
    #       ret

code_native(square_area, (Float64,))
    #       .section    __TEXT,__text,regular,pure_instructions
    #   Filename: none
    #   Source line: 1
    #       push    RBP
    #       mov RBP, RSP
    #   Source line: 1
    #       vmulsd  XMM0, XMM0, XMM0 # Duplicação ecalar de precisão multipla(AVX)
    #       pop RBP
    #       ret
    #
# Note que Julia usará instruções de ponto flutuante se quaser um dos
# argumentos forem float
# Vamos calcular a área de um circulo
circle_area(r) = pi * r * r     # circle_area (generic function with 1 method)
circle_area(5)                  # 78.53981633974483

code_native(circle_area, (Int32,))
    #       .section    __TEXT,__text,regular,pure_instructions
    #   Filename: none
    #   Source line: 1
    #       push    RBP
    #       mov RBP, RSP
    #   Source line: 1
    #       vcvtsi2sd   XMM0, XMM0, EDI          # Carrega inteiro (r) da memória
    #       movabs  RAX, 4593140240              # Carrega pi
    #       vmulsd  XMM1, XMM0, QWORD PTR [RAX]  # pi * r
    #       vmulsd  XMM0, XMM0, XMM1             # (pi * r) * r
    #       pop RBP
    #       ret
    #

code_native(circle_area, (Float64,))
    #       .section    __TEXT,__text,regular,pure_instructions
    #   Filename: none
    #   Source line: 1
    #       push    RBP
    #       mov RBP, RSP
    #       movabs  RAX, 4593140496
    #   Source line: 1
    #       vmulsd  XMM1, XMM0, QWORD PTR [RAX]
    #       vmulsd  XMM0, XMM1, XMM0
    #       pop RBP
    #       ret
    #
```

## Extras

Você pode ver mais um monte de detalhes no [manual de Julia](http://docs.julialang.org/en/latest/manual/)
O melhor lugar pra pedir ajuda em Julia é a (muito amigável) [mailing list](https://groups.google.com/forum/#!forum/julia-users).