Status of default initialisation of struct fields? - julia

Under Julia v0.6, the simple code:
julia> struct A
x::Int = 1
end
generates this error:
ERROR: syntax: "x::Int=1" inside type definition is reserved
This is quite an elusive message: reserved for what?
-> Do I have to understand that this kind of definition is going to be allowed in future Julia revisions?

This is available via Parameters.jl.
julia> using Parameters
julia> #with_kw struct A
a::Int = 6
b::Float64 = -1.1
c::UInt8
end
julia> A(c=4)
A
a: 6
b: -1.1
c: 4

Related

Can two structs reference each other? - Julia

I have a struct that includes a field of the same type, which I cannot assign at creation.
Julia does not seem to like the following. (It coughs up a circular reference complaint.) I intend this to boil the problem down to its essentials
mutable struct Test
test:: Union{Test,Nothing}
end
t1 = Test(nothing)
t2 = Test(nothing)
t1.test = t2
t2.test = t1
What is the right way to achieve this? (E.g., how can I point to my partner, who can point to me as his partner?)
Separately, is the above currently the right way to have an initially "null" field?
What you propose is a correct way to have initially nothing field.
Alternatively you can do something like:
julia> mutable struct Test
test::Test
Test(t::Test) = new(t)
Test() = new()
end
julia> t1 = Test()
Test(#undef)
julia> t2 = Test()
Test(#undef)
julia> t1.test = t2
Test(#undef)
julia> t2.test = t1
Test(Test(Test(#= circular reference #-2 =#)))
where you have temporarily #undef field.
See also Incomplete Initialization section of the Julia Manual.
Edit
An example of circular reference with a standard Vector{Any}:
julia> x = Any[]
Any[]
julia> push!(x, x)
1-element Vector{Any}:
1-element Vector{Any}:#= circular reference #-1 =#

How to lock the variable type in Julia?

I want to lock the type of a variable in Julia, how to do? For example, I define an array called weight,
weight = Array{Float64,1}([1,2,3])
Now I want to lock the type of weight as Array{Float64,1}, is it possible?
I mean if do not lock the type of weight, then if I mistakenly or casually do
weight = 1
Then weight will become an Int64 variable, so it is not longer a 1D array. This is obviously not what I want.
I just want to make sure that once I defined weight as 1D Float64 array, then if I change the type of weight, I want Julia gives me an error saying that the type of weight has been changed which is not allowed. Is it possible? Thanks!
This is useful because by doing this, it may preventing me from forgetting weight is an 1D array, and therefore preventing bugs.
For global variables use const:
julia> const weight = Array{Float64,1}([1,2,3])
3-element Vector{Float64}:
1.0
2.0
3.0
julia> weight[1]=11
11
julia> weight=99
ERROR: invalid redefinition of constant weight
Note that redefining the reference will throw a warning:
julia> const u = 5
5
julia> u=11
WARNING: redefinition of constant u. This may fail, cause incorrect answers, or produce other errors
You can circumvent it by using the Ref type:
julia> const z = Ref{Int}(5)
Base.RefValue{Int64}(5)
julia> z[] = 11
11
julia> z[] = "hello"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
In functions use local with type declaration:
julia> function f()
local a::Int
a="hello"
end;
julia> f()
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
You'd normally write:
weight::Vector{Float64} = Array{Float64,1}([1,2,3])
...but this doesn't seem to be possible in global scope:
julia> weight::Vector{Float64} = Array{Float64,1}([1,2,3])
ERROR: syntax: type declarations on global variables are not yet supported
Stacktrace:
[1] top-level scope
# REPL[8]:1
However, you can do it in local scope or in a struct:
julia> function fun()
weight::Vector{Float64} = Array{Float64,1}([1,2,3])
weight = 1
end
fun (generic function with 1 method)
julia> fun()
ERROR: MethodError: Cannot `convert` an object of type Int64 to an object of type Vector{Float64}
Closest candidates are:
convert(::Type{T}, ::AbstractArray) where T<:Array at array.jl:532
convert(::Type{T}, ::LinearAlgebra.Factorization) where T<:AbstractArray at /Users/julia/buildbot/worker/package_macos64/build/usr/share/julia/stdlib/v1.6/LinearAlgebra/src/factorization.jl:58
convert(::Type{T}, ::T) where T<:AbstractArray at abstractarray.jl:14
...
Stacktrace:
[1] fun()
# Main ./REPL[10]:3
[2] top-level scope
# REPL[11]:1
You could use const, but then redefinition with a value of the same type will cause a warning:
julia> const weight = Array{Float64,1}([1,2,3]);
julia> weight = [2.]
WARNING: redefinition of constant weight. This may fail, cause incorrect answers, or produce other errors.
1-element Vector{Float64}:
2.0

What is the meaning of <: in julia? [duplicate]

This question already has answers here:
Julia: what does the "<:" symbol mean?
(2 answers)
Closed 2 years ago.
Can anyone help me with this code:
struct GenericPoint{T<:Real}
x::T
y::T
end
What is meaning of <: in {T<:Real} in Julialang?
Let me begin by saying that the punctuation page of the manual is a handy way to search for such operators, which are otherwise very difficult to look for using a search engine.
In the specific case of <:, we find this page, with the relevant documentation for essential operators.
There are (at least) 3 contexts where A <: B might be used, and in all of them this expresses the idea that A is a subtype of B.
as a predicate, A <: B returns true if and only if all values of type A are also of type B:
julia> Int <: Number
true
julia> Int <: AbstractString
false
in a type definition, this declares that the newly defined type is a subtype of an existing (abstract) type:
# `Foo` is declared to be a subtype of `Number`
struct Foo <: Number
end
as a type-parameter constraint (like in your example), T <: Real expresses the idea that type parameter T can be any subtype of Real:
julia> struct GenericPoint{T<:Real}
x::T
y::T
end
# Works because 1 and 2 are of type Int, and Int <: Real
julia> GenericPoint(1, 2)
GenericPoint{Int64}(1, 2)
# Does not work because "a" and "b" are of type String,
# which is not a subtype of Real
julia> GenericPoint("a", "b")
ERROR: MethodError: no method matching GenericPoint(::String, ::String)
Stacktrace:
[1] top-level scope at REPL[5]:1
Note that the use for type-parameter constraints is not restricted to the definition of parametric types, but also applies to function/method definitions:
julia> foo(x::Vector{T}) where {T<:Number} = "OK"
foo (generic function with 1 method)
# OK because:
# - [1,2,3] is of type Vector{Int}, and
# - Int <: Number
julia> foo([1, 2, 3])
"OK"
# Incorrect because:
# - ["a", "b", "c"] is of type Vector{String}, but
# - String is not a subtype of Number
julia> foo(["a", "b", "c"])
ERROR: MethodError: no method matching foo(::Array{String,1})

Julia 1.1.1 - absolutely global variables

I am coming from Fortran and I use global vectors of data over the full program. Usually I declare a module:
module xyz
real, allocatable :: vector(:,:,:) ! a 3 dim vector, undefined
end module
Now, in some place, let say Subroutine (Function) A, I am allocating memory for it and initialize to some values:
allocate(vector(10,20,30))
vector = ran()
Now, in any other unit of the program (Subroutine or function B, C, D...), if I am using the module, i.e:
using xyz
The above declared vector is available.
I was not able to obtain this behavior in the new technological wonder Julia 1.1. The scope rules are just giving a headache.
In Julia the rules for accessing variables from other modules are explained in detail here.
The key issues in your situation are the following things:
a variable is visible after using only if it is exported in the module
you are allowed to access the variable in other modules
you are not allowed to rebind a variable from other modules
This means that global variable binding creation operation is private to the module.
Here is a simple example module definition:
module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
now assume you define and later use it in REPL (it could be any other module)
julia> module M
export x
x = Int[]
function rebindx()
global x = Int[]
end
end
Main.M
julia> using .M
Now you can access x:
julia> x
0-element Array{Int64,1}
julia> push!(x, 1)
1-element Array{Int64,1}:
1
julia> x
1-element Array{Int64,1}:
1
julia> x[1] = 10
10
julia> x
1-element Array{Int64,1}:
10
But not rebind x:
julia> x = 0
ERROR: cannot assign variable M.x from module Main
However, you can call a function defined inside M module to change the binding of x like this:
julia> x
1-element Array{Int64,1}:
10
julia> M.rebindx()
0-element Array{Int64,1}
julia> x
0-element Array{Int64,1}
This was possible because rebindx was defined inside module M so it has the right to change the binding of variable x defined in this module.

What does assignment like x\y = 1 mean in Julia?

While experimenting with Julia 1.0, I've noticed that I can do something like this:
x\y = 1
The REPL then shows:
\ (generic function with 1 method)
which means its a valid assignment (the interpreter doesn't complain). However, x, y, and x\y all remain undefined.
What is the meaning of such expression?
It is a new function definition that (kind of) shadows the left division operator \ in Base, since the left division operator is already defined for some types in Julia. The new function definition is \(x,y) = 1 (the names of function parameters do not matter) which works for all types of variables. This will prevent julia from loading Base.\ due to name conflict. No matter what the input is your new \ will return the same value.
julia> x\y = 5
julia> a = 3; b = 4;
julia> a\b
5
julia> c = "Lorem ipsum"; d = "dolor";
julia> c\d
5
If you have already used the \ that is defined in Base, your redefinition will throw an error saying that extending Base.\ requires an explicit import with import Base.\. The behavior of defining \ after import Base.\ however will be different. It will extend the operator Base.\.
julia> 1\[1,3]
2-element Array{Float64,1}:
1.0
3.0
julia> import Base.\
julia> x\y=3
\ (generic function with 152 methods)
julia> 1\[1,3]
2-element Array{Int64,1}:
3
3

Resources