For example
function f(x)
# do something
# then I assigned the outside variable name of 'x' to y
println(y)
end
f(1)
I will get
# something and
1
then,
a = 1
f(a)
I will get
# something and
"a"
Is it possible in julia? If not, how can I get my function operation log?
The most idiomatic way would be to slightly change your interface of f and require a keyword argument:
julia> function f(;kwargs...)
for (k, v) in kwargs
println("$k = $v")
end
end
f (generic function with 1 method)
julia> f(a = 1)
a = 1
Alternatively (short of inspecting stack traces), you need something macro-based:
julia> struct Quot
expr
value
end
julia> macro quot(e)
return :($Quot($(QuoteNode(e)), $e))
end
#quot (macro with 1 method)
julia> function f2(x::Quot)
println(x)
end
f2 (generic function with 1 method)
julia> x = 2
2
julia> f2(#quot x)
Quot(:x, 2)
Depending on what you need a simples macro that dumps function calls that still get executed could be:
macro logs(expr)
#info expr
expr
end
And this can be used as:
julia> a = π/2;
julia> #logs sin(a)
[ Info: sin(a)
1.0
Related
Let's assume I have this Dict:
d=Dict("arg1"=>10,"arg2"=>20)
and a function like this:
function foo(;arg1,arg2,arg3,arg4,arg5)
#Do something
end
How can I call the function and pass the parameters in the Dict d as parameters for the function?
I know I can do this:
foo(arg1=d["arg1"],arg2=d["arg2"])
But is there any way to automate this? I mean a way to figure out which arguments are defined in the Dict and pass it automatically to the function.
Dictionaries with Symbol keys can be directly splatted into the function call:
julia> d = Dict(:arg1 => 10, :arg2 => 12)
Dict{Symbol, Int64} with 2 entries:
:arg1 => 10
:arg2 => 12
julia> f(; arg1, arg2) = arg1 + arg2
f (generic function with 1 method)
julia> f(; d...)
22
Note the semicolon in the function call, which ensure that the elements in d are interpreted as keyword arguments instead of positional arguments which just happen to be Pairs.
How can I declare a Julia function that returns a function with a specific signature. For example, say I want to return a function that takes an Int and returns an Int:
function buildfunc()::?????
mult(x::Int) = x * 2
return mult
end
What should the question marks be replaced with?
One thing needs to be made clear.
Adding a type declaration on the returned parameter is just an assertion, not part of function definition. To understand what is going on look at the lowered (this is a pre-compilation stage) code of a function:
julia> f(a::Int)::Int = 2a
f (generic function with 1 method)
julia> #code_lowered f(5)
CodeInfo(
1 ─ %1 = Main.Int
│ %2 = 2 * a
│ %3 = Base.convert(%1, %2)
│ %4 = Core.typeassert(%3, %1)
└── return %4
)
In this case since the returned type is obvious this assertion will be actually removed during the compilation process (try #code_native f(5) to see yourself).
If you want for some reason to generate functions I recommend to use the #generated macro. Be warned: meta-programming is usually an overkill for solving any Julia related problem.
#generated function f2(x)
if x <: Int
quote
2x
end
else
quote
10x
end
end
end
Now we have a function f2 where the source code of f2 is going to depend on the parameter type:
julia> f2(3)
6
julia> f2(3.)
30.0
Note that this function generation is actually happening during the compile time:
julia> #code_lowered f2(2)
CodeInfo(
# REPL[34]:1 within `f2'
┌ # REPL[34]:4 within `macro expansion'
1 ─│ %1 = 2 * x
└──│ return %1
└
)
Hope that clears things out.
You can use Function type for this purpose. From Julia documentation:
Function is the abstract type of all functions
function b(c::Int64)::Int64
return c+2;
end
function a()::Function
return b;
end
Which prints:
julia> println(a()(2));
4
Julia will throw exception for Float64 input.
julia> println(a()(2.0));
ERROR: MethodError: no method matching b(::Float64) Closest candidates are: b(::Int64)
The easiest way to explain the problem is with a code snippet.
function foo()
bar(x) = 1+x
println(bar(1)) #expecting a 2 here
bar(x) = -100000x
println(bar(1)) #expecting -100000
end
foo()
OUTPUT:
-100000
-100000
I imagine that the compiler is optimizing away a function that doesn't last long, but I haven't seen anything in the docs that would cause me to expect this behavior, and Google returns nothing but the docs. What is going on here?
This looks like a version of https://github.com/JuliaLang/julia/issues/15602. In the upcoming Julia 1.6 release this gives a warning:
julia> function foo()
bar(x) = 1+x
println(bar(1)) #expecting a 2 here
bar(x) = -100000x
println(bar(1)) #expecting -100000
end
WARNING: Method definition bar(Any) in module Main at REPL[1]:2 overwritten at REPL[1]:4.
foo (generic function with 1 method)
You should use anonymous functions like this instead:
julia> function foo()
bar = x -> 1+x
println(bar(1)) #expecting a 2 here
bar = x -> -100000x
println(bar(1)) #expecting -100000
end
foo (generic function with 1 method)
julia> foo()
2
-100000
Why does the order of the method definition differ in this case? It doesn't make much sense in my opinion.
julia> f() = 1
f (generic function with 1 method)
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f()
ERROR: UndefKeywordError: keyword argument arg not assigned
Stacktrace:
[1] f() at ./REPL[2]:1
[2] top-level scope at REPL[3]:1
julia> f() = 1
f (generic function with 1 method)
julia> f()
1
julia> f(arg=1)
1
The order of method definition gives different result because of how function
with keyword arguments fits into the mechanics of method dispatch in Julia 1.x.
As pointed in the comments above, the short answer is: because the second definition completely overwrites the other.
But I think this is not completely exact, lets see.
Case 1: with the order:
julia> f() = 2
f (generic function with 1 method)
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f()
ERROR: UndefKeywordError: keyword argument arg not assigned
The user defined function f() is overridden.
Case 2: reversing the order both methods are visible:
julia> f(;arg) = 1
f (generic function with 1 method)
julia> f() = 2
f (generic function with 1 method)
julia> f()
2
julia> f(arg=3)
1
When f(;arg) is lowered the compiler produces the method f(), without keyword arguments,
to handle the case where no keyword arguments are passed.
This produce two different outcomes:
Case 1: the produced method f() overrides the user defined f().
Case 2: the user defined f() overrides the produced method f() but f(;args) remains visible.
Note that from both cases it seems that as final result
we get a function f with 1 method, but indeed in the second case we have effectively 2 functions with 1 method each,
one that manage the user defined f() and one that manages the keyword arguments version f(;arg).
The full details of how keyword arguments method definition is lowered is detailed
in the docs
I'm having an issue with type in functions, I've managed to write the minimal code that explains the problem:
immutable Inner{B<:Real, C<:Real}
a::B
c::C
end
immutable Outer{T}
a::T
end
function g(a::Outer{Inner})
println("Naaa")
end
inner = Inner(1, 1)
outer = Outer(inner)
g(outer)
Will lead to the method error
MethodError: no method matching g(::Outer{Inner{Int64,Int64}})
So basically, I don't want to have to say what the types of Inner are, I just want the function to make sure that it's an Outer{Inner} and not Outer{Float64} or something.
Any help would be appreciated
The type Inner{Int64,Int64} is a concrete Inner type and it is not a subtype of
Inner{Real, Real}, since different concrete types of Inner (Int64 or Float64)
can have different representations in memory.
According to the documentation, function g should be defined as:
function g(a::Outer{<:Inner})
println("Naaa")
end
so it can accept all arguments of type Inner.
Some examples, after define g with <::
# -- With Float32 --
julia> innerf32 = Inner(1.0f0, 1.0f0)
Inner{Float32,Float32}(1.0f0, 1.0f0)
julia> outerf32 = Outer(innerf32)
Outer{Inner{Float32,Float32}}(Inner{Float32,Float32}(1.0f0, 1.0f0))
julia> g(outerf32)
Naaa
# -- With Float64 --
julia> innerf64 = Inner(1.0, 1.0)
Inner{Float64,Float64}(1.0, 1.0)
julia> outerf64 = Outer(innerf64)
Outer{Inner{Float64,Float64}}(Inner{Float64,Float64}(1.0, 1.0))
julia> g(outerf64)
Naaa
# -- With Int64 --
julia> inneri64 = Inner(1, 1)
Inner{Int64,Int64}(1, 1)
julia> outeri64 = Outer(inneri64)
Outer{Inner{Int64,Int64}}(Inner{Int64,Int64}(1, 1))
julia> g(outeri64)
Naaa
More details at the documentation: Parametric Composite Type
Update: The way to declare an immutable composite type (as in the original question), have changed to:
struct Inner{B<:Real, C<:Real}
a::B
c::C
end
struct Outer{T}
a::T
end
Furthermore, function g could be declared with a parametric type:
function g(a::T) where T Outer{<:Inner}
println(a)
println(a.a)
println(a.c)
end
And hence, there is no need to create an instance of Outer before calling the function.
julia> ft64 = Inner(1.1, 2.2)
Inner{Float64,Float64}(1.1, 2.2)
julia> g(ft64)
Inner{Float64,Float64}(1.1, 2.2)
1.1
2.2
julia> i64 = Inner(3, 4)
Inner{Int64,Int64}(3, 4)
julia> g(i64)
Inner{Int64,Int64}(3, 4)
3
4