Skip to content

Cannot construct a parameters object #110

@rvignolo

Description

@rvignolo

Hi!

First of all, thanks for the package, it is great.

Let me be as precise as posible. This would seem like a lot to process but it is actually quite simple to understand.

I am facing an interesting issue when defining parameters. As you may know, named tuples are nice because they are inmutable and type stable, so they can be used as a parameters container for a model (of course structs are also useful, but for this particular example I need to work with named tuples). However, if you try to do the following:

julia> using Parameters
julia> nt = (a = 1, f = t -> a + t)
(a = 1, f = var"#9#10"())
julia> nt.f(1)
ERROR: UndefVarError: a not defined
Stacktrace:
 [1] (::var"#9#10")(::Int64) at .\none:1
 [2] top-level scope at none:0

you get an error related to the scope of variable a.

To overcome this issue, you can use the Parameters.jl package, specifically by means of the following macro:

julia> nt2 = @with_kw (a = 1, f = t -> a + t)
##NamedTuple_kw#511 (generic function with 2 methods)
julia> nt2()
(a = 1, f = var"#388#390"{Int64}(1))
julia> nt2().f
#388 (generic function with 1 method)
julia> nt2().f(1)
2

Also, it can handle more complex examples:

julia> nt2 = @with_kw (a = 1, f = t -> a + t, g = t -> f(t) + sin(t))
##NamedTuple_kw#255 (generic function with 2 methods)

julia> nt2().g(1.)
2.8414709848078967

This is nice. What is happening in the background is that the @with_kw macro produces a constructor function that receives named arguments so you can use them to define other parameters. You can inspect this using @macroexpand or @expand (from MacroTools.jl).

Now I want to make use of these features in a more complicated example. Let's say I would like to include the numerical derivative of f in my parameters by using GSL.jl package (I have already tested other packages but this one seems to be the fastest at the moment). The first thing I have to do, is define a gsl_function object:

julia> using GSL

julia> const h = 9.765625e-4
0.0009765625

julia> const abserr = Cdouble[0]
const 1-element Array{Float64,1}:
 0.0

julia> const result = Cdouble[0]
1-element Array{Float64,1}:
 0.0

julia> nt2 = @with_kw (a = 1, f = t -> a + t, f′ = t -> deriv_central(@gsl_function(f), t, h, result, abserr))##NamedTuple_kw#262 (generic function with 2 methods)

julia> nt2()
(a = 1, f = var"#80#84"{Int64}(1), f′ = var"#81#85"())

julia> nt2().f′(0.1)
ERROR: UndefVarError: f not defined
Stacktrace:
 [1] (::var"#88#89")(::Float64, ::Ptr{Nothing}) at /Users/ramirovignolo/.julia/packages/GSL/yvp3l/src/manual_wrappers.jl:45
 [2] deriv_central(::gsl_function, ::Float64, ::Float64, ::Array{Float64,1}, ::Array{Float64,1}) at /Users/ramirovignolo/.julia/packages/GSL/yvp3l/src/gen/direct_wrappers/gsl_deriv_h.jl:36
 [3] (::var"#81#85")(::Float64) at ./none:1
 [4] top-level scope at none:1

It seems that @gsl_function expands and uses @cfunction (from Base). When this macro is expanded, f is not captured. Does anyone knows how to avoid this problem at all? Thanks!!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions