Parameters.jl
Parameters.jl copied to clipboard
Properties
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
)
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.
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
Tnx for your interest. With Julia 0.7 this could be done via properties. So, maybe it should be a 0.7 only feature?
I'm not sure I understand, could you elaborate?
See https://github.com/JuliaLang/julia/pull/25311
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?
Yes, you'd need to mark a "field" with @calc
or maybe now rather @prop
.
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.
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
AFAIU we want two features:
- 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. - 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.
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)
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?
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.
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.