-
Notifications
You must be signed in to change notification settings - Fork 8
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
Move to Accessors.jl
from Setfield.jl
#91
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #91 +/- ##
==========================================
- Coverage 84.82% 82.72% -2.11%
==========================================
Files 3 3
Lines 145 191 +46
==========================================
+ Hits 123 158 +35
- Misses 22 33 +11 ☔ View full report in Codecov by Sentry. |
Accessors.jl
from Setfield.jl
Accessors.jl
from Setfield.jl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff @sunxd3 :)
The equivalence between VarNames are changed, before @varname(y[:], true) and @varname(y[1:100] (where y = zeros(10,10)) are considered to be ==. But with Accesssors, two IndexLens are generally not equivalent even when they have the same field because they are also functors.
I don't get this. Why does it matter that it's a functor?
From what I can tell it seems the issue is that @varname(y[1:100])
results in the indices field holding the range 1:100
, not ConcretizedSlice(Base.OneTo(100))
, which is what @varname(y[:], true)
results in?
You're saying this was not the case before?
Optics are functions or functors, how would this affect type stability?
Maybe add some tests with @inferred
?
Though for the subset of cases where care about, I'd be surprised if this would actually have any implications for type-stability.
The only worry is whether the fact that subtypes of Function
will in certain cases not be specialized on, but Base.ComposedFunction
does not subtype Function
+ from what I can tell, none of the optics subtype Function
either, so we should be good.
src/varname.jl
Outdated
is_static_lens(l::Lens) | ||
|
||
Return `true` if `l` does not require runtime information to be resolved. | ||
is_static_optic(l) | ||
|
||
In particular it returns `false` for `Setfield.DynamicLens` and `Setfield.FunctionLens`. | ||
Return `true` if `l` is one or a composition of `identity`, `PropertyLens`, and `IndexLens`. | ||
""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why the docstring was changed here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I subtly changed the function we used to have: is_static_lens
returned false by default, now it is undefined by default.
Now the behavior is such that, when optic
is one of identity
, PropertyLens
, and IndexLens
, or composition of them, returns true; if optic
is DynamicIndexLens
or composition, it returns false, otherwise error.
So I thought being explicit is good here, but I should add something like for DynamicIndexLens, returns false
.
src/varname.jl
Outdated
function Base.:∘(vn::VarName{sym,T}, optic) where {sym,T} | ||
return VarName{sym}(getoptic(vn) ⨟ optic) | ||
end | ||
function Base.:∘(vn::VarName{sym,typeof(identity)}, optic) where {sym} | ||
return VarName{sym}(optic) | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm a bit uncertain about this.
We implemented this originally to replicate the composition behavior of Setfield.jl, but now this reversed and so it seems a bit strange to not also reverse this here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of the place I was uncertain too: I didn't want to break too many things, but maybe we should also adapt CompositionBase
and introduce opcompose
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose we just remove this function, composition between a varname and a lens
or optic
is a bit strange for me anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing is, we are making VarName
act as, what was before, a PropertyLens
, in which case it does make sense to consider the composition IMO. We are still doing this, no?
Before, |
Co-authored-by: Tor Erlend Fjelde <[email protected]>
@torfjelde another look? |
Just made some adjustment, The interpolation is weaker compared to before. It is mainly attributed to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The interpolation is weaker compared to before. It is mainly attributed to Accessors.parse_obj_optic. Now more than one interpolated symbol (e.g. @varname($n1[$n2+1])), and interpolation of the LHS of a . expr (e.g. $name.a[1]) are disallowed.
Woaah this seems not great; why do we feel the need to make this change?
EDIT: Maybe it doesn't matter that much. I was thinking it could cause issues because we do make use of interpolation and such in @submodel
, buuut just realized this is a separate thing unrelated to VarName
. So it's less of an issue than what I was imaging at first.
But I have actually used this myself (in the example discussed with Joel), in particular with the new Gibbs sampler where we will use @varname
to specify what to sample rather than symbols. In such a scenario, it can be very convenient to do iteration + interpolation to construct the varnames you want (I used this feature myself when helping out Joel). So I'm still not super-keen on this change 😕
Might be worth raising an issue and asking about this, as IIUC it should be okay to define |
The interpolation ability was added by @phipsgabler at jw3126/Setfield.jl#168, but this never got ported to Accessors. I do think the interpolation can be quite handy, but that means we need to keep Setfield around for a while. |
Co-authored-by: Tor Erlend Fjelde <[email protected]>
Is there a reason why we can't just copy-paste the macro? 🤷 |
That should work since it is only a small utility function. |
@torfjelde @yebai function copied, not sure if it's small, but it should maintain the interpolation ability. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @sunxd3 -- good work!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great stuff @sunxd3 :)
Changes from
Setfield
toAccessors
Accessors
is based onComposeFunction
, which means all theoptic
s are either function or functor. Also, noget(obj, optic)
interface, butoptic(obj)
.Lens
abstract type doesn't exist inAccessors
,IdentityLens
is justidentity
,ComposedLens
is nowComposedOptic
(alias forComposedFunction
)Inner
andOuter
are interchanged,l1 ∘ l2
inSetfield
isl2 ∘ l1
inAccessors
.Accessors
adopted⨟
(\bbsemi
"opposite compose") fromCompositionBase
:l1 ∘ l2
inSetfield
isl1 ⨟ l2
inAccessors
.Unsure
VarNames
are changed, before@varname(y[:], true)
and@varname(y[1:100]
(wherey = zeros(10,10)
) are considered to be==
. But withAccesssors
, twoIndexLens
are generally not equivalent even when they have the same field because they are also functors.Accessor.parse_obj_optic
andSetfield.parse_obj_lens
behave differently when deal with interpolation. I have tried and failed to maintain the current interface withAccessor.parse_obj_optic
, so I am keepingSetfield.parse_obj_lens
(andSetfield
as a dependency), while replace theLens
with optic in the result ofSetfield.parse_obj_lens
.