Julia what does a nameless value in the function header mean? - julia

I often see something like the following in Julia:
convert(::Type{Point{Float64}}, ::Float64)
how does the (:: work? And what is the terminology for this?

Your answer can be found in the Julia documentation for defining conversions. To quote (with types switched to make it even more straightforward to read):
The type of the first argument of this method is a singleton
type, Type{Point{Float64}}, the only instance of which is
Point{Float64}. Thus, this method is only invoked when the first
argument is the type value Point{Float64}. Notice the syntax used
for the first argument: the argument name is omitted prior to the ::
symbol, and only the type is given. This is the syntax in Julia for a
function argument whose type is specified but whose value is never
used in the function body. In this example, since the type is a
singleton, there would never be any reason to use its value within the
body.
(Emphasis mine)
You will also encounter the foo(::SomeType) syntax in error messages, when trying to invoke a function with arguments of the wrong type (after all you can't show the argument names of a variant that does not exist). E.g:
julia> foo(x::Bool) = 3
foo (generic function with 1 method)
julia> foo(5)
ERROR: `foo` has no method matching foo(::Int64)

Related

How is a string assigned to a struct in this Julia code?

I'm looking at the this thread
I'm trying to understand the following line of code:
struct Foo end
(::Type{Float64})(::Foo) = "not a Float64"
It seems like it assigns a string to a variable of type Foo, but I don't see any variable declaration on the left-hand-side.
What is going on?
There's a few things going on here.
The line is a method, not a variable assignment. f(x) = "blah" is one-line syntax for
function f(x)
"blah"
end
The (::Foo) part is actually 1 annotated argument for the method. An argument's name can be omitted, you just can't use the argument in the method body because no variable references it. The argument only dispatches the method. For example, f(::Foo) = "blah" would work for f(Foo()) but not f(Bar()).
The (::Type{Float64}) part instead of a method name indicates this is a functor. (f::F)(x) = x*f.suffix means that instances of struct F can be called like a method F(".net")("something"). The name f isn't a method name and will not exist for you to use like one, it's there to reference the instance of F to be used in the method. The name can be omitted if it's not used in the method (::F)(x) = x*".com".
Type{Float64} is a type whose only instance is Float64, so this means that you can only use this method by calling Float64(Foo()). It seems to me that defining a method Base.Float64(::Foo) = "not a Float64" would be equivalent, I don't actually know why they opted for functor syntax.
When you see annotations surrounded by parentheses, the annotation can only belong to whatever is in the parentheses and to the left. f::Foo means f is annotated with Foo, f(::Foo) means an anonymous argument is annotated with Foo.

Specify the type of variable keyword arguments in Julia [duplicate]

Is it possible to type function kwargs in Julia?
The following works for standard Varargs.
function int_args(args::Integer...)
args
end
int_args(1, 2, 3)
# (1, 2, 3)
int_args(1, 2, 3.0)
# ERROR: MethodError: `int_args` has no method matching int_args(::Int64, ::Int64, ::Float64)
However, when applying this same syntax to kwargs, all function calls seem to error.
function int_kwargs(; kwargs::Integer...)
kwargs
end
int_kwargs(x=1, y=2)
# ERROR: MethodError: `__int_kwargs#0__` has no method matching __int_kwargs#0__(::Array{Any,1})
Normal keyword arguments can have types, as in function f(x; a::Int=0), but this doesn't work for "rest" keyword arguments. Also note that since we currently don't dispatch on keyword arguments, the a::Int in this case is a type assertion and not a dispatch specification.
It looks like this case is not handled well, and needs a better error message at least. I'd encourage you to file an issue at https://github.com/JuliaLang/julia/issues.
I'm not sure what the syntax x::T... should mean for keyword arguments. In the case of varargs, it's clear that each element of x should have type T, but for rest keyword arguments each element is actually a symbol-value pair. Of course we could give it the meaning you describe (all values have type T), but this doesn't seem to come up very often. Keyword arguments tend to be quite heterogeneous, unlike varargs which are more like lists or arrays.

Anonymous arguments in julia

Julia permits function and method definitions with unnamed arguments.
This is not mentioned in the functions documentation, nor is it explicitly discussed in the methods documentation. For example:
function myfunc(::Int)
println("Hello!")
end
How should I describe this behavior (I've googled "anonymous arguments" without success), and when is it useful?
This behavior is useful for method dispatch, when you care only about argument type not argument value. Most often this is a case when what you dispatch on is a singleton type.
An example is:
julia> Vector{String}(undef, 3)
3-element Array{String,1}:
#undef
#undef
#undef
This function is defined in the following way:
Array{T,1}(::UndefInitializer, m::Int) where {T} =
ccall(:jl_alloc_array_1d, Array{T,1}, (Any, Int), Array{T,1}, m)
And you can see that we only care that the first argument was of UndefInitializer type, which is in turn defined as:
struct UndefInitializer end
const undef = UndefInitializer()
We see that UndefInitializer is a singleton type, so we do not care about the value of a variable of this type, but only about its type.
Another common singleton type in Base is Missing. Here are example definitions from Base of standard functions getting a Missing as an argument:
for f in (:(acos), :(acosh), :(asin), :(asinh), :(atan), :(atanh),
:(sin), :(sinh), :(cos), :(cosh), :(tan), :(tanh),
:(exp), :(exp2), :(expm1), :(log), :(log10), :(log1p),
:(log2), :(exponent), :(sqrt))
#eval $(f)(::Missing) = missing
end
(again - you can see that we do not care about the value of the variable - we know its type is Missing so we return missing)
In the Julia manual you have examples of such methods e.g. here but admittedly as far as I can tell the manual does not give a name for this style of method definition.

julia introspection - get name of variable passed to function

In Julia, is there any way to get the name of a passed to a function?
x = 10
function myfunc(a)
# do something here
end
assert(myfunc(x) == "x")
Do I need to use macros or is there a native method that provides introspection?
You can grab the variable name with a macro:
julia> macro mymacro(arg)
string(arg)
end
julia> #mymacro(x)
"x"
julia> #assert(#mymacro(x) == "x")
but as others have said, I'm not sure why you'd need that.
Macros operate on the AST (code tree) during compile time, and the x is passed into the macro as the Symbol :x. You can turn a Symbol into a string and vice versa. Macros replace code with code, so the #mymacro(x) is simply pulled out and replaced with string(:x).
Ok, contradicting myself: technically this is possible in a very hacky way, under one (fairly limiting) condition: the function name must have only one method signature. The idea is very similar the answers to such questions for Python. Before the demo, I must emphasize that these are internal compiler details and are subject to change. Briefly:
julia> function foo(x)
bt = backtrace()
fobj = eval(current_module(), symbol(Profile.lookup(bt[3]).func))
Base.arg_decl_parts(fobj.env.defs)[2][1][1]
end
foo (generic function with 1 method)
julia> foo(1)
"x"
Let me re-emphasize that this is a bad idea, and should not be used for anything! (well, except for backtrace display). This is basically "stupid compiler tricks", but I'm showing it because it can be kind of educational to play with these objects, and the explanation does lead to a more useful answer to the clarifying comment by #ejang.
Explanation:
bt = backtrace() generates a ... backtrace ... from the current position. bt is an array of pointers, where each pointer is the address of a frame in the current call stack.
Profile.lookup(bt[3]) returns a LineInfo object with the function name (and several other details about each frame). Note that bt[1] and bt[2] are in the backtrace-generation function itself, so we need to go further up the stack to get the caller.
Profile.lookup(...).func returns the function name (the symbol :foo)
eval(current_module(), Profile.lookup(...)) returns the function object associated with the name :foo in the current_module(). If we modify the definition of function foo to return fobj, then note the equivalence to the foo object in the REPL:
julia> function foo(x)
bt = backtrace()
fobj = eval(current_module(), symbol(Profile.lookup(bt[3]).func))
end
foo (generic function with 1 method)
julia> foo(1) == foo
true
fobj.env.defs returns the first Method entry from the MethodTable for foo/fobj
Base.decl_arg_parts is a helper function (defined in methodshow.jl) that extracts argument information from a given Method.
the rest of the indexing drills down to the name of the argument.
Regarding the restriction that the function have only one method signature, the reason is that multiple signatures will all be listed (see defs.next) in the MethodTable. As far as I know there is no currently exposed interface to get the specific method associated with a given frame address. (as an exercise for the advanced reader: one way to do this would be to modify the address lookup functionality in jl_getFunctionInfo to also return the mangled function name, which could then be re-associated with the specific method invocation; however, I don't think we currently store a reverse mapping from mangled name -> Method).
Note also that (1) backtraces are slow (2) there is no notion of "function-local" eval in Julia, so even if one has the variable name, I believe it would be impossible to actually access the variable (and the compiler may completely elide local variables, unused or otherwise, put them in a register, etc.)
As for the IDE-style introspection use mentioned in the comments: foo.env.defs as shown above is one place to start for "object introspection". From the debugging side, Gallium.jl can inspect DWARF local variable info in a given frame. Finally, JuliaParser.jl is a pure-Julia implementation of the Julia parser that is actively used in several IDEs to introspect code blocks at a high level.
Another method is to use the function's vinfo. Here is an example:
function test(argx::Int64)
vinfo = code_lowered(test,(Int64,))
string(vinfo[1].args[1][1])
end
test (generic function with 1 method)
julia> test(10)
"argx"
The above depends on knowing the signature of the function, but this is a non-issue if it is coded within the function itself (otherwise some macro magic could be needed).

How to create an object like `()` in user space

In Julia the empty tuple is both a type and an instance of that type. So isa((),()) is true. Is it possible to create a similar object myself?
I don't believe so. In fact, in Julia 0.4 isa((),()) is no longer true. The type of () is now Tuple{}:
julia> VERSION
v"0.4.0-dev+5441"
julia> typeof(())
Tuple{}
julia> isa((),()) # Throws an error since () is no longer considered a Type
ERROR: TypeError: isa: expected Type{T}, got Tuple{}
I think the only remaining objects that are an instance of themselves are Any, Type and DataType.

Resources