Neste notebook, vamos explorar o conceito de despacho múltiplo, que é um recurso chave da linguagem Julia.
Para entender despacho múltiplo em Julia, vamos começar com um exemplo que nós já vimos.
Em Julia, podemos declarar funções sem informar o tipo dos argumentos da função. Por exemplo:
f(x) = x^2
f (generic function with 1 method)
Então a Julia vai determinar automaticamente sobre quais tipos de argumentos faz sentido aplicar a função, e sobre quais tipos não faz:
f(9)
81
f([1, 2, 3])
MethodError: no method matching ^(::Vector{Int64}, ::Int64) Closest candidates are: ^(::Union{AbstractChar, AbstractString}, ::Integer) at strings/basic.jl:730 ^(::Complex{<:AbstractFloat}, ::Integer) at complex.jl:860 ^(::Complex{<:Integer}, ::Integer) at complex.jl:862 ... Stacktrace: [1] literal_pow @ ./intfuncs.jl:340 [inlined] [2] f(x::Vector{Int64}) @ Main ./In[1]:1 [3] top-level scope @ In[3]:1 [4] eval @ ./boot.jl:368 [inlined] [5] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1428
Temos a opção de declarar explicitamente quais tipos de argumentos uma função pode receber.
Por exemplo, vamos definir uma função teste
que só pode receber argumentos do tipo String
:
teste(x::String, y::String) = println("Os argumentos x e y são strings")
teste (generic function with 1 method)
Vamos verificar que a função teste
age sobre strings, mas não age sobre argumentos de outros tipos:
teste("despacho", "múltiplo")
Os argumentos x e y são strings
teste(2, 3)
MethodError: no method matching teste(::Int64, ::Int64) Stacktrace: [1] top-level scope @ In[6]:1 [2] eval @ ./boot.jl:368 [inlined] [3] include_string(mapexpr::typeof(REPL.softscope), mod::Module, code::String, filename::String) @ Base ./loading.jl:1428
Para fazer com que a função teste
aceite números inteiros, vamos definir teste
para argumentos do tipo Int
:
teste(x::Int, y::Int) = println("Os argumentos x e y são números inteiros")
teste (generic function with 2 methods)
teste(2, 3)
Os argumentos x e y são números inteiros
Agora teste
age sobre os inteiros.
Mas observe, a função teste
continua definida quando x
e y
são strings:
teste("despacho", "múltiplo")
Os argumentos x e y são strings
Quando declaramos
teste(x::Int, y::Int) = println("Os argumentos x e y são números inteiros"),
não removemos ou substituímos
teste(x::String, y::String),
simplesmente adicionamos um método à função genérica teste
.
Uma função genérica é um conceito abstrato associado a uma operação.
Por exemplo, a função genérica +
representa o conceito de adição.
Um método é uma implementação específica de uma função genérica para um tipo específico de argumento.
Por exemplo, a função +
possui métodos para números de precisão flutuante, inteiros, matrizes, etc.
Podemos usar methods
para ver os métodos que a função teste
possui:
methods(teste)
E podemos ver os métodos da função +
:
methods(+)
Portanto, agora podemos aplicar teste
a strings e inteiros.
Quando aplicamos teste
a um par de argumentos, a Julia vai inferir os tipos dos argumentos e despachar o método apropriado.
Isso é despacho múltiplo.
Despacho múltiplo torna os programas genéricos e rápidos.
Para ver qual método está sendo despachado quando chamamos uma função genérica, usamos a macro @which
:
@which teste(2, 3)
@which 3.0 + 5.0