Когда вы пишете foo(a,b,c=42) = a*b*c
, Джулия просто определяет два метода:
foo(a, b) = foo(a, b, 42)
foo(a, b, c) = a*b*c
Вы можете увидеть это, просто спросив Джулию о методах:
julia> foo(a, b, c=42) = a*b*c
foo (generic function with 2 methods)
julia> methods(foo)
# 2 methods for generic function "foo":
[1] foo(a, b) in Main at REPL[120]:1
[2] foo(a, b, c) in Main at REPL[120]:1
Это все необязательно(позиционный) параметр делает.Фактически бывают ситуации, когда необязательный параметр должен указываться в первом аргументе, но это не поддерживаемый синтаксис.Таким образом, вместо этого вы можете вручную сделать что-то вроде:
print(x) = print(stdout, x)
print(io, x) = # actually print to the io
Таким образом, io
такой же «необязательный» аргумент, как и c
в вашем примере.Конечно, я надеюсь, что вы можете увидеть, как это делает отражение здесь, ну, довольно сложно.Одним из возможных путей было бы спросить, что делает foo
с двумя аргументами:
julia> code_lowered(foo, Tuple{Any,Any})
1-element Array{Core.CodeInfo,1}:
CodeInfo(
1 ─ %1 = (#self#)(a, b, 42)
└── return %1
)
Таким образом, потенциальная «подобная отражению» утилита может быть построена для самоанализа на этом IR:
julia> c = code_lowered(foo, Tuple{Any,Any})
1-element Array{Core.CodeInfo,1}:
CodeInfo(
1 ─ %1 = (#self#)(a, b, 42)
└── return %1
)
julia> c[1].code[1].args[end]
42
Конечно, вы захотите объединить это в функцию с обильным количеством проверки ошибок, чтобы убедиться, что метод действительно просто вызывает сам себя, и больше ничего не происходит, кроме заполнения этого последнего аргумента.