Parameters.jl icon indicating copy to clipboard operation
Parameters.jl copied to clipboard

Properties

Open mauro3 opened this issue 7 years ago • 14 comments

It would be cool to have fields which are always calculated:

@with_kw type P
    a=1
    b=2
    @calc c=a+3b
end

would translate into something like

type P
    a
    b
    c
    P(a,b) = (c=a+3b; new(a,b,c))
    ...
end
...

(i.e. there would be no constructor which allows setting c)

mauro3 avatar Sep 19 '16 12:09 mauro3

I was going to ask for the same. I want some user to be able to set a and b but not c - which is just a consequence of a and b.

Can't promise anything unfortunately but I'll try to have a look and see if I can make a PR.

carstenbauer avatar Mar 10 '18 07:03 carstenbauer

Just to be a little bit more precise, one can currently do

@with_kw type P
    a=1
    b=2
    c=a+3b
end

but a user will be able to overwrite the c=a+3b default. So I probably wouldn't call the macro @calc but maybe @fix or @nokw.

@with_kw type P
    a=1
    b=2
    @nokw c=a+3b
end

carstenbauer avatar Mar 10 '18 07:03 carstenbauer

Tnx for your interest. With Julia 0.7 this could be done via properties. So, maybe it should be a 0.7 only feature?

mauro3 avatar Mar 10 '18 09:03 mauro3

I'm not sure I understand, could you elaborate?

carstenbauer avatar Mar 12 '18 19:03 carstenbauer

See https://github.com/JuliaLang/julia/pull/25311

mauro3 avatar Mar 12 '18 19:03 mauro3

I see that this could be used to hide the field c from the user. But wouldn't the @with_kw macro still need to know that it should exclude a field from being an allowed keyword in the constructor?

carstenbauer avatar Mar 12 '18 19:03 carstenbauer

Yes, you'd need to mark a "field" with @calc or maybe now rather @prop.

mauro3 avatar Mar 12 '18 19:03 mauro3

This would be an ok syntax:

@with_kw struct A
    a
    b <= sin(a) + 5
end

i.e. the b is a property which is set via sin(a) + 5.

Also, properties would be read-only (also for mutable types) as it gets too complicated otherwise.

mauro3 avatar May 16 '18 10:05 mauro3

Although, even with properties, it might be nice to have fields which are calculated for performance reasons:

@with_kw struct A
    a
    @set b = really_expensive_function(a) + 5
end

mauro3 avatar Aug 02 '18 07:08 mauro3

AFAIU we want two features:

  1. Be able to specify a property (not a real field) which when called by A.b will (on-the-fly) calculate it's value based on the current field values.
  2. A "calculated field", indicated by @set, @calc, or @nokw, which will be calculated when an instance is constructed based on the initial field values.

Correct? I was asking for the latter type of field above.

carstenbauer avatar Aug 26 '18 07:08 carstenbauer

Case 1. would be doable by having

@with_kw struct A {F<:Function}
  a
  b
  c::F = (a::A)->(a.a+2a.b)
end
d = A(1,2)

and then Parameters.jl would need to extend getproperty such that d.c calls d.c(d)

BeastyBlacksmith avatar Feb 25 '19 11:02 BeastyBlacksmith

But how would you know when one wants to store a function in a field vs when it should be used as a property-function? I think it would still need to be marked somehow, no?

mauro3 avatar Feb 25 '19 12:02 mauro3

That depends on how convenient the syntax should be, the code above works right now as it is. The user than has to declare that a Function is stored and add the type Parameter to the field, which IMO is not a bad thing, since it could be troublesome if Parameters.jl handles that for me, but then I have to account for the additional type parameter(s) for example when I define outer Constructors. There is potential to make the construction of the anonymous function more readable like

@with_kw struct A {F<:Function}
  a
  b
  c::F = a+2b
end

The information that c should be a function could then be extracted from the type parameters and annotations.

BeastyBlacksmith avatar Feb 26 '19 10:02 BeastyBlacksmith

But if I have, say a ODE problem which defaults to exponential growth:

@with_kw struct MyODE{F}
  tspan::Tuple{Float64,Float64} = (0.0, 1.0)
  objfn::F = x -> x
end

Now, objfn is not a property. Thus when doing myode.f I want the function to be returned and not myode.myode. Thus a field which is supposed to be a property needs to be marked somehow.

mauro3 avatar Feb 26 '19 12:02 mauro3