Open chrisvfritz opened 9 years ago
I suppose is could make sense if you only want to observe a cursor for a particular part of your UI. You might need to be careful about not observing twice if your component mounts twice.
There shouldn't be a problem with some cursors not existing though, the cursors are "optimistic" - you can .get
a cursor that doesn't exist. If you .deref
it, you get null
back, but you can update it and the path will get created. It may not work quite that well with arrays though. Cursors to arrays are still a little problematic and need more work.
See https://github.com/arch-js/arch/pull/38 where that change was made.
Ahh, didn't know about cursors being optimistic. That's good to know! I also didn't consider cases where I may be mounting the same component more than once within an application instance, which I imagine would be quite common with multiple routes.
I haven't dug into this part of the source yet, but I wonder if on-change
could make a check to see if the cursor is already being observed with that function. The only reliable way I can think of for doing that would be to compare the results of .to-string!
on the functions, but that may become expensive at scale. Not sure.
I suppose ideally, cursors to arrays would work perfectly, which would make the discussion moot. I'm not sure exactly how difficult a problem that is though.
If the cursor implementation is a real source of pain, it may also be worth using something like react-cursor on the backend and having arch simply provide observability and sugar for the interface. Just ignore if this is something you've already considered. :smiley:
And again, haven't looked into the cursor implementation, but this may be useful: LiveScript allows typecasting to array if not already an array with [] ++ something-that-may-or-may-not-be-an-array-already
.
We also found ancient-oak, all of those are interesting and we'll evaluate them for alternative immutable backends, some of which might give us more power for the cursor implementation.
Ultimately, I think we want to keep the cursor implementation and API in Arch, because it's probably the most important part of it and we want/need control over its semantics, so using a 3rd party implementation (especially of a simple thing like a cursor) seems like a wrong direction.
This also lets us swap the immutable backend if we like and not break existing applications (bar the .raw
call, which should be used rarely and the 80% use case is to be able to do reference equality check, which will hold no matter what backend we use).
+1 for keeping the API. I was thinking that even if you used a different cursor implementation on the backend, the API would remain the same and wrap it. The reason this is the first cursor implementation I've actually used is largely because it's the first one that made it simple.
Too many other APIs have a lot of functions that initially sound very similar (e.g. set
/reset
/update
/swap
or get
/select
/refine
). And in the very common case that I want to traverse deeply down the tree, @props.search.get \youtube.channels.query.text
is so much more elegant than something like @props.search.refine \youtube .refine \channels .refine \query .refine \text
, which every other API I've dug into seems to force.
OK, rant over. I renamed the issue to better describe what the real issue seems to be, but I don't think I have anything more to say about it. You can decide whether the leave it open until that use case has been better addressed or close it for now, since there may not be anything more to discuss.
I think it's worth leaving open and it looks like we might switch the immutable backend to ancient-oak (which seems very light-weight and idiomatic). That will force us to implement the deep gets ourselves, at which point we can handle the numeric case properly, i.e. .get \my.list.3.sublist.15 .update -> \yo
will create the following structure:
{
my: {
list:
[null, null, null, {
sublist: [ ... 15 nulls ..., 'yo']
}]
}
}```
:+1: :smiley:
I'm not sure the
start
function is the right place to list observers. What I've found myself doing locally is not even having anobservers
folder, but rather defining an observer in acomponent-will-mount
. The reason is some parts of the cursor that need to be observed will not exist in the initial state.Does that make sense? Or is there something I'm not getting? (This very well may be, as I'm pretty new to cursors.)