How to pass struct fields as function arguments?

Example

struct variables
   a :: Integer
   b :: Float64
   c :: Integer
end

function f(a::Integer,b::Float64,c::Integer)
   d = a + b + c
   println(d)
end

var = variables(1,2.5,3)

f(var)  # ?

How can I pass a structure as an input argument?

1 Like

EDIT 2: Here is how you actually should do this:

function f(var::variables)
  d = var.a + var.b + var.c
  println(d)
end

f(var)

You could also do this, although you shouldn’t, and it can’t be properly inferred by the compiler so it will involve dynamic dispatch:

f(getfield.(Ref(var), fieldnames(variables))...)

EDIT: Brief description:

Gets a Tuple of Symbols which refer to the field names of the variables struct type via fieldnames(variables), then uses a broadcasted getfield to get the values of those fields out of the var struct, and then splats them into the call to f.

You could instead do this as an @generated function if you want it to be inferrable.

2 Likes

FWIW, this seems like an unusual thing to do. For example, it changes behaviour when reordering the fields in the struct which isn’t very nice.

2 Likes

Agreed, the best thing to do is to just dispatch on the input as f(var::variables) = .... I think I misread the intent of the OP :laughing:

This is a very good case for Parameters.jl if you have a lot of variables:

using Parameters

@with_kw struct variables
   a :: Integer
   b :: Float64
   c :: Integer
end

function f(s::variables)
    @unpack_variables s
    d = a + b + c
    println(d)
end

julia> f(variables(1,2.5,3))
6.5
7 Likes

Hi @Ronis_BR,

This package looks very useful as I’m just really starting to use Structs more. Unfortunately, the @unpack_variables macro does not appear to be working. I’d like to know if I’m doing something wrong or if something has changed since your post here.

After installing the Parameters package, I created a script called parameters_test.jl containing the following:

using Parameters

@with_kw struct v_type
    a::Int
    b::Float64
    c::Int
end

v = v_type(11, 2.2, 33)

function vtest(a::Int, b::Float64, c::Int)
    println("a = $a")
    println("b = $b")
    println("c = $c")
    return (a+b+c)
end

function vtest(abc::v_type)
    @unpack_variables abc
    println("a = $a")
    println("b = $b")
    println("c = $c")
    return (a+b+c)
end

When I execute this, however, I get the following:

julia> include("parameters_test.jl")
ERROR: LoadError: UndefVarError: @unpack_variables not defined
Stacktrace:
 [1] top-level scope
   @ :0
 [2] include(fname::String)
   @ Base.MainInclude ./client.jl:476
 [3] top-level scope
   @ REPL[1]:1
in expression starting at /Users/home/parameters_test.jl:19
in expression starting at /Users/home/parameters_test.jl:18

FYI, I’m running Julia 1.8.0 (2022-08-17). Appreciate any feedback.

Hi @jman87 !

I think the name of the macro will be @unpack_v_type in your case. It is always @unpack_<name of the structure>.

1 Like