I really like the @with_kw approach and personally also like the ability to overwrite, but I would just like to cast a warning if it has been overwritten.
Thanks for showing me that approach though, I just think it might become convulated qutie fast if say I had 5 entries which had to be calculated in my struct.
Looks like Parameters.jl supports putting those @asserts directly in the field definition itself — you needn’t create the constructors yourself. I’d guess something like this would do the ticket:
@with_kw struct MyTest
a = 1
b = 2*a
@assert b == 2a
end
Just to address the specific wording here even though I know it’s not really what you mean: No. It is fundamentally impossible in julia to strictly enforce constraints on the values of the fields in a struct.
The best one can do is use inner constructors to enforce constraints, but those can be bypassed in various ways. For instance:
julia> using Parameters
julia> @with_kw struct MyTest{T}
a::T = 1
b::T = 2*a
@assert b == 2a
end
MyTest
julia> MyTest(a=1, b=1)
ERROR: AssertionError: b == 2a
julia> reinterpret(MyTest{Int}, [1, 1])[1]
MyTest{Int64}
a: Int64 1
b: Int64 1
A determined user can always find a way to stick an ‘invalid’ entry into a struct (so long as the type is compatible). The best you can do is make it inconvenient to do so and then tell users that if they bypass your constructors, it’s their own fault if things go wrong.
Most users are not going to figure out the reinterpret trick which you did and I was completely oblivious of it also to be honest - so great find!
Regarding the enforcing of constraints, would it be possible to any way write an @assert expression which basically is a warning? So for example if “b” is set externally and not defined through “a”, then it would simply allow it (because it is not possible to disallow as you say), but print a warning saying that the automatic calculation of this parameter was bypassed.
For my use case the exact value of a or b, is not so important it is just whether or not it was overwritten or calculated based on a predefined expression.
Basically something like I mentioned in the first post; “WARNING: MyTest.b was set manually.” But I would want this for multiple variables, imagine if I had also fields c,d,e,f and so forth.
No, the reinterpret trick (or other tricks) will also allow one to bypass any automatic warning mechanism. If julia had a mechanism to strictly enforce this stuff, a lot of important optimizations would be impossible.
Don’t worry about the points I’m bringing up here though, it’s most likely not relevant for you. Just stick warnings or assertions in your constructors and you’ll be fine. If a user bypasses your constructors, that’s their fault.
Unfortunate, but thanks for the clarification. I personally would like this kind of feature, but I see why it might be difficult to implement etc. Thanks for spending time on the question!
My understanding is that the problem is not that it’s difficult to implement, it’s that the very concept is anathema to julia being usable as a high performance language.
We need these sorts of low level escape hatches for various things. But the upside is that it is considered the user of that escape hatches responsibility to make sure anything they do there is valid. So again, this is not really your problem.