I am trying to call a general method from a specific one, but cannot figure out how.
function fn(x)
# generic
...
end
function fn(x :: String)
# I want to call the generic version here
val = fn(x)
# do something with val and then return it
...
end
Is this possible?
A workaround is using a helper function that can be called from both generic and specific methods. e.g.
function helper(x)
# main work is here
...
end
function fn(x)
# generic
helper(x)
end
function fn(x :: String)
val = helper(x)
# now use the val to do something
...
end
Without using such helpers, is there a way to control the dispatch to select a particular method to use? Is there something like :before and :after keywords and call-next-method from lisp CLOS in Julia?
You can use the invoke function:
julia> function fn(x)
#info "generic $x"
end
fn (generic function with 1 method)
julia> function fn(x :: String)
#info "before"
invoke(fn, Tuple{Any}, x)
#info "after"
end
fn (generic function with 2 methods)
julia> fn(10)
[ Info: generic 10
julia> fn("10")
[ Info: before
[ Info: generic 10
[ Info: after
(just to be clear - the printing of "before" and "after" is only to highlight what gets executed in what sequence - the only thing that is related to method dispatch here is the invoke function)
Related
The name of the struct to instantiate will be passed by the caller to my program. Then I would need to instantiate the corresponding struct for the same for further processing.
For example, if the struct is defined like this
struct A end
and I have a function defined as
function load(struct_name::AbstractString)
if struct_name == "A"
return A()
elseif struct_name == "B"
return B()
elseif ..... # and so on
end
end
it will work. But is there a more direct way like return struct_name() instead of having n number of if else statements? I see that Julia supports reflection. How can that be used to support the above use case?
I would recommend not doing it in production code, but you can do the following:
function load(struct_name::AbstractString)
invoke(eval(Symbol(struct_name)),Tuple{})
end
strut_name via eval will get resolved in the global scope of the module.
It is safer to use a dictionary as #EPo suggested.
An example of dictionary-based dispatch. Dict("a" => A, "b" => B)[tag] selects a constructor, and () calls it.
struct A end
struct B end
function dispatch(tag)
return Dict("a" => A, "b" => B)[tag]()
end
#assert dispatch("a") == A()
If you care about default values to handle unexpected parameter, for example dispatch('zzz'),
you can make recourse to get().
As a side note about risks of eval() there is a small collection of powerful warning references in a neighboring Python question. In short, eval() is a big security hole and a 'smell' (warning sign) for a questionable design of a program.
You could use a macro instead:
julia> module Load
export #load
macro load(struct_name::Symbol)
return :($(esc(struct_name))())
end
end
Main.Load
julia> using Main.Load: #load
julia> struct A end
julia> struct B end
julia> #load A
A()
julia> #macroexpand #load B
:(B())
julia> #load C
ERROR: UndefVarError: C not defined
Stacktrace:
[1] top-level scope at none:0
I was wondering if there was a way to use Symbols for multiple dispatch, but also include a "catch-all method". i.e. something like
function dispatchtest{alg<:Symbol}(T::Type{Val{alg}})
println("This is the generic dispatch. The algorithm is $alg")
end
function dispatchtest(T::Type{Val{:Euler}})
println("This is for the Euler algorithm!")
end
The second one works and matches what's in the manual, I'm just wondering how you get the first one to work.
You can do it this way:
julia> function dispatchtest{alg}(::Type{Val{alg}})
println("This is the generic dispatch. The algorithm is $alg")
end
dispatchtest (generic function with 1 method)
julia> dispatchtest(alg::Symbol) = dispatchtest(Val{alg})
dispatchtest (generic function with 2 methods)
julia> function dispatchtest(::Type{Val{:Euler}})
println("This is for the Euler algorithm!")
end
dispatchtest (generic function with 3 methods)
julia> dispatchtest(:Foo)
This is the generic dispatch. The algorithm is Foo
julia> dispatchtest(:Euler)
This is for the Euler algorithm!
I'm trying to understand how parametric types work in Julia.
Suppose I have a function foo, which takes an Integer (i.e. non-parametric type), and I want to assert this function to return a vector, whose elements are subtypes of Real. From documentation I deduced that it should be implemented as follows:
function foo{T<:Real}(n::Integer)
# come code to generate variable vec
return vec::Vector{T}
end
But it is not working. What am I doing wrong?
Parametric types are used to parameterise the inputs to a function, not the outputs. If your function is type-stable (read about what that means in the performance tips), then the output of the function can be automatically inferred by the compiler based on the input types, so there should be no need to specify it.
So your function might look something like this:
function foo{T<:Real}(n::T)
#some code to generate vec
return(vec)
end
For example, you can generate a vector of the appropriate type within the body of your function, e.g. something like this:
function f1{T<:Number}(x::T)
y = Array(T, 0)
#some code to fill out y
return(y)
end
But note that T must appear in the argument definitions of the inputs to the function, because this is the purpose of parametric types. You'll get an error if T does not appear in the description of the inputs. Something like this doesn't work:
f{T<:Number}(x::Vector) = x
WARNING: static parameter T does not occur in signature for f at none:1.
The method will not be callable.
f (generic function with 1 method)
But this does, and is type stable, since if the input types are known, then so are the outputs
f{T<:Number}(x::Vector{T}) = x
A parametric method or a constructor of a parametric type
A function is called using the traditional parenthesis syntax:
julia> f(2,3)
5
The above rule is true for both parametric and non-parametric methods.
So, one should not try to call a parametric method like: f{atype}(2,3). I think the source of this mall-usage could be the syntax of calling a parametric type constructor:
julia> typeof(Array{Int})
DataType
julia> Array{Int}(2)
2-element Array{Int32,1}:
57943068
72474848
But in the case of a parametric method:
julia> same_type{T}(x::T, y::T) = true;
julia> typeof(same_type)
Function
julia> same_type{Int}
ERROR: TypeError: Type{...} expression: expected Type{T}, got Function
So with this introduction it has become clear that something like:
function foo{T<:Real}(n::Integer)
.....
end
would be useless, because the value of T won't be determined from caller the arguments.
Make benefit of parametric methods
julia> same_type{T}(x::T, y::T) = true;
julia> same_type(x,y) = false;
julia> same_type(1, 2)
true
julia> same_type(1, 2.0)
false
The main purpose of parametric methods is to let dispatch find the right method to call with respect to argument types when calling a function, but also it has the following idiomatic side effect:
Method type parameters are not restricted to being used as the types
of parameters: they can be used anywhere a value would be in the
signature of the function or body of the function.
julia> mytypeof{T}(x::T) = T
mytypeof (generic function with 1 method)
julia> mytypeof(1)
Int64
Now, let's go back to the main problem of:
How to write a method with Parametric return types?
If your method is already parametric, you could use the parameter value as return type as in the above mytypeof sample or e.g:
julia> newoftype{T}(x::T,n) = T(n)
newoftype (generic function with 1 methods)
julia> newoftype([1,2],4)
4-element Array{Int32,1}:
57943296
72475184
141142104
1970365810
But making return type of a method, a function of arguments value is a straightforward functionality and could be simply done without need to a parametric method. really many of typical methods do this job e.g:
julia> Array(Int,4)
4-element Array{Int32,1}:
126515600
72368848
72474944
0
julia> Array(Float64,4)
4-element Array{Float64,1}:
-2.122e-314
0.0
5.12099e-292
5.81876e-292
It could be done using a argument type of Type e.g:
julia> myarray(T::Type,n::Int)=Array(T,n);
Is there any introspective magic that would give me a list of functions defined in a module?
module Foo
function foo()
"foo"
end
function bar()
"bar"
end
end
Some mythical function like:
functions_in(Foo)
Which would return: [foo,bar]
The problem here is that both names and whos list exported names from a module. If you wanted to see them then you would need to do something like this:
module Foo
export foo, bar
function foo()
"foo"
end
function bar()
"bar"
end
end # module
At this point both names and whos would list everything.
If you happen to be working at the REPL and for whatever reason did not want to export any names, you could inspect the contents of a module interactively by typing Foo.[TAB]. See an example from this session:
julia> module Foo
function foo()
"foo"
end
function bar()
"bar"
end
end
julia> using Foo
julia> whos(Foo)
Foo Module
julia> names(Foo)
1-element Array{Symbol,1}:
:Foo
julia> Foo.
bar eval foo
Somehow the tab completion is looking up un-exported names, so there must be a way to get Julia to tell them to you. I just don't know what that function is.
EDIT
I did a little digging. The un-exported function Base.REPLCompletions.completions seems to work, as demonstrated in a continuation of the REPL session we were previously using:
julia> function functions_in(m::Module)
s = string(m)
out = Base.REPLCompletions.completions(s * ".", length(s)+1)
# every module has a function named `eval` that is not defined by
# the user. Let's filter that out
return filter(x-> x != "eval", out[1])
end
functions_in (generic function with 1 method)
julia> whos(Foo)
Foo Module
julia> names(Foo)
1-element Array{Symbol,1}:
:Foo
julia> functions_in(Foo)
2-element Array{UTF8String,1}:
"bar"
"foo"
Suppose I have the following type:
type Foo
a::Int64
b::Int64
end
I can instantiate this with
bar = Foo(1,2)
Is there a way to use keywords here, because in the above I have to remember that a is first, and b is second. Something like this:
bar = Foo(a=1, b=2)
Edit:
The solution by spencerlyon2 doesn't work if called from the function:
#!/usr/bin/env julia
type Foo
a::Float64
b::Float64
end
function main()
Foo(;a=1, b=2.0) = Foo(a,b)
bar = Foo(a=1, b=2.0)
println(bar.a)
end
main()
Why? Is there a workaround?
Edit 2:
Doesn't work from inside a function:
#!/usr/bin/env julia
type Foo
a::Int64
b::Int64
end
function main()
Foo(;a=1, b=2) = Foo(a,b)
bar = Foo(a=1, b=2)
println(bar.a)
end
main()
but if take it out of the function -- it works:
#!/usr/bin/env julia
type Foo
a::Int64
b::Int64
end
# function main()
Foo(;a=1, b=2) = Foo(a,b)
bar = Foo(a=1, b=2)
println(bar.a)
# end
# main()
Yep, but you will need default values for the arguments:
julia> type Foo
a::Int64
b::Int64
end
julia> Foo(;a=1, b=2) = Foo(a, b)
Foo
julia> Foo(b=10)
Foo(1,10)
julia> Foo(a=40)
Foo(40,2)
julia> Foo(a=100, b=200)
Foo(100,200)
Edit
Let's break down the syntax Foo(;a=1, b=1) = Foo(a, b).
First, defining a function with the same name as a type defines a new constructor for that type. This means we are defining another function that will create objects of type Foo. There is a whole chapter on constructors in the manual, so if that term is unfamiliar to you you should read up on them.
Second, Julia distinguishes between positional and keyword arguments. Positional arguments are the default in Julia. With positional arguments names are assigned to function arguments based on the order in which the arguments were defined and then passed into the function. For example if I define a function f(a, b) = .... I know that the first argument I pass to f will be referred to as a within the body of the function (no matter what the name of the variable is in the calling scope).
Keyword arguments are treated differently in Julia. You give a function's keyword arguments non-default values using the syntax argument=value when calling the function. In Julia you tell the compiler that certain arguments are to be keyword arguments by separating them from the standard positional arguments with a semicolon (;) and giving them default values. For example, if we define g(a; b=4) = ... we can give a a value by making it the first thing passed to g and b a value by saying b=something. If we wanted to call the g function with arguments a=4, b=5 we would write g(4; b=5) (note the ; here can be replaced by a ,, but I have found it helps me remember that b is a keyword argument if I use a ; instead).
With that out of the way, we can finally understand the syntax above:
Foo(;a=1, b=2) = Foo(a, b)
This creates a new constructor with zero positional arguments and two keyword arguments: a and b, where a is given a default value of 1 and b defaults to 2. The right hand side of that function declaration simply takes the a and the b and passes them in order to the default inner constructor (that was defined automatically for us when we declared the type) Foo.
EDIT 2
I figured out the problem you were having when defining a new outer constructor inside a function.
The lines
function main()
Foo(;a=1, b=2.0) = Foo(a,b)
actually create a completely new function Foo that is local to the main function. So, the left hand side creates a new local Foo and the the right hand side tries to call that new local Foo. The problem is that there is not a method defined for the local Foo that takes two positional Int64 arguments.
If you really want to do this you need to tell the main function to add a method to the Foo outer function, by specifying that Foo belongs to the global scope. This works:
function main()
global Foo
Foo(;a=1, b=2.0) = Foo(a,b)
bar = Foo(a=1, b=2.0)
println(bar.a)
end
About using inner constructors. Sure you can do this, but you will also want to define a default inner constructor. This is because if you do not define any new inner constructors, Julia generates a default one for you. If you do decide to create one of your own, then you must create the default constructor by hand if you want to have it. The syntax for doing this is
type Foo
a::Int64
b::Int64
# Default constructor
Foo(a::Int64, b::Int64) = new(a, b)
# our new keyword constructor
Foo(;a::Int64=1, b::Int64=2) = new (a, b)
end
I should note that for this particular use case you almost certainly do not want to define the keyword version as an inner constructor, but rather as an outer constructor like I did at the beginning of my answer. It is convention in Julia to use the minimum number of inner constructors as possible -- using them only in cases where you need to ensure invariant relationships between fields or partially initialize an object.