ERROR: setfield! immutable struct cannot be changed in Julia - julia

I am updating some old code and I am now getting errors: ERROR: setfield! immutable struct cannot be changed in Julia when I try to change the values of an immutable struct. Is there a common workaround for how I can edit/mutate those values (this may be a rather silly question given that the type is explicitly immutable so it's not a good idea generally to try and change it).

As far as I remember immutables can not be safely manipulated even if you get a memory pointer to them and try to use ccal.
However, as an imperfect workaround you can consider using Setfield package as in the example below.
using Setfield
struct S
a::Int
b::String
end
Using:
julia> s = S(2, "hello")
S(2, "hello")
julia> s = #set s.a = 5
S(5, "hello")
Note that in many scenarios this might be faster than actually changing type of S to mutable.

Related

Initialise empty\undef Dict while using abstract types

I want to generate a Dict with undef values so I can later loop over the keys and fill in correct values. I can initialise an such a Dict using concrete types in the following way and it all works fine:
currencies = ["USD", "AUD", "GBP"]
struct example
num::Float64
end
undef_array = Array{example}(undef,3)
Dict{String,example}(zip(currencies, undef_array))
When my struct has an abstract type however I can still generate the undef array but I cannot create the dict. I get an error "UndefRefError: access to undefined reference"
abstract type abstract_num end
struct example2
num::abstract_num
end
undef_array = Array{example2}(undef,3)
Dict{String,example2}(zip(currencies, undef_array))
Although it is possible to create such a Dict with a concrete array:
struct numnum <: abstract_num
num::Float64
end
def_array = [example2(numnum(5.0)), example2(numnum(6.0)), example2(numnum(4.5))]
Dict{String,example2}(zip(currencies, def_array))
Question
My question is whether it is possible to generate a Dict with undef values of a type that relies on an abstract type? Is it is possible what is the best way to do it?
In your second (not working) example, undef_array is an array whos elements aren't initialized:
julia> undef_array = Array{example2}(undef,3)
3-element Array{example2,1}:
#undef
#undef
#undef
The reason is that it's not possible to instantiate an object of type example2 because your abstract type abstract_num (the type of the field of example2) doesn't have any concrete subtypes and, thus, can't be instantiated either. As a consequence even indexing undef_array[1] gives an UndefRefError and, hence, also zip won't work.
Compare this to the first case where the array elements are (arbitrarily) initialized:
julia> undef_array = Array{example}(undef,3)
3-element Array{example,1}:
example(1.17014136e-315)
example(1.17014144e-315)
example(1.17014152e-315)
and undef_array[1] works just fine.
Having said that, I'm not really sure what you try to achieve here. Why not just create a mydict = Dict{String, example2}() and fill it with content when the time comes? (As said above, you would have to define concrete subtypes of abstract_num first)
For performance reasons you should, in general, avoid creating types with fields of an abstract type.
Try:
a=Dict{String,Union{example3,UndefInitializer}}(currencies .=>undef)
However, for representing missing values the type Missing is usually more appropriate:
b=Dict{String,Union{example3,Missing}}(currencies .=>missing)
Please note that typeof(undef) yields UndefInitializer while typeof(missing) yields Missing - hence the need for Union types in the Dict. The dot (.) you can see above (.=>) is the famous Julia dot operator.
Moreover, I recommend to keep to Julia's naming conversion - struct and DataType names should start with a Capital Letter.
Last but not least, in your first example where concrete type Float64 was given, Julia has allocated the array to some concrete address in memory - beware that it can contain some garbage data (have a look at console log below):
julia> undef_array = Array{example}(undef,3)
3-element Array{example,1}:
example(9.13315366e-316)
example(1.43236026e-315)
example(1.4214423e-316)

julia static field of composite type

In Julia am I allowed to create & use static fields? Let me explain my problem with a simplified example. Let's say we have a type:
type Foo
bar::Dict()
baz::Int
qux::Float64
function Foo(fname,baz_value,qux_value)
dict = JLD.load(fname)["dict"] # It is a simple dictionary loading from a special file
new(dict,baz_value,quz_value)
end
end
Now, As you can see, I load a dictionary from a jld file and store it into the Foo type with the other two variables baz and qux_value. Now, let's say I will create 3 Foo object type.
vars = [ Foo("mydictfile.jld",38,37.0) for i=1:3]
Here, as you can see, all of the Foo objects load the same dictionary. This is a quite big file (~10GB)and I don't want to load it many times. So,
I simply ask that, is there any way in julia so that, I load it just once and all of there 3 types can reach it? (That's way I simply use Static keyword inside the question)
For such a simple question, my approach might look like silly, but as a next step, I make this Foo type iterable and I need to use this dictionary inside the next(d::Foo, state) function.
EDIT
Actually, I've found a way right now. But I want to ask that whether this is a correct or not.
Rather than giving the file name to the FOO constructor, If I load the dictionary into a variable before creating the objects and give the same variable into all of the constructors, I guess all the constructors just create a pointer to the same dictionary rather than creating again and again. Am I right ?
So, modified version will be like that:
dict = JLD.load("mydictfile.jld")["dict"]
vars = [ Foo(dict,38,37.0) for i=1:3]
By the way,I still want to hear if I do the same thing completely inside the Foo type (I mean constructor of it)
You are making the type "too special" by adding the inner constructor. Julia provides default constructors if you do not provide an inner constructor; these just fill in the fields in an object of the new type.
So you can do something like:
immutable Foo{K,V}
bar::Dict{K,V}
baz::Int
qux::Float64
end
dict = JLD.load("mydictfile.jld")["dict"]
vars = [Foo(dict, i, i+1) for i in 1:3]
Note that it was a syntax error to include the parentheses after Dict in the type definition.
The {K,V} makes the Foo type parametric, so that you can make different kinds of Foo type, with different Dict types inside, if necessary. Even if you only use it for a single type of Dict, this will give more efficient code, since the type parameters K and V will be inferred when you create the Foo object. See the Julia manual: http://docs.julialang.org/en/release-0.5/manual/performance-tips/#avoid-fields-with-abstract-containers
So now you can try the code without even having the JLD file available (as we do not, for example):
julia> dict = Dict("a" => 1, "b" => 2)
julia> vars = [Foo(dict, i, Float64(i+1)) for i in 1:3]
3-element Array{Foo{String,Int64},1}:
Foo{String,Int64}(Dict("b"=>2,"a"=>1),1,2.0)
Foo{String,Int64}(Dict("b"=>2,"a"=>1),2,3.0)
Foo{String,Int64}(Dict("b"=>2,"a"=>1),3,4.0)
You can see that it is indeed the same dictionary (i.e. only a reference is actually stored in the type object) by modifying one of them and seeing that the others also change, i.e. that they point to the same dictionary object:
julia> vars[1].bar["c"] = 10
10
julia> vars
3-element Array{Foo{String,Int64},1}:
Foo{String,Int64}(Dict("c"=>10,"b"=>2,"a"=>1),1,2.0)
Foo{String,Int64}(Dict("c"=>10,"b"=>2,"a"=>1),2,3.0)
Foo{String,Int64}(Dict("c"=>10,"b"=>2,"a"=>1),3,4.0)

Julia - Array of UTF8 behavior

I encountered a problem which I've solved, but why the solution works doesnt make sense to me
I had a function similar to this one
function testB(a::Array{AbstractString})
println(a)
end
running it like so gave me
testB(convert(Array{UTF8String},["a","b"]))
ERROR: MethodError: `testB` has no method matching
testB(::Array{UTF8String,1})
Note that Im not manually converting to UTF8 in reality, its for demonstration, in reality I have an AbstractString array, but when I fetch elements from it, they become UFT8
My solution reads in short
function testA{T <: AbstractString}(a::Array{T})
println(a)
end
running this method gives
testA(convert(Array{UTF8String},["a","b"]))
UTF8String["a","b"]
Can anyone tell me why testA works but testB doesnt?
Also, is there a name for this {T <: SomeDataType} notation?
While UTF8String is a subtype of AbstractString, Array{UTF8String} is not a subtype of Array{AbstractString} (no covariance). Hence your testB does not work. (But testB(convert(Array{AbstractString},["a","b"])) should work.)
Rationale for why it has to be like this: a function f(x::Vector{AbstractString}) could e.g. push! a new FooString into x (assuming FooString is a subtype of AbstractString). Now if x was in fact a Vector{UTF8String}, that would fail.

In julia functions : passed by reference or value?

In julia how do we know if a type is manipulated by value or by reference?
In java for example (at least for the sdk):
the basic types (those that have names starting with lower case letters, like "int") are manipulated by value
Objects (those that have names starting with capital letters, like "HashMap") and arrays are manipulated by reference
It is therefore easy to know what happens to a type modified inside a function.
I am pretty sure my question is a duplicate but I can't find the dup...
EDIT
This code :
function modifyArray(a::Array{ASCIIString,1})
push!(a, "chocolate")
end
function modifyInt(i::Int)
i += 7
end
myarray = ["alice", "bob"]
modifyArray(myarray)
#show myarray
myint = 1
modifyInt(myint)
#show myint
returns :
myarray = ASCIIString["alice","bob", "chocolate"]
myint = 1
which was a bit confusing to me, and the reason why I submitted this question. The comment of #StefanKarpinski clarified the issue.
My confusion came from the fact i considred += as an operator , a method like push! which is modifying the object itself . but it is not.
i += 7 should be seen as i = i + 7 ( a binding to a different object ). Indeed this behavior will be the same for modifyArray if I use for example a = ["chocolate"].
The corresponding terms in Julia are mutable and immutable types:
immutable objects (either bitstypes, such as Int or composite types declared with immutable, such as Complex) cannot be modified once created, and so are passed by copying.
mutable objects (arrays, or composite types declared with type) are passed by reference, so can be modified by calling functions. By convention such functions end with an exclamation mark (e.g., sort!), but this is not enforced by the language.
Note however that an immutable object can contain a mutable object, which can still be modified by a function.
This is explained in more detail in the FAQ.
I think the most rigourous answer is the one in
Julia function argument by reference
Strictly speaking, Julia is not "call-by-reference" but "call-by-value where the value is a
reference" , or "call-by-sharing", as used by most languages such as
python, java, ruby...

Resolving Julia 0.4 deprecation of Uint64

I want to create a 2D array of Uint64s in Julia 0.4. This worked in 0.3:
s = 128
a = zeros(Uint64, s, s)::Array{Uint64,2}
It continues to compile but gives me the notice
WARNING: Base.Uint64 is deprecated, use UInt64 instead.
I don't know what this message means. I've tried googling the error message but haven't found anything helpful. What is an equivalent line of code that will not produce any warnings?
s = 128
a = zeros(UInt64, s, s)::Array{UInt64,2}
Watch out for capitals!
Doug's answer is correct, except that you can simplify it to
s = 128
a = zeros(UInt64, s, s)
You don't need the type annotation ::Array{UInt64,2}. Defining a = zeros(UInt64, s, s) will create a variable which knows its type.
Note that the Julia error message was telling you what you had to do -- replace Uint64 by UInt64. If you can think of a better way of rephrasing the message to be clearer, that would be useful to hear.
In general, type annotations are at best redundant when defining variables in Julia -- the type is automatically inferred from the type of the right-hand side, and this will be the type assigned to the variable being created.
Type annotations are used in Julia in two circumstances:
1. to define the type of variables inside a composite type
2. for multiple dispatch in function definitions, to specify which types a given method applies to.

Resources