Julia 1.1.1 - absolutely global variables - julia

I am coming from Fortran and I use global vectors of data over the full program. Usually I declare a module:
module xyz
real, allocatable :: vector(:,:,:) ! a 3 dim vector, undefined
end module
Now, in some place, let say Subroutine (Function) A, I am allocating memory for it and initialize to some values:
allocate(vector(10,20,30))
vector = ran()
Now, in any other unit of the program (Subroutine or function B, C, D...), if I am using the module, i.e:
using xyz
The above declared vector is available.
I was not able to obtain this behavior in the new technological wonder Julia 1.1. The scope rules are just giving a headache.

In Julia the rules for accessing variables from other modules are explained in detail here.
The key issues in your situation are the following things:
a variable is visible after using only if it is exported in the module
you are allowed to access the variable in other modules
you are not allowed to rebind a variable from other modules
This means that global variable binding creation operation is private to the module.
Here is a simple example module definition:
module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
now assume you define and later use it in REPL (it could be any other module)
julia> module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
Main.M
julia> using .M
Now you can access x:
julia> x
0-element Array{Int64,1}
julia> push!(x, 1)
1-element Array{Int64,1}:
1
julia> x
1-element Array{Int64,1}:
1
julia> x[1] = 10
10
julia> x
1-element Array{Int64,1}:
10
But not rebind x:
julia> x = 0
ERROR: cannot assign variable M.x from module Main
However, you can call a function defined inside M module to change the binding of x like this:
julia> x
1-element Array{Int64,1}:
10
julia> M.rebindx()
0-element Array{Int64,1}
julia> x
0-element Array{Int64,1}
This was possible because rebindx was defined inside module M so it has the right to change the binding of variable x defined in this module.

Related

How do I retrieve keyword arguments out of a field of splatted kwargs?

If I have a function signature like f(args...; kwargs...), how can I get a specific keyword out of kwargs? Naïvely typing kwargs.x does not work:
julia> f(args...; kwargs...) = kwargs.x
f (generic function with 1 method)
julia> f(x=1)
ERROR: type Pairs has no field x
Stacktrace:
[1] getproperty(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::Symbol) at ./Base.jl:20
[2] #f#7(::Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:x,),Tuple{Int64}}}, ::typeof(f)) at ./REPL[2]:1
[3] (::var"#kw##f")(::NamedTuple{(:x,),Tuple{Int64}}, ::typeof(f)) at ./none:0
[4] top-level scope at REPL[3]:1
This question appeared on the JuliaLang Slack channel in the #helpdesk. For an automatic invite to the very helpful julia slack, simply fill out https://slackinvite.julialang.org
The reason this happens is that splatted keyword arguments are not stored in a named tuple by default. We can see how they're stored like so:
julia> g(;kwargs...) = kwargs
g (generic function with 1 method)
julia> g(a=1)
pairs(::NamedTuple) with 1 entry:
:a => 1
julia> g(a=1) |> typeof
Base.Iterators.Pairs{Symbol,Int64,Tuple{Symbol},NamedTuple{(:a,),Tuple{Int64}}}
So the splatted kwargs are instead stored as some sort of iterator object. However, we can easily convert that kwargs iterator to a NamedTuple like so: (;kwargs...) and then access it in the way we'd expect, so your example would translate into
julia> f(args...; kwargs...) = (;kwargs...).x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
Of course, the more idiomatic way to do this would be to instead write the function as
julia> f(args...; x, kwargs...) = x
f (generic function with 1 method)
julia> f(x=1, y=2)
1
but this assumes you know the name you want to access (x) at the time when you write the function.
A brief sidenote: If we return to our example of g(;kwargs...) = kwargs, we can ask for the fieldnames of the iterator object the was returned like so:
julia> g(x=1, y=2) |> typeof |> fieldnames
(:data, :itr)
Hm, what is this data field?
julia> g(x=1, y=2).data
(x = 1, y = 2)
Aha! so we can actually get the kwargs as a named tuple using that, i.e. f(;kwargs...) = kwargs.data.x would work, but I wouldn't recommend this approach since it seems to rely on undocumented behaviour, so it may be a mere implementation detail that is not guaranteed to be stable across julia versions.

What is the difference between fields and properties in Julia?

Julia has the setter functions setproperty! and setfield! and the getter functions getproperty and getfield that operate on structs. What is the difference between properties and fields in Julia?
For example, the following seems to indicate that they do the same thing:
julia> mutable struct S
a
end
julia> s = S(2)
S(2)
julia> getfield(s, :a)
2
julia> getproperty(s, :a)
2
julia> setfield!(s, :a, 3)
3
julia> s
S(3)
julia> setproperty!(s, :a, 4)
4
julia> s
S(4)
fields are simply the "components" of a struct. The struct
struct A
b
c::Int
end
has the fields b and c. A call to getfield returns the object that is bound to the field:
julia> a = A("foo", 3)
A("foo", 3)
julia> getfield(a, :b)
"foo"
In early versions of Julia, the syntax a.b used to "lower", i.e. be the same as, writing getfield(a, :b). What has changed now is that a.b lowers to getproperty(a, :b) with the default fallback
getproperty(a::Type, v::Symbol) = getfield(a, v)
So by default, nothing has changed. However, authors of structs can overload getproperty (it is not possible to overload getfield) to provide extra functionality to the dot-syntax:
julia> function Base.getproperty(a::A, v::Symbol)
if v == :c
return getfield(a, :c) * 2
elseif v == :q
return "q"
else
return getfield(a, v)
end
end
julia> a.q
"q"
julia> getfield(a, :q)
ERROR: type A has no field q
julia> a.c
6
julia> getfield(a, :c)
3
julia> a.b
"foo"
So we can add extra functionality to the dot syntax (dynamically if we want). As a concrete example where this is useful is for the package PyCall.jl where you used to have to write pyobject[:field] while it is possible now to implement it such that you can write pyobject.field.
The difference between setfield! and setproperty! is analogous to the difference between getfield and getproperty, explained above.
In addition, it is possible to hook into the function Base.propertynames to provide tab completion of properties in the REPL. By default, only the field names will be shown:
julia> a.<TAB><TAB>
b c
But by overloading propertynames we can make it also show the extra property q:
julia> Base.propertynames(::A) = (:b, :c, :q)
julia> a.<TAB><TAB>
b c q

Why are variables and array elements inherited differently in Julia?

I'm trying to understand the scope rules in Julia. I've tried a for loop with z as a regular integer variable:
z = 2
for i = 1:4
z += 1
end
println(z)
and it gives me an UndefVarError: z not defined error, unless I put global z inside of the loop.
However, if I make z a 1x1 array it works perfectly fine without global:
z = [2]
for i = 1:4
z .+= 1
end
println(z)
$ julia test.jl
[6]
What's the difference between scopes of arrays and variables?
The contents of an array assigned to a global variable are constant in type:
julia> a = [1]
1-element Array{Int64,1}:
1
julia> push!(a, "s")
ERROR: MethodError: Cannot `convert` an object of type String to an
object of type Int64
And const typed globals are OK to be referenced within loops.

What does assignment like x\y = 1 mean in Julia?

While experimenting with Julia 1.0, I've noticed that I can do something like this:
x\y = 1
The REPL then shows:
\ (generic function with 1 method)
which means its a valid assignment (the interpreter doesn't complain). However, x, y, and x\y all remain undefined.
What is the meaning of such expression?
It is a new function definition that (kind of) shadows the left division operator \ in Base, since the left division operator is already defined for some types in Julia. The new function definition is \(x,y) = 1 (the names of function parameters do not matter) which works for all types of variables. This will prevent julia from loading Base.\ due to name conflict. No matter what the input is your new \ will return the same value.
julia> x\y = 5
julia> a = 3; b = 4;
julia> a\b
5
julia> c = "Lorem ipsum"; d = "dolor";
julia> c\d
5
If you have already used the \ that is defined in Base, your redefinition will throw an error saying that extending Base.\ requires an explicit import with import Base.\. The behavior of defining \ after import Base.\ however will be different. It will extend the operator Base.\.
julia> 1\[1,3]
2-element Array{Float64,1}:
1.0
3.0
julia> import Base.\
julia> x\y=3
\ (generic function with 152 methods)
julia> 1\[1,3]
2-element Array{Int64,1}:
3
3

How do I create a method that takes any iterable collection of strings?

I have a function, f. I want to add a method that takes any container of Strings. For example, I want to write a method that generates the following when needed:
f(xs::Array{String, 1}) = ...
f(xs::DataArray{String, 1}) = ...
f(xs::ITERABLE{String}) = ...
Is this possible to do in Julia's type system? Right now, I'm using a macro to write a specialized method when I need it.
#make_f(Array{String, 1})
#make_f(DataArray{String, 1})
This keeps things DRY, but it feels...wrong.
Can't you just use duck typing? I.e., just assume that you're feeding the function an object of the right type and throw an error if at some point e.g. you don't have a string in your iterable.
This should improve once you can really talk about iterables using traits; currently there is no iterable type. Scott's answer, for example, will not work with a tuple of strings, even though that is iterable.
E.g.
julia> f(x) = string(x...) # just concatenate the strings
f (generic function with 1 method)
julia> f(("a", "á"))
"aá"
julia> f(["a", "á"])
"aá"
julia> f(["a" "b"; "c" "d"]) # a matrix of strings!
"acbd"
At least in Julia 0.4, the following should work:
julia> abstract Iterable{T} <: AbstractVector{T}
julia> f{T<:Union{Vector{String},Iterable{String}}}(xs::T) = 1
f (generic function with 1 method)
julia> x = String["a", "é"]
2-element Array{AbstractString,1}:
"a"
"é"
julia> f(x)
1

Resources