how do I create/use a global variable inside of a function?
If I make the Global variable in one function, how do I reference it in a subsequent function?
Here is what you would need to do:
function a()
global z = 0
print(z)
end
function b()
global z += 1
print(z)
end
Note that in Function b, if you do not reference z as global z, it will look in the local scope of the function where there is no z variable defined and give an error:
julia> b()
ERROR: UndefVarError: z not defined
julia> a() # defines z in global scope
0
julia> b() # works now because z has been defined
1
Edit: As Michael pointed out in the comment below, it is not generally a good idea to use this sort of global paradigm in practice. This can result in code that is difficult to debug, understand, and potentially invalid outputs.
Related
In Fortran, we know that we can in a module define a global variable (use the private property), so that we can use the subroutines in the module to set or change the values of that variable. See below,
module Mod
integer, parameter :: r8=selected_real_kind(15,9)
real(kind=r8), private, save :: var
contains
subroutine f(x)
real(kind=r8) :: x
var = 2.0_r8*x
end subroutine f
end
As we can see, we can call f(x) and set the var in the module to be 2x.
Now in Julia, it seems like below,
module Mod
global var
function f(x::Float64)
global var = 2.0*x
return nothing
end
I mean, in the function, if var is on the left hand side, do I have to specify the key word 'global' every time?
I also tried to give the global var a type, like
global var::Float64
But it gives me an error
syntax: type declarations on global variables are not yet supported
It seems i can only do either just specify nothing, like just
global var
or give it a value while setting its type,
global var=0.0::Float64
Is there better to just give the global var a type before using it?
This is a way to make what you want and to make it efficient:
julia> const x = Ref(0)
Base.RefValue{Int64}(0)
julia> function f(y)
x[] = y
end
f (generic function with 1 method)
julia> x[]
0
julia> f(10)
10
julia> x[]
10
julia> f("10")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
julia> f(5.0)
5.0
julia> x[]
5
Comments:
I make x a const which makes sure that the compiler will know its type (so that it can optimize code)
I make x a Ref to allow mutability of its contents and to make it clear later in the x[] = y statement that x[] part refers to a global variable (as variable x is not defined in a local scope of f)
As you can see in the example I could not use "10" in the call of f as it does not have a matching type. Note though that I could use 5.0 (a float) as it can be converted to an integer.
In Julia, I know of three ways to define a named multiline function:
1.
function f(x, y)
...
end
2.
f = function(x, y)
...
end
3.
f(x, y) = begin
...
end
They all seem to produce the same outcome.
Is there any difference? Which one should be used and why?
1 and 3 are functionally identical, but 1 is preferred stylistically. The "short form function declaration" f(x,y) = … is typically used (and encouraged) for one-line definitions — that is, without a begin block.
2 is different. It's creating an anonymous function, and then assigning it to f. Note that unlike the bindings created by 1 and 3, you can actually reassign f to completely different things. This means that Julia cannot assume that f will always call that function, which means that it cannot do any of its normal optimizations. Now, if you used const f = function(x, y) …, then f is a constant binding and it should behave similarly to the other declarations. But note that f is still just a binding to an anonymous function — the function itself doesn't know what its name is! So it'll print as #1 (generic function with 1 method) instead of f (generic function with 1 method).
See https://docs.julialang.org/en/stable/manual/functions/ for more details.
Definitions 1 and 3 are equivalent (the difference is only style, option 1 is usually preferred). They define function f for which you can implement multiple methods (https://docs.julialang.org/en/v1/manual/methods/).
Definition 2 creates an anonymous function and assigns it to a global variable f. I would not encourage it in general.
If you would call such a function inside other function using name f the result would not be type stable (variable f from global scope would have to be resolved). Anonymous functions are usually used in situations where the name is not important.
Actually there are two other ways to define multiple line anonymous function (again - I do not encourage it but show it for completeness):
f = x -> begin
...
end
and
f = identity() do x
...
end
In the code below, I expect both f and the final a to return 3. But in fact they both return 2. Why is this? Hasn't 3 replaced 2 in the enclosing environment at the time the promise is evaluated?
a <- 1
f <- function(a){
a <<- 3
cat(a)
}
f(a <- 2)
a
Note that If I use an = instead of a <- in the call to f, the final a is 3 as expected, but f remains 2.
Let's walk through the code
a <- 1
assigns the value 1 to the name a in the global environment.
f <- function(a){...}
creates a function saved to the name f in the global environment.
f(a <- 2)
Now we are calling the function f with the expression a<-2 as a parameter. This expression is not evaluated immediately. It is passed as a promise. The global value of a remains 1.
Now we enter the body of the function f. The expression we've passed in is assigned to the local variable a in the function scope (still un-evaluated) and a in the global remains 1. The fact they they both involve the symbol a is irrelevant. There is no direct connection between the two a variables here.
a <<- 3
This assigns the value of 3 to a in a parent scope via <<- rather than the local scope as <- would do. This means that the a refered to here is not the local a that now hold the parameter passed to the function. So this changes the value of a in the global scope to 3. And finally
cat(a)
Now we are finally using the value that was passed to the function since the a here refers to the a in the local function scope. This triggers the promise a <- 2 to be run in the calling scope (which happens to be the global scope). Thus the global value of a is set to 2. This assignment expression returns the right-hand-side value so "2" is displayed from cat().
The function exits and
a
shows the value of the a in the global environment which is now a. It was only the value 3 in the brief moment between the two expressions in f.
If you where to call
f( a=2 )
This is very different. Now we are not passing an expression to the function anymore, we are passing the value 2 to the named function parameter a. If you tried f(x=2) you would get an error that the function doesn't recognize the parameter named "x". There is no fancy lazy expression/promise evaluation in this scenario since 2 is a constant. This would leave the global value set to 3 after the function call. f(a <- 2) and f(a = a <- 2) would behave the same way.
The following returns 1, indicating a local x is created.
x = 1
bar() = (x = 2)
bar() # 2
x # 1
This returns 5, indicating both x refer to the global one.
x = 1
for i = 1:5
x = i
end
x # 5
A reference example: this time for loop fails to update the global.
x = 10
function foo(n)
for i = 1:n
x = i
end
1
end
foo(2), x # 1, 10
Update
The link from #matt-b is very useful. This is in fact the result of Soft Scope vs Hard Scope, see here. To wrap up, function scope used to work like loop scope, until there was a break change with the introduction of soft scope & hard scope. The documentation is not quite up to speed.
If you want to use global x in function scope you must declare it global
x = 10
function foo(n)
global x
for i = 1:n
x = i
end
1
end
foo(2), x # 2
As #colinfang have commented, in Julia function scope and loop scope are treat differently and I think the following sentence from documentation try to address this fact:
Julia uses lexical scoping, meaning that a function’s scope does not
inherit from its caller’s scope, but from the scope in which the
function was defined.
The link from #matt-b is very useful. This is in fact the result of Soft Scope vs Hard Scope, see here. To wrap up, function scope used to work like loop scope, until there was a break change with the introduction of soft scope & hard scope. The documentation is not quite up to speed.
I've looked at the other lexical scoping questions in R and I can't find the answer. Consider this code:
f <- function(x) {
g <- function(y) {
y + z
}
z <- 4
x + g(x)
}
f(3)
f(3) will return an answer of 10. My question is why? At the point g() is defined in the code, z has not been assigned any value. At what point is the closure for g() created? Does it "look ahead" to the rest of the function body? Is it created when the g(x) is evaluated? If so, why?
When f is run, the first thing that happens is that a function g is created in f's local environment. Next, the variable z is created by assignment.
Finally, x is added to the result of g(x) and returned. At the point that g(x) is called, x = 3 and g exists in f's local environment. When the free variable z is encountered while executing g(x), R looks in the next environment up, the calling environment, which is f's local environment. It finds z there and proceeds, returning 7. It then adds this to x which is 3.
(Since this answer is attracting more attention, I should add that my language was a bit loose when talking about what x "equals" at various points that probably do not accurately reflect R's delayed evaluation of arguments. x will be equal to 3 once the value is needed.)