-
Notifications
You must be signed in to change notification settings - Fork 16
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
constructor_of() #68
Comments
I am open to moving things out of @generated constructor_of(::Type{T}) where T =
getfield(T.name.module, Symbol(T.name.name)) While this function is non trivial, it is also very short and I hesitate to add a dependency just for such a short function. |
Yeah it does seem a bit short to add that dependency for. I mostly wanted to flag that I'm using the exact same function for the same purpose, and it seems to be a general requirement for any tool that works with immutables like this. Maybe when more work is done in base we can have something generalised. |
While the default
Just FYI I recently created a similar package https://github.com/tkf/Kaleido.jl based on Setfield.jl |
Yeah I was thinking that, but I'm also not strongly opinionated about it because in practice I only have one or two types that I'm actually overloading I'll take a look at Kaleido. The core difference between Flatten and Setfield/Kaleido approach is that Flatten is more about abstracting the process than specifying it - for cases where you don't know or care what the field names are. Its like a query: get all the e.g |
I think lens is powerful and abstract enough to handle such cases.
For example, this can be done by using Setfield
struct SubtypeFieldsLens{T} <: Lens
end
Setfield.get(obj, ::SubtypeFieldsLens{T}) where T =
foldl(fieldnames(typeof(obj)), init=NamedTuple()) do xs, n
v = getfield(obj, n)
if v isa T
return (; xs..., (n => v,)...)
else
return xs
end
end
Setfield.set(obj, ::SubtypeFieldsLens{T}, xs) where T =
foldl(fieldnames(typeof(obj)), init=(obj, 1)) do (obj, i), n
v = getfield(obj, n)
if v isa T
return (set(obj, Setfield.PropertyLens{n}(), xs[i]), i + 1)
else
return (obj, i)
end
end[1]
@assert get((a = 1, b = "2", c = 3.0), SubtypeFieldsLens{Real}()) ==
(a = 1, c = 3.0)
@assert set((a = 1, b = "2", c = 3.0), SubtypeFieldsLens{Real}(), (2, 6)) ==
(a = 2, b = "2", c = 6)
# Parse all String fields into Int:
@assert modify(
xs -> parse.(Int, Tuple(xs)),
(a = 1, b = "2", c = "3"),
SubtypeFieldsLens{String}(),
) == (a = 1, b = 2, c = 3)
# Get the second String field of the object inside property `a`
@assert get(
(a = (b = 1, c = "2", d = 3, e = "4"),),
(@lens _.a) ∘ SubtypeFieldsLens{String}() ∘ (@lens _[2])
) == "4" (This is probably not super efficient but I think you can improve it to make things more inferrable.) It also should be possible to recurse into all sub-objects and flatten fields. In the last example I tried to show that lenses compose with other lenses. I think it would be nice if you express what you need using Also, you can simply use |
That's interesting. The composability would be great. It would need to handle field level trait functions like Also Flatten is very efficient - ie flatten and reconstruct compile together to just change the fields that are altered. Basically everything is compiled away. And it's very simple to use and a tiny amount of code that I understand really well. I doubt I will have time to rewrite it as a Lens anytime soon as I have so many other packages to work on but I'll definately think about it in future. |
Of course, it is good to keep your library simple. I just thought it might be worth considering |
No that was really interesting! The only problem is I have already done the rewrite otherwise I would be looking at using Lens :) |
@tkf https://github.com/tkf/Kaleido.jl looks really cool! Getting rid of So what should be the scope of the base package? Just |
FWIW, I feel like |
Sure! |
Interesting idea. I never tried to understand what |
Yeah ok I am in favor of a base package. Lets talk about name and scope.
|
I think other people may be interested in this. For example, when using Flux.jl, I repeatedly write code like this using Setfield: @settable
using QuickTypes: @qstruct_fp
using Flux: @treelike
@settable @qstruct_fp Foo(...)
@treelike Foo which is not really sane. Looking at @MikeInnes Are you interested in a base package for constructors? Hope you don't mind the ping :)
I agree. Also, it may be useful to add
I prefer
I think (But I'm not quite sure relying on internal/C API is a great idea. Using positional constructor sounds OK to me.) |
I agree, the package should cover mutables and things like
|
A somewhat contrived example would be a user-defined (named) tuple-like type with some kind of invariant; e.g., the sum of all the numerical fields is less than one. |
Ah, I guess you mean that it's possible to define something like Base.setindex(collection::Tuple, values::Tuple, indices::Tuple) to do the batch update (in principle; this example as-is a type piracy against |
Yeah you are right, |
How to construct an object without calling the constructors: |
Interesting. But isn't that doing type conversion to match the existing field type? In Flatten and Setfield you can change the field type. |
Ah, good observation. It does look like a messy operation. |
Re #84 (comment). Can we create @ararslan @kmsquire @oxinabox @scls19fr @simonster You guys are listed in https://github.com/orgs/JuliaCollections/people. Is it possible to set up a repository |
Just to confirm, I am willing to maintain |
+1. I've been thinking about this as well the last few days, while implementing it in yet another package. Can also co-maintain. |
IMO it doesn't make sense to have it in JuliaCollections. It could easily live in a personal account with multiple people having commit access. |
@ararslan Thanks for the response. I guess it was too much of a stretch then... |
Alternatively, how about creating a new organization? I think it'd be nice to put Setfield in the same organization as well (maybe after renaming #54). Of course, provided that @jw3126 likes that option. I believe the getter/setter API formulated in Setfield should be used across Julia ecosystem. I think putting it in an organization would communicate it better. ...but the problem is it's hard to come up with a good name. Just to start brainstorming:
|
I am okay with moving
These names came to my mind first:
Out of the names suggested so far, I like |
I thought about it a bit but then it felt like a team developing tooling for designing physical buildings or something. ...although I don't trust my common sense for English phrase :) Besides, I don't think it fits super well with Setfield. Anyway, I think other options are better. |
Sounds good to me. But maybe @rafaqz have other ideas? |
I like JuliaObjects. Flatten.jl would fit there as well. |
I'm updating and abstracting Flatten.jl to allow arbitrary flattening and modifications of nested structs using method and type 'queries'.
It has some similarities to Setfield.jl in that it needs to call the constructor of immutable types, so I've just copied your
constructor_of()
to make this more apparent. But I was thinking it might be nice to abstract this to a base package one day so that structs with custom type parameters can just define a specific constructor once for anything that needs it.The text was updated successfully, but these errors were encountered: