Why can I change the value of an array from another module but not the value of a variable - global-variables

I have a module that I would like to use as a set of Global variables.
file Global.jl:
module Global
export data
export dataLoaded
data = zeros(Int32, 20, 12, 31, 24, 60, 5);
dataLoaded = false;
end
file main2.jl:
include("Global.jl")
import .Global
println(Global.data[10,1,1,1,1,1])
println(Global.dataLoaded)
Global.data[10,1,1,1,1,1] = 5
println(Global.data[10,1,1,1,1,1])
Global.dataLoaded = true
println(Global.dataLoaded)
I was not expecting that dataLoaded can not be changed in the same way data is. Is there any way to allow changing dataLoaded?
$ /usr/local/julia-1.2.0/bin/julia main2.jl
0
false
5
ERROR: LoadError: cannot assign variables in other modules
Stacktrace:
[1] setproperty!(::Module, ::Symbol, ::Bool) at ./Base.jl:14
[2] top-level scope at /usr/home/.../main2.jl:11
[3] include at ./boot.jl:328 [inlined]
[4] include_relative(::Module, ::String) at ./loading.jl:1094
[5] include(::Module, ::String) at ./Base.jl:31
[6] exec_options(::Base.JLOptions) at ./client.jl:295
[7] _start() at ./client.jl:464
in expression starting at /usr/home/.../main2.jl:11

As I have commented in How to define global variables to be shared later in Julia you are not allowed to change a binding of a variable from outside the module.
First, to explain what is going on consider:
x = [1,2,3]
x[1] = 10
The second operation x[1] = 10 does not change a binding of x, it only changes the value stored in the first element of vector x (as vectors are mutable).
On the other hand writing:
y = 1
y = 10
First defines y to have a value 1 (of type Int which is immutable), and then y = 10 rebinds y to hold 10.
Now - how you can solve your problem. There are two approaches:
The first is to define a setter function inside your Global module like this:
function setdataloaded(value::Bool)
global dataLoaded = value
end
As setdataloaded is defined in Global module it can change the bindings of variables in this module. Then you can call setdataloaded from outside of the module to change the value of dataLoaded.
The second is to use a mutable container instead of an immutable one. The simplest is Ref. So you can define:
dataLoaded = Ref(false)
and then you can get is value as dataLoaded[] and set its value like dataLoaded[] = true from outside of the Global module (because this time you are mutating the contents of the container and not rebinding dataLoaded).
EDIT
As noted in the comment technically you can evaluate dataLoaded = 10 expression within Global module even from code outside of this module by writing:
#eval Global dataLoaded = 10
or
Global.eval(:(dataLoaded = 10))
using the fact that each module (except baremodule but this is a rare use case) has its own module-local definition of eval.
In a way the eval approach is a kind of first approach I have described (using a setter function) that is allowed by default.

Related

JULIA include statement error: applicable method may be too new

I want to import a function present in a julia file somewhere during runtime
just like in python we have importlib.import_module to import module is there something present in julia
I'm new to julia and I'm not sure how to do that.
I have to import a function main from another julia file and want to run it but I have to also check a condition before that if the condition is true then I want to import the function.
EDIT
I have a file
main.jl
function myMain()
s1 = "Hello"
s2 = "World!"
include("functions/hello.jl")
say(s1, s2)
end
myMain()
hello.jl
function say(s1, s2)
print(s1, s2)
end
Error
ERROR: LoadError: MethodError: no method matching say(::String, ::String)
The applicable method may be too new: running in world age 32378, while current world is 32379.
Closest candidates are:
say(::Any, ::Any) at ~/Desktop/julia_including/functions/hello.jl:1 (method too new to be called from this world context.)
Stacktrace:
[1] myMain()
# Main ~/Desktop/julia_including/main.jl:5
[2] top-level scope
# ~/Desktop/julia_including/main.jl:8
in expression starting at /home/shivansh/Desktop/julia_including/main.jl:8
It works fine when I don't use include inside the myMain() function in main.jl
Julia contrary to Python is a compiled language.
Hence for maximum performance all functions should be known at the compilation time so efficient assembly code can be generated.
Hence generally you want to avoid syntax like the one you are proposing and have the inlude outside of the function.
However, if you really know what you are doing, why you are doing this and need such functionality then comes the world of Julia metaprogramming.
The code is the following:
function myMain()
s1 = "Hello"
s2 = "World!"
include("say.jl")
Base.invokelatest(say, s1, s2)
end
Now you can do:
julia> myMain()
HelloWorld!
Honestly, it just sounds like you wanna do this
if some_condition
include("/path/to/some/file/that/you/need.jl")
else
include("/path/to/some/OTHER/file/that/you/need.jl")
end
EDIT
I think though, after seeing the error that you added, what you wanna do is define your function multiple times instead, and with different argument types:
function say(x::Any, y::Any)
println("Default")
end
function say(x::String, y::Any)
println("String in arg1: $x")
end
function say(x::Any, y::String)
println("String in arg2: $y")
end
function say(x::String, y::String)
println("String in args 1 and 2: $x $y")
end
That way using say differs based on the datatype of the arguments:
julia> say("Foo", "Bar")
String in args 1 and 2: Foo Bar
julia> say("Foo", 2)
String in arg1: Foo
julia> say(0, "Bar")
String in arg2: Bar
and if you have two different functions that act on 2 strings you can do this instead:
struct MySayFunctionType{Symbol}
end
function say(x::String, y::String, ::MySayFunctionType{:Type1})
println("Type1 function is being called: $x $y")
end
function say(x::String, y::String, ::MySayFunctionType{:Type2})
println("Type2 function is being called: $x $y")
end
and then use these like this
if condition
say("Foo", "Bar", MySayFunctionType{Symbol("Type1")}() )
else
say("Foo", "Bar", MySayFunctionType{Symbol("Type2")}() )
end
and if you want a default version of this function to be called -- say Type2 -- you can just add a default value for the third argument like this:
function say(x::String, y::String, z::MySayFunctionType{:Type2}=MySayFunctionType{Symbol("Type2")}())
println("Type2 function is being called: $x $y")
end
The reason this works is because "MySayFunctionType{:Type1}" is considered to be a different type than "MySayFunctionType{:Type2}" so multiple dispatch would consider that as well.

How to define a constant in Julia struct

I want to define a struct:
struct unit_SI_gen
x::Float32
const c = 2.99792458e8
speed(x)=c*x
end
However, it raise an error :
syntax: "c = 2.99792e+08" inside type definition is reserved
I know I cant use struct as class in python, but I can not find how to solve this problem.
How to define a constant in struct ?
Given I agree with what was said above about normal usage of struct in Julia, it is actually possible to define what was requested in the question using an inner constructor:
struct unit_SI_gen{F} # need a parametric type to make it fast
x::Float32
c::Float64 # it is a constant across all unit_SI_gen instances
speed::F # it is a function
function unit_SI_gen(x)
c = 2.99792458e8
si(x) = c*x
new{typeof(si)}(x, c, si)
end
end
I second #Tasos's comment, you should probably make yourself familiar with Julia's structs first. The relevant part of the documentation is probably here.
Since you declared your struct as struct (in contrast to mutable struct) it is immutable and hence all (immutable) fields of the struct are constants in the sense that they can't be changed.
julia> struct A
x::Int
end
julia> a = A(3)
A(3)
julia> a.x = 4
ERROR: type A is immutable
Stacktrace:
[1] setproperty!(::A, ::Symbol, ::Int64) at .\sysimg.jl:19
[2] top-level scope at none:0
Note, that they get their unchangeable value in the construction process and not in the struct definition.
Also, methods should generally live outside of the struct definition.

How to initialize a composite type in Julia-lang and be accessible to all functions without it being passed as a function parameter?

In Julia Lang, how can a composite type have its parameter values allocated during runtime and be accessible to all the functions in the file?
I am looking for a feature similar to the 'static' keyword in Java. This is to avoid having to send the composite type in every function call as it is initialized from reading a file once and many functions rely on it; and not altered afterwards but the values are not known at compile time. ( I recall the usages of structs in Julia but am not sure if this would change anything )
In Julia you can define global variables. Each Julia module (or baremodule) has its global scope.
If you declare a global variable const then its type may not change (but its binding to a value possibly can).
The second part of your question is mutability of such a global constant. If the type of the global constant variable is immutable (e.g. numbers, strings, structs, tuples, named tuples) then it will not be possible to change its value. However, it will be still possible to rebind the variable to a new value (as long as the new value has an appropriate type, we will get a warning that the binding has changed - see examples below).
A good example of such an approach in Julia Base is Base.GLOBAL_RNG variable (with the exception that it is mutable) - it holds a state of a default random number generator in Julia.
Here is a simple example using struct:
module E
struct A # immutable
x::Int
end
const a = A(1) # global constant in module E
f() = println("a: $a")
function g()
global a = A(10) # rebinding of a global variable requires global keyword
end
function h()
a.x = 100
end
end # module
If you execute this in REPL you can test the behavior:
julia> E.a # we test the value of a global variable in module E
Main.E.A(1)
julia> E.f() # function f() from this module can access it
a: Main.E.A(1)
julia> E.h() # we cannot mutate fields of a
ERROR: type is immutable
Stacktrace:
[1] setproperty! at .\sysimg.jl:9 [inlined]
[2] h() at .\REPL[1]:16
[3] top-level scope
julia> E.g() # but we can change the binding, we get a warning
WARNING: redefining constant a
Main.E.A(10)
julia> E.a
Main.E.A(10)
julia> E.a = E.A(1000) # the binding cannot be changed outside the module
ERROR: cannot assign variables in other modules
Stacktrace:
[1] setproperty!(::Module, ::Symbol, ::Main.E.A) at .\sysimg.jl:15
[2] top-level scope
If you define a global constant in REPL then rebinding its value additionally emits a warning (here are some more examples with a global variable defined in REPL scope):
julia> global const z = E.A(5)
Main.E.A(5)
julia> z.x = 10
ERROR: type A is immutable
Stacktrace:
[1] setproperty!(::Main.E.A, ::Symbol, ::Int64) at .\sysimg.jl:9
[2] top-level scope
julia> z = E.A(2)
WARNING: redefining constant z
Main.E.A(2)
julia> z = "test" # we cannot change a type of const variable
ERROR: invalid redefinition of constant z
Here are the relevant sections of the Julia Manual:
global scope: https://docs.julialang.org/en/latest/manual/variables-and-scoping/#Global-Scope-1
constants: https://docs.julialang.org/en/latest/manual/variables-and-scoping/#Constants-1
composite types: https://docs.julialang.org/en/latest/manual/types/#Composite-Types-1
global keyword: https://docs.julialang.org/en/latest/base/base/#global
EDIT: added missing global keyword in the definition of g function.

define Julia functions with optional positional arguments

From this link, it says:
# You can define functions with optional positional arguments
function defaults(a,b,x=5,y=6)
return "$a $b and $x $y"
end
defaults('h','g') # => "h g and 5 6"
defaults('h','g','j') # => "h g and j 6"
defaults('h','g','j','k') # => "h g and j k"
try
defaults('h') # => ERROR: no method defaults(Char,)
defaults() # => ERROR: no methods defaults()
catch e
println(e)
end
I think the purpose of this example is to show that, if the provided arguments are less than the default ones, the function will also return the default ones.
But why the error appears when one or no argument is provided? i.e. how do I know that providing two arguments are okay, but providing one or none is not okay?
The answer is quite simple:
For the function defaults it is required to give at least two arguments (a and b that have no default value), because the language specifications do not allow required positional arguments to be in an "unknown state". If no default value is provided, the interpreter raises the exception. Citing the manual, the design reason behind optional arguments:
Optional arguments are actually just a convenient syntax for writing multiple method definitions with different numbers of arguments
It is like they are creating some "functions" that already knows which are some of the arguments. You write:
defaults(a,b,x=5,y=6)
and internally exist:
defaults(a, b, x, y)
defaults(a, b, x, 6)
defaults(a, b, 5, 6)
(and notice that I'm not writing defaults(a, b, 5, y) to keep the discussion simple).
Calling defaults with 3 arguments is ok, but you will override the default value of x. Calling it with 4 arguments is ok, but you will override the default value of x and y. Calling it with less than 2 arguments is not ok, because the interpreter does not know what to return (since you need a and b to interpolate the returned string).
You may define a function that will require only one positional argument in this way:
function defaults(a,b=4,x=5,y=6)
return "$a $b and $x $y"
end
There are more information also here.

Multiple dispatch for methods of a class in Julia

My question is how can I overload certain method within a certain class in Julia?
In other words suppose I have a following definition of a class:
type Sometype
prop::String
setValue::Function
# constructor
function Sometype()
this = new ()
this.prop = ""
####### v1 #######
this.setValue = function(v::Real)
println("Scalar Version was Invoked!")
# operations on scalar...
# ...
end
####### v2 #######
this.setValue = function(v::Vector{Real})
println("Vector Version was Invoked!")
# operations on vector...
# ...
end
####### v3 #######
this.setValue = function(v::Matrix{Real})
println("Matrix Version was Invoked!")
# operations on Matrix...
# ...
end
return this
end
end
So when I say in my main code:
st = Sometype()
st.setValue(val)
depending on whether val is a scalar, vector or matrix it would invoke the corresponding version of a setvalue method. Right now, with definition above, it overrides definitions of setvalue with the last one (matrix version in this case).
This style of Object-Oriented Programming (OOP), in which the functions live inside objects, is not used in Julia.
Instead, in Julia we just define methods outside the object definition. E.g.:
type Sometype
prop::String
end
Sometype(v::Real) = ...
function Sometype{T}(v::Vector{T}) # parametric type
....
end
Note that the first definition is an example of the short-hand way of defining simple functions on a single line, and the second example is for more complicated functions.
As pointed out by #GnimucKey, instead of v::Vector{Real}, you should use v::Vector{T} with the function parametrised by T. I have changed my answer accordingly. An argument specified as v::Vector{Real} will never match an argument, since it is impossible to create objects of the abstract type Real, and the invariance of types means that an object like Vector{Float64} is not a subtype of Vector{Real}.

Resources