Pipeline tap operator `|:`

@Clemdz - maybe the ** operator would be a better example. It only saves a few characters over Math.pow(), yet people decided it would be useful enough as its own operator. Creating additional syntax for a feature depends not just on how difficult it is to do without the syntax, but also on how often this particular piece of functionality gets used - in the case of **, a whole ton.

This proposal may be a bit ahead of its time - right now it feels like it would be a slight convenience to have, but I'm not sure if it's worth the additional operator yet.

...but once the pipeline proposal is out, I may start realizing how valuable such an operator would be, and many people could start jumping in on this idea.

2 Likes

For the method chaining case, why not just add it to Object prototype?

Object.defineProperty(Object.prototype, 'debugTap', {
  enumerable: false,
  value: function(cb) { cb(this); return this; }
})

then you can easily do anything:

data
  .filter(x => x != null)
  .map(x => x ** 2)
  .map(x => x ** 2)
  .debugTap(console.log)
  .filter(x => x > 100)
1 Like

Nothing new can or should be added to Object.prototype; it could also break code in the wild.

It also wouldn’t work on null objects.

Hi all! Hope it helps... Here are some interesting cases with Pipeline tap operator |:

case1: Pipeline tap operator |: and Ternary Comparison Assignment Operators:
const result = someData
  |> someData.filter(x => x >= 10) ? "true" : "false";
case2: Pipeline tap operator |: and Optional Primitive Type Annotation and Ternary Comparison Assignment Operators and Ternary-like try/catch:
function test1(a: string): string {
    return a.toUpperCase();
}

const result = someData
  |> someData.filter(x => x >= 10) try? test1('value1'): "false"; // if sucess call test1 ... catch "false"
case3: Pipeline tap operator |: and Concurrent Async and Normal Await Evaluation Blocks and Ternary-like try/catch:
const data = {
  x: awaitmulti getX(),
  y: await.multi getY(),
}

const result = data
  |> data.filter(x => x >= 10) try? "true": "false"; // if sucess  true  ... catch "false"
case4: Pipeline tap operator |: and Class property parameters
class DataStorage {
  constructor(this value) {}
}

const result = someData
  |> someData.filter(x => x >= 10) ? DataStorage(x) : "false";
references

@ljharb Hi! What do you think these ideas?

I think that it’s not useful to think about syntax ideas without a problem statement. What problem are you solving? Get folks to agree that the problem exists, first, before it’s worth talking about how to solve it.

3 Likes
  1. So ... I was trying to show some cases that pipeline tag operator |: might be interesting
  2. In my opinion... pipeline tap operator |: ... in my humble opinion, it's something interesting because with ternary '?' we have an 'switch-case' ... so this can replace if/else ( note: I've seen that a good practice is to avoid if/else code) - so, code becomes more compact and readable

Syntax isn't interesting; the problem it solves is interesting. What problem is it trying to solve? (note that discussing this requires zero discussion of new syntax or API)

2 Likes

@willow_grace - perhaps some of the confusion here, is that none of your cases actually used the |: pipeline tap operator, they all used the plain |> pipeline operator, and sometimes they used a new try? syntax who's purpose and description of how it works hasn't been explained yet. Did you borrow the try? idea from another thread? If so, which one? (You listed a ton of references there).

1 Like
  1. I hope to clear all your doubts or questions.

  2. Thank you so much for the feedback, I think you're amazing...I really respect and admire you. All your feedback... has made me more thoughtful about how Javascript is an interesting and viable language. And if I'm somehow helping the community. I think it's really cool to see all the points of view.

  3. My examples that I put here are use cases, I don't intend to defend any idea or use case. My goal is to demonstrate how pipeline tap operator |: can be interesting in the aforementioned use cases. As I said, it's demonstration, not validation. If the pipeline tag operator |: is adopted this would allow to do what I am demonstrating here.

  4. In short, yes they are ideals borrowed from other topics. The fact that I reference other topics would be to say that I'm thinking about adopting the pipeline tap operator |: in these other use cases. I'm checking the possibility if pipeline tap operator |: might be interesting.

cases

  1. In the first case I use 2 techniques: Pipeline tap operator |: and Ternary Comparison Assignment Operators. So... I imagined in the case that a person, a programmer, needed to quickly get data from some function... So... a quick and easy way in Javascript would be through the Pipeline tag operator |: and Assignment Operators of Ternary Comparison because I just like I said before would be like a small switch case... This sytaxe allows the programmer with simple lines to do many things... it makes me think of the 'less is more' design idea... with few lines we can do validations at the same time as calling internal functions. In this specific case, I do 2 things: I filter the data and check if any data I have is of numeric type and if it is greater than 10, if accepted, the return is a true message
  2. In this case 2 I do 4 things in a simple way: validation, serialization, callback and error handling with ternary as try/catch.
  3. In this case 3 I do 3 things in a simple way: async, filter and error handling with ternary as try/catch.
  4. In this case 4 I do 3 things in a simple way: callback, filter and error handling with ternary as try/catch.

My arguments

  1. Javascript doesn't have something like LINQ, pipeline tap operator |: would or could be LINQ in Javascript
  2. In my view, everything is easier to understand with pipeline tap operator |: and ternary-like try/catch ... as try/catch

This is what's confusing me. You're saying you're using both the tap operator and a ternary operator. But, the code snippet you shared for case 1 only showed a normal pipeline operator (not the tap), with the ternary operator.

It's a similar story with all of your other cases. Is there a mistake in these code samples? Did you intend to use the tap operator?

@theScottyJam Hi... here... more notes and clarification ... If you have any questions, I'm happy to explain.

  1. This is what's confusing me. You're saying you're using both the tap operator and a ternary operator. But, the code snippet you shared for case 1 only showed a normal pipeline operator (not the tap), with the ternary operator.

  • Truth... now that i see it... I will make this correction now.
  1. It's a similar story with all of your other cases. Is there a mistake in these code samples?

  • Yes...
  1. Did you intend to use the tap operator?

  • Yes... but... the fact is that I forgot to post it with |: in the use cases, sorry
  1. , and sometimes they used a new try? syntax who's purpose and description of how it works hasn't been explained yet. Did you borrow the try? idea from another thread? If so, which one? (You listed a ton of references there).

  • This... try? - the idea would be if it would be possible to use the ternary as try/catch which I found very interesting, reference here ternary-like-try-catch author: DiriectorDoc
  • I wrote too fast and ended up posting without proofreading it before, sorry.

Code snippets are not "use cases" - a use case is prose describing a problem. A code snippet might be a potential solution to a use case.

My earlier post is saying that code snippets are not useful until the problem has been presented. What is the problem being solved here?

1 Like

I'm still a little confused at the four cases though. They seem to showcase the syntax of this proposal (assuming we switch |> for |:), along with the other proposals, but it doesn't seem to showcase their functionality or show why they go good together. Nor does it seem to correctly use some of the ideas (e.g. the tap operator only makes sense if you are performing a side-effect on the RHS, which none of these examples do. And in case3, you use await.multi to put multiple values into the same object, then you attempt to use .filter() on an object?).

Was there a specific correlation you were trying to draw between these proposals, to show why they go good together? If so, could you expound and explain what it is? Or were you just trying to throw the syntax of the different proposals into the same code block to show what they visually looked like if somehow got those all into the language together?

1 Like

Hi...

  • Sorry.
  • As I said, the objective I put is demonstration, not validation. I'm just showing some scenarios. My goal is not to demonstrate why they work well, but the functionality related to other scenarios. When I talk about "use cases", I mean test cases. For example... a test case is a set of actions executed to verify a particular feature or functionality of your software application. A test case contains test steps, test data, precondition, postcondition developed for specific test scenario to verify any requirement. The test case includes specific variables or conditions, using which a testing engineer can compare expected and actual results to determine whether a software product is functioning as per the requirements of the customer. Given the proposal here... I could do something like I described.

Yes.

  • Yeah... yes... exactly this. I'm just trying to put the syntax of the different proposals in the same code block to show what they look like visually if we somehow put them together in the language... So, I hope to clarify this idea.