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

Major cleanup

Open rafaqz opened this issue 5 years ago • 4 comments

This code is showing it's age and my inexperience writing Julia when I wrote this.

  • [ ] flatten, reconstruct modify metaflatten etc should all have kwarg versions so people can actually understand what they do
  • [ ] hacks like getting the fieldname instead of tuple index are inconsistent and not worth the effort. They should be removed.
  • [ ] functions should be the first argument - although this can be ambiguous when there are to method arguments.
  • [ ] flattenable should not be used by default, see #20
  • [ ] clearer language/kw args around querying should be used like select and skip instead of use and ignore
  • [ ] ultimately some cleaner lens-like logic should be defined for expressing what nested actually does in a clear way. Recursive @generated nesting needs to be formally wrapped somehow. Or use lenses if they can match the performance?

Maybe instead if a new package was written called ObjectQueries.jl people would better understand what you can do with it, and it could be rewritten from scratch:

query(x; select=Number)
# It still doesn't seem totally clear that `skip` skips actually the whole tree below the object:
query(x; select=Number, filter=flattenable, skip=SomeObject)

filter would actually be the first argument:

query(x; select=Number) do obj, fn
    return getfield(obj, fn)
end

rafaqz avatar Oct 24 '20 11:10 rafaqz

Maybe update without the bang for reconstruct:

This would be the default:

update(x; select=Number) do obj, fn, newvalue
    return value
end

And in-place :

update!(x; select=Number) do obj, fn, newvalue
    return setfield!(obj, fn, newvalue)
end

rafaqz avatar Oct 24 '20 11:10 rafaqz

Whatever it is it can be composable with lens from Setfield.jl/Accessors.jl? Composing get seems straightforward - compose(FlattenLens{Params}(), @lens _.a) should get the a field from every Param object.

I'm not sure how nested @generated set and compose will "compose".

Flatten.jl would need to handle

set(obj, Composed(FlattenLens(), innerlens))

for set(ojb, compose, get(obj, composed)) == obj to work

rafaqz avatar Oct 24 '20 15:10 rafaqz

You should only need to overload

(::FlattenLens)(obj) = # roughly whats currently in this package
Accessors.set(obj, lens::FlattenLens, val) = # not sure if this package covers immutable updates?

You should not need to think about composition. Accessors.jl will handle that for you.

jw3126 avatar Nov 03 '20 23:11 jw3126

Yeah I've been looking at how to get Accesors to do everything Flatten.jl does. I also rewrote this as a Setfiled Lens in a script before I knew about Accessors - its still using recursive @generated for the struct walking but composable with other lenses. Its fine and mostly seems to be compile-time operations.

The one thing missing for me in the Lens/Optic approach is context. With Flatten.jl you can get the field name and the type of the parent object for types that are filtered - which is really key to getting good output tables in https://github.com/rafaqz/ModelParameters.jl. That also lets you use FieldMetadata.jl to add more field context.

Context lenses don't follow the lens rules, so I'm not sure where to put them.

rafaqz avatar Nov 04 '20 01:11 rafaqz