In Julia: initialize fields with nothing - julia

I have a mutable struct with optional fields like this:
mutable struct MyStruct
field1::Union{Int, Nothing}
field2::Union{String, Nothing}
field3::Union{Int, Nothing}
field4::Union{String, Nothing}
# ...
end
I can now write a default constructor which initializes the fields with nothing:
MyStruct() = MyStruct(nothing, nothing, nothing, nothing)
This is not so nice when my struct has many fields. Also, I have to count the fields to get the constructor call with all the 'nothings' correct in this case. Is there a better way to do that?
Depending on the field content, I want to call different functions later:
if mystruct.field1 == nothing
do_this()
else
do_that()
end

You can use fieldcount function to achieve that. This function gives you the number of fields of that an instance of given type would have. Here is an example containing a mutable struct and an outer constructor.
julia> mutable struct Foo
x
y
z
end
julia> Foo() = Foo(ntuple(x->nothing, fieldcount(Foo))...); # you can also fill an array and use `...`
julia> Foo()
Foo(nothing, nothing, nothing)

Related

Easy initialisation of empty containers

Consider the following code.
struct MyType
data::Dict{Int, Float64}
end
MyType() = MyType(Dict{Int, Float64}())
Having to repeat the type of data is a bit clumsy, and the problem gets out of hand very quickly if you have more variables and/or your types get more complicated. Can I avoid this?
If the type in question is default-constructible (i.e., it has a no-args constructor), you can use the following trick.
struct Default; end
Base.convert(::Type{T}, ::Default) where T = T()
struct MyType
data::Dict{Int, Float64}
end
MyType() = MyType(Default())
You can do:
Base.#kwdef struct MyType
data::Dict{Int, Float64} = Dict{Int, Float64}()
end
And now you can just write MyType():
julia> MyType()
MyType(Dict{Int64, Float64}())
I personally more like the package Parameters which is additionally affecting how struct is displayed:
using Parameters
#with_kw struct MyType
data::Dict{Int, Float64} = Dict{Int, Float64}()
end
And now in REPL you can see:
julia> MyType()
MyType
data: Dict{Int64, Float64}
The following hack-ish method works (as of Julia 1.8):
MyType() = MyType((t() for t in MyType.types)...)
It doesn't include Int or Float64, so it passes OP conditions. And also, it generalizes to types with many fields, and complex ones because it is essentially recursive.

Can you create a singleton in Julia?

I know that Julia does not have OOP but that multiple dispatch enables similar ideas. Given how seemingly contentious the use of singletons are in Python, I am wondering if there is a similar idea Julia (i.e. a struct that can only be instantiated once).
I am wondering if there's a way to have the constructor keep track of the number of times an object was instantiated with a global var or something like that? Or it's altogether not be possible?
The main way people make singletons in Julia is to define an empty struct (which means that it has 0 size), and define methods that return information for it.
struct Singleton
end
data(::Singleton) = "whatever you want it to do"
etc.
From this book, a singleton can be defined as a type without fields:
struct MySingleton end
julia> MySingleton() === MySingleton()
true
You can also use Val, which can receive any value (of bit type):
julia> Val(1) === Val(1)
true
julia> Val(:foo) === Val(:foo)
true
using Val you can write something like this:
julia> do_something(::Val{:asymbol}) = println("foo")
julia> do_something(::Val{:anothersymbol}) = println("bar")
julia> do_something(s::String) = do_something(Val{Symbol(s)})
julia> do_something("asymbol")
foo
The definition of Val is:
struct Val{x} end
So, for a more clear readability of your code, you could define your own singleton type as, for example:
struct Command{x} end

Julia: circular reference

how can is solve this problem?
mutable struct Parent
name::String
children::Vector{Child}
function Parent(name)
return new(name)
end
end
mutable struct Child
name::String
parent::Parent
function Child(name)
return new(name)
end
end
parent = Parent("father")
child = Child("son")
Produces an error
LoadError: UndefVarError: Child not defined
Is there some way to handle this case?
As far as I know the only way to handle this currently is via a parametric type (I know it is not perfect). Here is an example which additionally restricts the parameter so that you get almost what you want:
abstract type AbstractChild end
mutable struct Parent{T<:AbstractChild}
name::String
children::Vector{T}
function Parent{T}(name) where {T<:AbstractChild}
return new{T}(name)
end
end
mutable struct Child <: AbstractChild
name::String
parent::Parent
function Child(name)
return new(name)
end
end
Parent(name) = Parent{Child}(name)
parent = Parent("father")
child = Child("son")
And just to add on to #Bogumił Kamiński's answer the abstract type AbstractChild end creates a node for julia to traverse from at runtime in the program.

How to instantiate a struct in Julia where I have the struct name in a string variable?

The name of the struct to instantiate will be passed by the caller to my program. Then I would need to instantiate the corresponding struct for the same for further processing.
For example, if the struct is defined like this
struct A end
and I have a function defined as
function load(struct_name::AbstractString)
if struct_name == "A"
return A()
elseif struct_name == "B"
return B()
elseif ..... # and so on
end
end
it will work. But is there a more direct way like return struct_name() instead of having n number of if else statements? I see that Julia supports reflection. How can that be used to support the above use case?
I would recommend not doing it in production code, but you can do the following:
function load(struct_name::AbstractString)
invoke(eval(Symbol(struct_name)),Tuple{})
end
strut_name via eval will get resolved in the global scope of the module.
It is safer to use a dictionary as #EPo suggested.
An example of dictionary-based dispatch. Dict("a" => A, "b" => B)[tag] selects a constructor, and () calls it.
struct A end
struct B end
function dispatch(tag)
return Dict("a" => A, "b" => B)[tag]()
end
#assert dispatch("a") == A()
If you care about default values to handle unexpected parameter, for example dispatch('zzz'),
you can make recourse to get().
As a side note about risks of eval() there is a small collection of powerful warning references in a neighboring Python question. In short, eval() is a big security hole and a 'smell' (warning sign) for a questionable design of a program.
You could use a macro instead:
julia> module Load
export #load
macro load(struct_name::Symbol)
return :($(esc(struct_name))())
end
end
Main.Load
julia> using Main.Load: #load
julia> struct A end
julia> struct B end
julia> #load A
A()
julia> #macroexpand #load B
:(B())
julia> #load C
ERROR: UndefVarError: C not defined
Stacktrace:
[1] top-level scope at none:0

How to hard code struct variables in Julia?

I have a Julia struct:
struct WindChillCalc
location::Tuple;
w_underground_url::String;
WindChillCalc(location, wug) = new(location, w_underground_url);
end
How do I hard code w_underground_url to contain "someString" upon the constructor of WindChillCalc being called?
Try something like below
struct testStruct
x::Real
y::String
testStruct(x,y) = new(x,"printThis")
end
test = testStruct(1,"")
test2 = testStruct(2,"")
println(test.y)
println(test2.y)
It prints "printThis" for any object.
Just write for example:
struct WindChillCalc{T}
location::T;
w_underground_url::String;
WindChillCalc(location::T) where {T <: NTuple{2, Real}} =
new{T}(location, "some string");
end
and now Julia automatically creates a concrete type for you:
julia> WindChillCalc((1, 2.5))
WindChillCalc{Tuple{Int64,Float64}}((1, 2.5), "some string")
Note that I have restricted the type of the parameter to be a two element tuple where each element is a Real. You could of course use another restriction (or use no restriction).
With this approach your code will be fast as during compile time Julia will know exact types of all fields in your struct.

Resources