# VarStructs.jl: variable Julia structs

**URL:** <https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653>\
**Category:** Package Announcements\
**Tags:** package, announcement, data, dispatch, struct\
**Created:** [August 10, 2020, 1:11am UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653 "2020-08-10T01:11:45Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)\
**Post date:** [August 10, 2020, 1:11am UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653/1 "2020-08-10T01:11:45Z")

</div>

I want to announce the VarStructs.jl package which introduces variables structs with dispatching and redefinition support.

> **[GitHub - aminya/VarStructs.jl: Variable Julia Structs with dispatching](https://github.com/aminya/VarStructs.jl)**
>
> Variable Julia Structs with dispatching

```julia
using Pkg; Pkg.add("VarStructs")
using VarStructs

```

# Features

VarStructs are similar to structs but have extra features:

- You can add fields after their definition.
- They can be defined inside a function or a local scope.
- They can be redefined.

Similar to structs

- They can be used for dispatching (zero-cost)
- They can have custom constructors
- They have type conversion/checking for the fields that are declared

# Declaration

There are two ways to declare them:

## Struct Syntax

In this syntax, providing initial values and types for the fields are optional.

```julia
@var struct Animal
    name::String
    number::Int64
end

```

## Call Syntax

In this syntax, you **should** provide the initial values for the fields. Providing type for the fields are optional (if not provided, it is considered as `Any`).

```julia
@var Person(
        name = "Amin",
        number::Float64 = 20.0,
    )

```

# Getting an Instance

Use the following syntax for getting an instance:

```julia
julia> person = Person(name = "Amin", number = 20.0)
Person(
    name::Any = Amin,       
    number::Float64 = 20.0,
)

# Type conversion for the fields that were declared
julia> person2 = Person(name = "Amin", number = 20) # number is converted to Float64
Person(
    name::Any = Amin,       
    number::Float64 = 20.0,
)

# Type checking for the fields that were declared
julia> person2 = Person(name = "Amin", number = "20")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Float64

# new field added
julia> person2 = Person(name = "Amin", number = 20.0, initial = "T")
Person(
    initial::String = T,    
    name::Any = Amin,       
    number::Float64 = 20.0,
)

```

The two syntaxes that are used for declaration also return an instance of the VarStruct. So if you need an instance right away, you can use the following. Note that in redeclaration you will not get type checking based on the previous declaration.

```julia
animal = @var Animal(
        name = "lion",
        number::Int64 = 10,
    )

# redefinition of `Animal` returns a new instance:
animal2 = @var Animal(
        name = "dog",
        number::Int64 = 1,
    )

```

# Accessing, Setting, Adding Fields

```julia
# Accessing
julia> person.name
"Amin"

# Setting
julia> person.name = "Tim"

# Adding Fields
julia> person.initial = "T"

```

# Dispatch

`info` function dispatch for `Person` and `Animal` type:

```julia
function info(x::Person)
    println("Their home is city")
    return x.name
end

function info(x::Animal)
    println("Their home is jungle")
    return x.name
end

```

```julia
julia> info(person)
"Their home is city"
"Amin"

julia> info(animal)
"Their home is jungle"
"lion"

```

# Custom Constructor

To define a custom constructor return an instance using the keyword method:

```julia
function Person(name, number)
    return Person(
        name = name,
        number = number,
        initial = name[1],
    )
end

Person("Amin", 20.0)

```

# Give me benchmarks:

The dispatching is zero-cost like a normal struct:

```julia-auto
julia> using VarStructs

julia> @var struct A
       end;
julia> @var struct B
       end;

julia> dispacth_varstruct(x::A) = 1
dispath_varstruct (generic function with 1 method)

julia> dispacth_varstruct(x::B) = 2
dispath_varstruct (generic function with 2 methods)

julia> using BenchmarkTools
julia> @btime dispath_varstruct(x) setup=(x=rand()<0.5 ? A() : B())
  0.001 ns (0 allocations: 0 bytes)

```

---

<div class="post-metadata">

**Author:** ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)\
**Post date:** [October 5, 2020, 5:04pm UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653/2 "2020-10-05T17:04:08Z")

</div>

VarStructs 0.3.0 has been released and it has passed its test phase.

The improvements:

- Unset fields now have a type of `Unset` instead of `Missing`
- Fixed a bug that fields with complex types were not being parsed correctly

I have added a **schema** example, which shows the power of VarStructs. This example shows how to define a schema for your data and add/process the actual data dynamically.

[https://github.com/aminya/VarStructs.jl/blob/master/example/schema.jl](https://github.com/aminya/VarStructs.jl/blob/master/example/schema.jl)

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [October 5, 2020, 5:21pm UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653/3 "2020-10-05T17:21:39Z")

</div>

I’m a little confused by this, it seems like each `VarStruct` has only one single instance, and trying to create a new instance just mutates the old one?

```julia
julia> using VarStructs

julia> @var struct Foo
           a::Int
       end;

julia> f = Foo(a=1)
Foo(
    a::Int64 = 1, 
)

julia> g = Foo(a=2, b=1)
Foo(
    a::Int64 = 2, 
    b::Int64 = 1, 
)

julia> f
Foo(
    a::Int64 = 2, 
    b::Int64 = 1, 
)

```

Is this intentional? If so, I don’t really think it’s appropriate to call these things `struct`s…

Even more bizarre:

```julia
julia> f == g
false

julia> f === g
false

```

---

<div class="post-metadata">

**Author:** ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)\
**Post date:** [October 5, 2020, 5:29pm UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653/4 "2020-10-05T17:29:31Z")

</div>

Yes, this is confusing a bit. I need to make the non-shared instances the default behavior instead. Shared instances probably need to be annotated in the declaration explicitly.

I will consider adding this feature in the next version.

---

<div class="post-metadata">

**Author:** ![Amin\_Yahyaabadi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amin_yahyaabadi/32/9826_2.png) [@Amin\_Yahyaabadi](https://discourse.julialang.org/u/Amin_Yahyaabadi)\
**Post date:** [October 5, 2020, 11:27pm UTC](https://discourse.julialang.org/t/varstructs-jl-variable-julia-structs/44653/5 "2020-10-05T23:27:56Z")

</div>

VarStructs 0.4.0 is released with support for unique instances (like normal structs).

Now, `@var` will create VarStructs that will construct unique instances. Use `@shared_var` for shared VarStructs that construct shared instances.
