proposal-pipeline-operator icon indicating copy to clipboard operation
proposal-pipeline-operator copied to clipboard

pipeline-equals assignment

Open towc opened this issue 6 years ago • 4 comments

In the proposal I saw no mention of something like variable |>= fn as a clean shorthand for variable = fn(variable), so I thought I'd bring it up so it can be added to the spec with this proposal, and doesn't bite us later.

You might want to discourage it as JS is going more and more functional, but if so, it would be nice to have that written in the proposal as well

towc avatar May 30 '18 10:05 towc

I think that this could be useful for cases where you want to pass properties through the pipeline. This would solve a similar problem to async/await by allowing you to use operator results in the same scope as other operators in the pipeline.

A Promises example:

I think it's easier to exemplify with a working Promises example. This is a real world scenario: You need to read some items from storage, set some configuration, and make a network request -- all async operations.

getItemsAsync().then(items =>
  setConfigAsync(items).then(
    () => httpGet(items),
  ),
);

This creates more rightward drift in the code. Alternatively you could use let:

let oitems;
getItemsAsync().then(items => {
  oitems = items;
  return setConfigAsync(items);
}).then(() => httpGet(oitems));

async/await solves this problem by putting all of the operators in the same scope. Imagine we're in an async function...

const items = await getItemsAsync();
await setConfigAsync(items);
return httpGet(items);

I think this is much easier to reason about, and it doesn't require "carrying values around," if that makes sense.

Applying to the pipeline

Imagine an Observable chain that does the same operations:

getItems$().pipe(
  mergeMap(items => setConfig$(items).pipe(
    mergeMap(() => httpGet$(items)),
  ),
);

... alternatively ...

getItems$().pipe(
  mergeMap(items => setConfig$(items), (_, items) => items),
  mergeMap(httpGet$),
);

If the chain gets longer, the carrying around of items becomes more cumbersome.

You can see complaints about this here: https://github.com/ReactiveX/RxJava/issues/2931 and quite a few other places.

Solution using the pipeline and assignment

If you can do assignment in the pipeline this problem is solved by keeping the values in the same scope as the other operators:

// `of` is used here to kick off the Observable chain
of(1)
const items |>= mergeMap(() => getItems$()),
            |> mergeMap(() => setConfig$(items)),
            |> mergeMap(() => httpGet$(items)),

This syntax isn't perfect, but I think the general idea is good.

ajcrites avatar Jun 02 '18 16:06 ajcrites

I'd like to leave this idea for a follow-on proposal, and leave the initial proposal simpler and minimal. What do you think?

littledan avatar Jun 24 '18 13:06 littledan

@ajcrites Hey, I see your reasoning for wanting this though for your scenario

getItemsAsync().then(items =>
  setConfigAsync(items).then(
    () => httpGet(items),
  ),
);

which is the same as:

getItemsAsync()
  .then(setConfigAsync)
  .then(httpGet);

The composition, in my opinion, would be better composed as 'something that happens outside of an observable' which can then be called from an 'observable':

const someProcess = async () => 
  await getItemsAsync() 
    |> x => (await setConfigAsync(x), x) // I know, just for our example
    |> x => await httpGet(x)
;

no (in other words, you wouldn't even need observable chains involved, for process, in javascript)?

// Updated example above

Same as example above but without sequences:

const 
  someProcess = 
    async () => getItemsAsync()
        .then(x =>  setConfigAsync(x).then(() => httpGet(x))
;

elycruz avatar Jun 24 '18 19:06 elycruz

@ajcrites @towc 👍 for participation/effort 👍 Also @ajcrites The someProcess I show above is 'point-free' and allows the process to be easily composed with other function calls of a simliar structure (async functions etc.). Also no mutability (in example) 👍

elycruz avatar Jun 24 '18 19:06 elycruz