Julia: Updating a Float64 within a function - julia

I am trying to create a function to update a Float64 argument. The example below should be able to clarify what I am trying to achieve.
a=1.2
function fun!(a)
a=3.4;
end
Unfortunately, a is updated only in local scope. Is there a way to do it? I thought that passing a pointer to the function could help, but I am not sure how to do it in Julia.

You can't do this. A Float64 is not a mutable value, so you cannot mutate the value of a. You can only replace a by a separate Float64. This is what an immutable value is.
More lower level (and usually true, although there are exceptions): Float64s are represented by their actual bytes, while mutables are pointers to the actual bytes. The actual value of a mutable is its pointer. Mutating means changing values at the memory location that the pointer is pointing to, but this doesn't exist for the immutable.

To complete the answer and if you have a C/C++ background:
mutable objects are generally allocated on the heap and have stable memory addresses. They are passed by reference
immutable objects are on the stack and are passed by copy
Also, AFAIK, the ! of fun! is only a name convention to draw attention it has nothing to do with julia internals. You can write fun is you want.
Examples:
v=ones(3); # [1 1 1]
isimmutable(v) # false -> v is passed by reference
foo(v::Array{Float64}) = v .*= 2; # hence v can be modified
foo(v);
v # [2 2 2]
v=Int(1) # 1
isimmutable(v) # true -> v is passed by copy
foo(v::Int) = v *= 2 # use a local copy of v
foo(v) # returns 2, but it is a local copy
v # 1 (unmodified because we worked with a copy)
Also see FAQ
Ref{} example:
Isaiah Norton comment
foo(r::Ref{Int}) = r[] *= 2
r=Ref{Int}(1) # Base.RefValue{Int64}(1)
foo(r);
r # Base.RefValue{Int64}(2)

Related

Julia: Is there a way to convert a number into a pointer?

As the title says, is there a way to convert a number (say a float or interger) that stores an address into a pointer?
For example, in Julia one can convert a pointer into a integer by doing:
data = [1, 2]
ptr = pointer( data ) # Has type "Ptr{Int64}"
address = UInt64( ptr ) # Has type "UInt64"
How can one reverse these steps to get back the pointer? Say:
ptr = unknownFunction(address) # Has type "Ptr{Int64}"
Alternatively, is there a way to directly change the address held by a pointer? Say one has a pointer with:
Ptr{Int64} #0x0000000036f94110
How can you modify the address it hold to another number, for example 0x000000003ffffff0.
Yes, that it possible, but only if you already know what data lies at that pointer:
julia> arr = [15, 6, 1];
julia> address = UInt(pointer(arr));
julia> unsafe_load(Ptr{Int}(address))
15
For your second question, Julia supports pointer arithmetic. Here, you can add 8 bytes to the pointer of the first element in the array:
julia> unsafe_load(Ptr{Int}(address) + 8)
6
But I would echo other people's reservations about using pointers in Julia. They are only really useful for interoperation with e.g. C, or for doing questionable low-level bithacking tricks.

Why do Julia variables not exist in the scope of for-loops?

I am using Julia to do some basic integration estimation and am getting an UndefVarError with the following code:
using ExcelReaders
er = ExcelReaders
etInt = 0
waveLen = er.readxl("AM0AM1_5.xls", "Spectra!A3:A2004")
eT = er.readxl("AM0AM1_5.xls", "Spectra!B3:B2004")
gTilt = er.readxl("AM0AM1_5.xls", "Spectra!C3:C2004")
dirSol = er.readxl("AM0AM1_5.xls", "Spectra!D3:D2004")
function trArea(r::Real, l::Real, v::Array, x::Int)
return ((1/2) * (v[x] + v[x+1]) * (r-l))
end
for x in 1:length(waveLen)-1
etInt += trArea(waveLen[x], waveLen[x+1], eT, x)
end
The error points to line 16. To my understanding, this means that etInt is undefined within the scope of the for-loop. Why is this the case with Julia?
To my understanding, this means that etInt is undefined within the scope of the for-loop.
Global variables do exist in all local scopes (such as a for-loop). However, from Julia version 1.0 on they are read-only in those local scopes. Write access to global variables must be made explicit.
To give a simple example, while
julia> x = 1
1
julia> for i in 1:3
#show x # only reading a global variable
end
x = 1
x = 1
x = 1
works just fine,
julia> for i in 1:3
x += 1 # writing to a global variable
#show x
end
ERROR: UndefVarError: x not defined
Stacktrace:
[1] top-level scope at .\REPL[3]:2 [inlined]
[2] top-level scope at .\none:0
doesn't work. This can be healed by putting an explicit global annotation:
julia> for i in 1:3
global x += 1
#show x
end
x = 2
x = 3
x = 4
For more information, see the scoping section in the Julia documentation.
Note that people have complained about this a lot and it's actively being discussed on github and discourse (e.g. here and here).
Note that the effects of these scoping rules, like the potentially unintuitive error message that you're getting, really only hit you when you operate in a global scope (like the REPL). If you put everything in a function - any local scope - you get the expected behavior:
julia> function f()
x = 1
for i in 1:3
x += 1 # no global necessary
#show x
end
nothing
end
f (generic function with 1 method)
julia> f()
x = 2
x = 3
x = 4
This is anyways what you should do to really get fast runtime as global variables are almost always bad for performance (see the Performance Tips).
Also notice that everything will work as expected in Jupyter notebooks using IJulia. The reason is that people are coming up with context dependent solutions as well, in this case SoftGlobalScope.jl. Something similar is/was being considered for the REPL. These are the main places where people work interactively.
So, to summarize, you can either just learn the scoping rules (which is dead simple) or you wait for some of the discussed "fixes" to land as has already been the case for jupyter notebooks.
It seems that there was scope change implemented in 1.0 that has affected this behavior in Julia in the context of REPL and notebooks. Some other users have complained about it e.g.,
https://discourse.julialang.org/t/undefvarerror-on-loop-iterator-in-while-loop/14747
https://github.com/JuliaLang/julia/issues/28789
It seems a proposal has been made to rectify the oddity:
https://discourse.julialang.org/t/new-scope-solution/16707/

Accessing values in expression using a macro

I'm wondering whether it's possible to define a macro that can modify the values of an expression only if the values are of a specific type?
Here's a minimal example:
type Special
x::Int
end
f1(s, n::Special) = println("f1", s, n)
f2(s, n::Special) = println("f2", s, n)
x1 = Special(3)
x2 = Special(5)
expr = :(
f1("this is f1", x1),
f2("this is f2", x2)
)
Now a macro might be able to examine the values of the arguments to the functions, determine that x1 and x2 are of type Special, run some function to modify their values, say by changing 3 to 4 and 5 to 2 (it might involve comparing two values), then pass the expression back to the caller. The final result would be equivalent to calling:
f1("this is f1", 4)
f2("this is f2", 2)
I found that it's possible to access the values in a macro via:
eval(eval(filter(x -> typeof(eval(x)) == Special, expr.args[1].args))[1]).x
=> 3
but although this works it looks wrong, and I'm might either be doing it wrong or trying to do something too way out...
No, you should never try to check types or values inside macros. Using eval to figure out the type or value of something in a macro may work in very limited situations, but it'll break in almost every real use. Instead, just have the macro insert a call to a generic function — that's where Julia excels at picking apart types (as method dispatch) and values (within the method):
munge_special(x::Special) = Special(x.x + 42)
munge_special(x) = x
macro do_something_special(x)
return :(munge_special($(esc(x))))
end
julia> #do_something_special Special(2)
Special(44)
julia> #do_something_special 3
3

What is the simplest way to iterate over an array of arrays?

Let x::Vector{Vector{T}}. What is the best way to iterate over all the elements of each inner vector (that is, all elements of type T)? The best I can come up with is a double iteration using the single-line notation, ie:
for n in eachindex(x), m in eachindex(x[n])
x[n][m]
end
but I'm wondering if there is a single iterator, perhaps in the Iterators package, designed specifically for this purpose, e.g. for i in some_iterator(x) ; x[i] ; end.
More generally, what about iterating over the inner-most elements of any array of arrays (that is, arrays of any dimension)?
Your way
for n in eachindex(x), m in eachindex(x[n])
x[n][m]
end
is pretty fast. If you want best speed, use
for n in eachindex(x)
y = x[n]
for m in eachindex(y)
y[m]
end
end
which avoids dereferencing twice (the first dereference is hard to optimize out because arrays are mutable, and so getindex isn't pure). Alternatively, if you don't need m and n, you could just use
for y in x, for z in y
z
end
which is also fast.
Note that column-major storage is irrelevant, since all arrays here are one-dimensional.
To answer your general question:
If the number of dimensions is a compile-time constant, see Base.Cartesian
If the number of dimensions is not a compile-time constant, use recursion
And finally, as Dan Getz mentioned in a comment:
using Iterators
for z in chain(x...)
z
end
also works. This however has a bit of a performance penalty.
I'm wondering if there is a single iterator, perhaps in the Iterators package, designed specifically for this purpose, e.g. for i in some_iterator(x) ; x[i] ; end
Today (in Julia 1.x versions), Iterators.flatten is exactly this.
help?> Iterators.flatten
flatten(iter)
Given an iterator that yields iterators, return an iterator that
yields the elements of those iterators. Put differently, the
elements of the argument iterator are concatenated.
julia> x = [1:5, [π, ℯ, 42], 'a':'e']
3-element Vector{AbstractVector}:
1:5
[3.141592653589793, 2.718281828459045, 42.0]
'a':1:'e'
julia> for el in Iterators.flatten(x)
print(el, " ")
end
1 2 3 4 5 3.141592653589793 2.718281828459045 42.0 a b c d e
julia>

Why assignment in for loop can change global variable while it cannot in function?

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.

Resources