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
isolate proposal: a different scope for each driver #526
Comments
Very interesting proposal. I like how
So, unrelated to this proposal, right? Any feedback @Widdershin @TylorS? |
Yes, only loosely related. I just mentioned it because:
So I would first discuss that "non-string scope proposal" in staltz/cycle-onionify#11, where it's used for a clear, practical purpose. Let's use this issue only for the non-breaking change. |
I like this. I haven't run into this issue yet, but is it possible for isolate only to isolate certain drivers?. isolate(Child, {onion : 'child', HTTP: null})({onion, HTTP}) |
Another option could be to pass a second set of drivers that bypass isolate. isolate(Child, {onion : 'child'})({onion}, {HTTP}) |
@aronallen Very good point. Your suggestion of using (Thinking of #441, the DOM driver could accept scopes of type I think it's more consistent for isolate(Child, {onion : 'child', HTTP: null})({onion, HTTP}) but let the HTTP driver, not |
Do we use somewhere nulls already? Do we want "A functional and reactive JavaScript framework" to force users into nulls? |
Good point. Currently That said, I still like Aron's idea for a simple way of choosing no isolation for some sources/sinks. |
What about the empty string? |
😬 |
I like this idea. |
I think we're hitting a wall. Strings contain a lot of information in terms of bits, but not the kind of information drivers need to do their isolation stuff. We can use |
Here's a different way of thinking about this whole issue: should we allow each channel
|
And by the way, I don't think the enum
First and Second should be exactly the same thing because the arguments provided were the same. I don't think we can escape names (or can we?). Also, the enum is complicated because true enums only exist in TypeScript, as well as not being able to use the same scope for all channels if someone wants to. Also because of backwards compatibility, we are probably still going to primarily use strings as scopes. Because this is JavaScript, we shouldn't try to fight the language so much. I admit in a different language we'd be using ADTs for this. |
Doesn't const First = isolate(Child)
const Second = isolate(Child) have the same referential transparency issue as const First = isolate(Child, {DOM: ParentChild})
const Second = isolate(Child, {DOM: ParentChild}) ? I'm not sure we can escape names, but my point with enums was that maybe we can. Maybe scopes should convey just enough information for the channel to understand how to |
Instead of using strings as scope identifiers, we could use symbols. Then isolate could export a special symbol that means no isolation. This way we avoid giving meaning to null. |
We could also just reserve a string, Like "!" or "*" but i prefer the symbol solution. |
@aronallen Symbols are cool. Anyway, @staltz, I do see your point with referential transparency. At least now we have a way to write orthodox FP code if we want, while with my proposal it would be impossible. What about the DOM driver exporting a function const First = isolate(Child, {DOM: parentChild('first')})
const Second = isolate(Child, {DOM: parentChild('second')}) And maybe also a const First = isolate(Child, 'first')
const Second = isolate(Child) |
Symbols are good for isolation because (except for |
That is, unlike a string, they can't simply appear again like the same string can be written in two different scopes independently. But the actual mechanism of isolation in the DOM relies on classes. And those are strings... |
Unfortunately symbols are the most referential opaque thing on earth... :( I think we do care about referential transparency after all. |
On Fri, Feb 24, 2017 at 7:54 PM abaco ***@***.***> wrote:
Unfortunately symbols are the most referential opaque thing on earth... :(
I think we do care about referential transparency after all.
Is this true? A symbol is a value... Functions can have referential
transparency. How can values have this property?
… —
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#526 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAmyx5aY93qqM9XU_V3md7bd3IFNtJwLks5rfxlMgaJpZM4MIWnt>
.
|
That's true. Silly me. |
Just to make sure we are all on the same page, I'll describe how isolation works today:
Some notes: We don't have "Channel with Then, notice that in every case, isolateSource works as "zoom-in" while isolateSink means "zoom-out". For instance, check how onionify's isolateSource gets an outer (parent) state and returns an inner (child) state, while isolateSink takes an inner reducer and returns an outer reducer. Also notice that in the DOM channel, Now, new ways how we could change isolation (I'll list all applicable, I'm not saying which ones of these will we support):
Does this give anyone some insights? |
In my opinion, for the DOM channel I think we can support |
@staltz how do you produce so much awesome in so little time, so frequently? 🙇♂️ |
@davidskuza Your proposal would break all existing code, and I don't think it's worth it. I also suspect most people would usually want isolation for all channels, only occasionally skipping it for one or two of them. Then your first syntax would be rarely used. (Of course I don't know how people actually use However your suggestion convinced me we should support all the following APIs: isolate(Component) // auto-generated scope for all channels
isolate(Component, 'something') // 'something' for all channels
isolate(Component, {HTTP: 'else'}) // 'else' for HTTP, auto-generated for the rest
isolate(Component, 'something', {HTTP: 'else'}) // 'else' for HTTP, 'something' for the rest The last syntax would give us a straightforward way of writing referentially transparent code. We have that now (2nd syntax), and I think it's nice. With only the 3rd syntax it would be really cumbersome to enforce referential transparency: very verbose, and would require an update whenever a channel is added. |
This is probably the best time to make breaking changes, not so many people using it in production yet. Also good time to consider if we want to fix this:
|
The impurity of Are you proposing isolate(Component, {HTTP: 'something', onionify: 'something', history: 'something'}) while with staltz's proposal: isolate(Component, {DOM: ':root'}) |
DOM maybe yes but not every channel will be able to use string. Example on HTTP: For everything: isolate(Component, 'something')
// or
isolate(Component, { default: 'something' }) For everything except HTTP: isolate(Component, { onionify: 'something', history: 'something' }) instead of isolate(Component, { HTTP: null, onionify: 'something', history: 'something' }) |
What's your answer to staltz's question:
My answer is yes. Isolation instructions include "no isolation": for onionify that's the identity lens, for the DOM driver it can be the special scope ':root', and for the HTTP driver we'll have to come up with something. |
Yes, I agree with you and I want the same. I just proposed this way because we would not have to use null (for "no isolation"). If somebody comes with better idea than that then it's ok for me (even maybe that null is ok, I just try to make "us" to think if there is a better way than null). |
So far the most unknown issue is how to instruct the HTTP driver to do no isolation. Because other than that, I'd be totally in favor of doing the following:
To be honest, I don't see what's the big problem with |
I neither have strong objections against @staltz, what do you think of this syntax: isolate(Component, 'something', {HTTP: 'else'}) // 'else' for HTTP, 'something' for the rest |
I'm usually against adding more arguments, because they aren't quickly learnable from a glance. For instance in the past we improved from
and may forget or not be able to learn from a glance what is the purpose of the second and the third argument. I would suggest instead isolate(Component, {'*': 'something', HTTP: 'else'}) Which makes it a bit better, but still not ideal. |
I think you meant HTTP? |
Yes, sorry, I meant HTTP. I like your suggestion |
I am leaning towards not defining the value type for each driver, simply letting isolate pass a specific value to a specific driver. It is up to each driver to interpret what As for the '*' would that pass 'something' to any driver that has an undefined scope? We could also turn everything around, so instead of calling isolate on the Component, we call it on the driver. This would be a breaking change, but I think it makes more sense. since The syntax would then look like this
It makes it very clear that DOM is isolated, and HTTP is not. An optional second argument could be the scope, and each driver could have it's own type definition for scopes.
Instead of calling this new method isolate, we could call it constrain, so there is no confusion. So instead of "you may isolate a component" we say "you may pass a constrained driver to a component"
|
@aronallen that API wouldn't work because those arguments are sources, but isolate needs to cover both sources (the argument) and sinks (the return). This is also why I nowadays avoid writing const childSources = {DOM: sources.DOM, HTTP: sources.HTTP}
const childSinks = Component(childSources) |
That's almost what staltz summarized a few posts up. However, for the sake of backwards compatibility:
|
I think we have converged in this issue. Here's the summary of what will be done:
If anyone has an important and new comment about the proposal above, please speak up! :) |
only one comment: keep it simple |
Is it not simple? How? What would you suggest? How would you solve the new problems identified? |
What is the problems? I see there the problem with This my suggestion. =) |
I'm not sure if sophistication of DOM isolation is needed as well, this is again a step to magical behavior. |
That was my two cents, I myself like to overcomplicate stuff and invent problems. |
Why not |
Why not |
This issue is now done and released, check here https://cycle.js.org/releases.html#flexible-isolation I'll proceed by making lenses support in onionify, too. |
How about letting
isolate
accept multiple scopes? So instead of:one could also do:
This would solve for instance staltz/cycle-onionify#8:
When the scope for a driver is omitted, one would be internally generated, as usual:
I've already implemented this in a branch.
In addition to this change I also removed the conversion of scopes into strings (e.g. when you provide a number) because I need that for an other experiment with onionify. This can break isolation in some drivers, e.g. in the DOM driver when you pass a number as scope.
The text was updated successfully, but these errors were encountered: