I am trying to create a module in Julia which has a variable incremented each time one of its function is called.
module A
a = 0
export get_and_increment_a
function get_and_increment_a()
a = a + 1
return a
end
end
using .A
println(get_and_increment_a())
println(get_and_increment_a())
I would expect that the prinln() give me
1
2
But I have the following error message:
UndefVarError: a not defined
Stacktrace:
[1] get_and_increment_a() at ./In[1]:8
[2] top-level scope at In[2]:2
Anyone has an idea how to solve this issue?
The variable was not previously declared, if you want to use without declaring such a variable, you have to import from some library or just declare in another file and import to the current one.
Move a = 0 inside the function body. All variables inside are local only.
https://docs.julialang.org/en/v1/manual/variables-and-scoping/#Local-Scope
Related
I create an object and then try to use it in a loop
a = 0
for i in 1:2
a += 1
end
However, this results in the following error:
UndefVarError: a not defined
Have I forgotten how loops work or what is going wrong?
The point is that your a is a global variable and in Julia versions between 1.0 and 1.4.2 the local scoping for variables within loops was introduced. More precisely if you do not explicitly say you want to mutate a global variable (global a += 1) a new variable within a local scope is introduced.
The best thing to do is to upgrade to Julia 1.5. Julia 1.5 has introduced back soft scoping in the REPL.
If you need to stick with the current Julia version you could use global keyword or place your code in a function or use Jupyter notebook instead (that has soft scoping) or surround your code around let...end block such as:
let
a = 0
for i in 1:2
a += 1
end
a
end
So here's the code I was trying to execute in Julia:
i = begin
i = 5
while(i<=10)
println(i)
i+=1
end
end
It's just basically a simple code to print the value of i from 5 to 10 but it's messing with me
Are you in the REPL? What you are probably running into is that begin does not introduce its own scope, so i = 5 declares i as a global variable. Because while does introduce its own scope, if you do println(i), it only looks for i in its local scope where it is not defined, because i exists only as a global variable. You can add a line global i at the beginning of the body of the while loop to tell all code after that to use the global i, but note that global variables come with their own performance caveats. An arguably better solution would be to use let instead of begin, which does introduce a new scope, but note that then you can of course not access i afterwards, because it is now only local to the let block.
This behavior will actually be changed in the upcoming release of Julia 1.5, so your code should then just work.
Your issue is scope. When you enter into a loop, variables created inside the loop are local to the loop and destroyed after it exits. i is not currently defined inside your while loop, so you get the error. The quick fix is to tell Julia you want the loop to have access to the global i variable you defined at the top by adding global i immediately after the while statement. You also don't need the begin block, and naming the block i is immediately overwritten by the next statement defining i.
I would like to build a Julia application where a user can specify a function using a configuration file (and therefore as a string). The configuration file then needs to be parsed before the function is evaluated in the program.
The problem is that while the function name is known locally, it is not known in the module containing the parser. One solution I have come up with is to pass the local eval function to the parsing function but that does not seem very elegant.
I have tried to come up with a minimal working example here, where instead of parsing a configuration file, the function name is already contained in a string:
module MyFuns
function myfun(a)
return a+2
end
end
module MyUtil
# in a real application, parseconfig would parse the configuration file to extract funstr
function parseconfig(funstr)
return eval(Meta.parse(funstr))
end
function parseconfig(funstr, myeval)
return myeval(Meta.parse(funstr))
end
end
# test 1 -- succeeds
f1 = MyFuns.myfun
println("test1: $(f1(1))")
# test 2 -- succeeds
f2 = MyUtil.parseconfig("MyFuns.myfun", eval)
println("test2: $(f2(1))")
# test 3 -- fails
f3 = MyUtil.parseconfig("MyFuns.myfun")
println("test3: $(f3(1))")
The output is:
test1: 3
test2: 3
ERROR: LoadError: UndefVarError: MyFuns not defined
So, the second approach works but is there a better way to achieve the goal?
Meta.parse() will transform your string to an AST. What MyFuns.myfun refers to depends on the scope provided by the eval() you use.
The issue with your example is that the eval() inside MyUtil will evaluate in the context of that module. If that is the desired behavior, you simply miss using MyFuns inside MyUtil.
But what you really want to do is write a macro. This allows the code to be included when parsing your program, before running it. The macro will have access to a special argument __module__, which is the context where the macro is used. So __module__.eval() will execute an expression in that very scope.
foo = "outside"
module MyMod
foo = "inside"
macro eval(string)
expr = Meta.parse(string)
__module__.eval(expr)
end
end
MyMod.#eval "foo"
# Output is "outside"
See also this explanation on macros:
https://docs.julialang.org/en/v1/manual/metaprogramming/index.html#man-macros-1
And for the sake of transforming the answer of #MauricevanLeeuwen into the framework of my question, this code will work:
module MyFuns
function myfun(a)
return a+2
end
end
module MyUtil
macro parseconfig(funstr)
__module__.eval(Meta.parse(funstr))
end
end
f4 = MyUtil.#parseconfig "MyFuns.myfun"
println("test4: $(f4(1))")
I saw this example in the Julia language documentation. It uses something called Base. What is this Base?
immutable Squares
count::Int
end
Base.start(::Squares) = 1
Base.next(S::Squares, state) = (state*state, state+1)
Base.done(S::Squares, s) = s > S.count;
Base.eltype(::Type{Squares}) = Int # Note that this is defined for the type
Base.length(S::Squares) = S.count;
Base is a module which defines many of the functions, types and macros used in the Julia language. You can view the files for everything it contains here or call whos(Base) to print a list.
In fact, these functions and types (which include things like sum and Int) are so fundamental to the language that they are included in Julia's top-level scope by default.
This means that we can just use sum instead of Base.sum every time we want to use that particular function. Both names refer to the same thing:
Julia> sum === Base.sum
true
Julia> #which sum # show where the name is defined
Base
So why, you might ask, is it necessary is write things like Base.start instead of simply start?
The point is that start is just a name. We are free to rebind names in the top-level scope to anything we like. For instance start = 0 will rebind the name 'start' to the integer 0 (so that it no longer refers to Base.start).
Concentrating now on the specific example in docs, if we simply wrote start(::Squares) = 1, then we find that we have created a new function with 1 method:
Julia> start
start (generic function with 1 method)
But Julia's iterator interface (invoked using the for loop) requires us to add the new method to Base.start! We haven't done this and so we get an error if we try to iterate:
julia> for i in Squares(7)
println(i)
end
ERROR: MethodError: no method matching start(::Squares)
By updating the Base.start function instead by writing Base.start(::Squares) = 1, the iterator interface can use the method for the Squares type and iteration will work as we expect (as long as Base.done and Base.next are also extended for this type).
I'll grant that for something so fundamental, the explanation is buried a bit far down in the documentation, but http://docs.julialang.org/en/release-0.4/manual/modules/#standard-modules describes this:
There are three important standard modules: Main, Core, and Base.
Base is the standard library (the contents of base/). All modules
implicitly contain using Base, since this is needed in the vast
majority of cases.
lets say I have written a function for adding two numbers.
function [result] = add_twonum(a1,a2)
result = a1+a2;
endfunction
in the main file, when I call
result = add_twonum(1,2)
I expect result = 3 .
However it says
!--error 4
Undefined variable: add_twonum
Please help me. I have used Matlab a lot but never scilab. I tried every possible way I know of. like changing current directory etc etc.
In the main file, you need to execute the function first, with
exec('add_twonum.sci');
assuming add_twonum.sci is the file which contains your function. Then you can call the function:
result = add_twonum(a1,a2);