Conversation
|
@mauro3 Just as a fair warning, |
|
@mauro3 what do you think about this PR? |
| ConstructionBase = "187b0558-2788-49d3-abe0-74a17ed4e7c9" | ||
| OrderedCollections = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" | ||
|
|
||
| [compat] |
There was a problem hiding this comment.
How about adding ConstructionBase = "0.1, 1.0"? (I think CompatHelper can figure out 1.0 but I'm not sure if it adds 0.1)
|
Aright, sorry for the long radio-silence. I answer, just as I'm about to go on holidays again... I'm a bit hesitant to take on the dependency of ConstructionBase.jl. Is my understanding right, that if someone wants good performance, then there is nothing in the way of them just using
|
|
I guess that is correct. Are you open to have some tests that test that setproperties actually works on types created by your macro? |
|
Yes, I have no reservations to have ConstructionBase as a test-dependency. |
|
I think of this PR more as for package composition rather than performance. For example, I think we need this PR to make this scenario work:
|
|
True, but note that
My hunch is that this is fairly rare (but I might be wrong) and has an easy fix, and thus imposing the extra dependency is not worth it. |
|
I should've set up the scenario more accurately. What I meant to say was that function_b(x) = reconstruct(x, alpha = x.alpha + 1)package |
|
Ok, I don't quite understand ConstructionBase. How do properties even feature in ConstructionBase? |
|
Here is a concrete toy example: module A
using ConstructionBase
struct TypeA{x,y,z} end
TypeA(x, y, z) = TypeA{x,y,z}()
Base.getproperty(::TypeA{x,y,z}, name::Symbol) where {x,y,z} =
if name === :x
x
elseif name === :y
y
elseif name === :z
z
else
throw(ArgumentError("Unknown property $name"))
end
Base.propertynames(::TypeA) = (:x, :y, :z)
function ConstructionBase.setproperties(::TypeA{x0,y0,z0}, nt::NamedTuple) where {x0,y0,z0}
props = merge((x = x0, y = y0, z = z0), nt)
if keys(props) !== (:x, :y, :z)
throw(ArgumentError("Unknown properties in: $nt"))
end
return TypeA(props.x, props.y, props.z)
end
end # module A
# I'm pretending that package `B` uses `Parameters.reconstruct`:
module B
# using Parameters
using ConstructionBase
const reconstruct = setproperties
function_b(obj) = reconstruct(obj, x = obj.x + 1)
end # module B
# Package `C` uses packages `A` and `B` without knowing they are using
# `ConstructionBase`/`Parameters`.
module C
using ..A: TypeA
using ..B: function_b
demo() = @assert function_b(TypeA(0, 2, 3)) === TypeA(1, 2, 3)
end # module C
C.demo() |
|
Thanks for the detailed example! (Maybe something like this could go into your docs, as they are a bit on the theoretical side so far.) But in the example, package B could change from it using I guess, I kinda see OT: what is |
I see, I think that makes sense. Indeed, package
Thanks for the suggestion. That's a good idea.
Yeah, I think throwing an error makes sense. |
|
Another possibility would be to remove Or, we go down the route of defining custom methods for |
|
Yeah, you can overload
But Parameters.jl still needs to depend on ConstructionBase.jl if you want to overload |
|
Yes, I wasn't clear: the last option would require the dependency on ConstructionBase. Which is ok, but it's also ok to strive for few dependencies. |
Various packages implement variants of
Parameters.reconstruct. ConstructionBase.jl is an effort to unify these. Benefits are:ConstructionBase.setpropertiesis very fastgetpropertyto interact well with bothSetfield.jlandParameters.jl, she only needs to overload one function.See also JuliaObjects/ConstructionBase.jl#6
ConstructionBase is not yet released, so CI will fail and this PR should not yet be merged.