"Programmers don't love naming things, programmers love programming." Couldn't have said it better. As I was watching this I was thinking 'this is kinda like why Tailwind is great'. I suppose great minds think alike!
Typescript has really helped me not to worry about the names of things, since it's trivial later to do a 'rename' refactor on a name that no longer matches it's data or usage. I often start a type definition or variable declaration with 'let thinger = ...' so that I can fill in the variable first, use it, and then stare at my code and figure out what 'thinger' should be named now that it is filled in and used, it's funny that this works but it's super effective for me.
@@nathanfranck5822 I name stuff result more often than I'd like to admit. Though to be fair, it's a very good name for most scenarios. Since I tend to declare variables early, it also allows readers to know immediately what is going to be returned.
Id rather say programmers don't like to think about unnecessary stuff. I tried Tailwind and even though I don't have to think about naming, I have to make my way though long lines of utilitary classes. And that's really annoying. The same issue arises when U have to think how to put into Tailwind some stuff that I might easily do with Css or Scss And another problem is that utilitary classes become so difficult to read especially when there are more than 10-20 of them for one JSX tag. I have to re-read again and again until I find what I'm looking for
Functional programming is all about not repeating the same block of code but using this block inside a function and using the function instead of that block of code.
I really like the pipeline operators from Elixir. It makes code based on functions (regardless of strictly FP paradigm) much more intuitive and readable.
I love how javascript is slowly more and more adopting fp patterns This proposal will definitely have massive effect on the way we write our javascript code and the DX gains will be amazing
To be honest, when I first heard of a new feature coming to javascript, my first thought was "Another feature to bloat this old language even further". But now that I see what it does I think it is a good thing. Javascript has been trying to be a lot of things for a long time. It is a language that is a little bit of everything, and it doesn't seem to be the best at anything. Its strength should be on the high level code. Turning into something closer to a functional programming could make more sense in the future. Similar to what Python does, where it has libraries compiled in C running in it's high level runtime with garbage collector. I think that Javascript as a functional programming language would be easier to understand and debug.
JavaScript was actually designed to be a functional language and then it was shoehorned into looking a bit like Java (Mostly syntactically, but also with things like adding null where undefined was just fine). But FP things like first-class functions, anonymous function expressions, closures where there from the start. Also, at some point (2009 maybe?) we got the really nice array methods like map and reduce, keeping the momentum for FP in JS.
@@RaducuGabriel i'd argue that prototypes and objects arguably made it OOP before classes. Classes just made it more OO. Meanwhile, new additions like this make it more functional. While I don't really use JS anymore, it will remain in my heart as one of my favorite languages because it's the most innovative for developer experience. I mean, it evolved from being a simple browser scripting language as it was when I first used it (a.k.a. a complete joke language that everybody hated) to being used in backend systems for servers.
Don't like the hyping up too much, but seeing proposals is really cool. Maybe you could do a video just digging trough a few proposals and explain the use-cases? (negative ones aswell, please) Or a video for each one. Seeing things move in javascript (and libraries) makes the ecosystem feel more alive and is great.
Disadvantages: Another peculiar operator you need to know. Awkward symbols, a pain for international keyboards. If logging needs to be done, the chain needs to be broken which means refactoring the entire function to keep the result the same if you do not wish to add logging in the implementations. Advantages: No need for reassigning values. Linear flow, makes it easier to read without the nesting. Possible performance gains depending on implementation. That's about all I can think of. I'd say better to have it than not, but I'm not too fond of it myself. I prefer the Visitor pattern in OOP, which is the equivalent of this. This is much faster to write out though, less structure necessary.
@@CottidaeSEA "Awkward symbols, a pain for international keyboards." - I don't agree with this, | and > are very common symbols for any programmer - you need | for "or" statement, and you need > when doing comparisons, so "pain for international keyboard" is invalid argument
@@TheChodex They are very common, but when typed separatedly. In spanish keyboards for example, the keys are located in completely opposite sides of the keyboard, and you need to use two different modifiers (shift for > and altgr for |).
@@TheChodex |>% all three are necessary and they all need some sort of Alt/Shift combination. While they are all used, you rarely use so many of them in succession. That's why they are awkward.
I really like the equivalent in Clojure (called "threading macros" there). They have things like: thread-first (->) Inserts value of previous function as first parameter of next thread-last (->>) Same but as last param thread-as (as->) Give param a name, like % So it would be something like: (defn piped [x] (-> x add-two square square square))
As someone who started web dev when most people were using Internet Explorer 6, I love how JS language and then ecosystem evolved over the past few years ❤
You can make your own pipe too: function pipe(...fns) { return function apply(arg) { return fns.reduce((prev, curr) => { return curr(prev) }, arg) } } And use it like this: pipe( toUpper, trim, removeNumbers, )(" test123")
yes please do make more videos like this. We need them! I saw your first video yesterday and immediately subscribed. We need more videos that relate to the real life scenarios that developers face, not just tutorials. great work man !
Hey Theo, love your videos a lot, always learning a bunch from you, as an entry level dev I could just watch your videos and see your approach to things and your rants and I can instantly know what not to do and what to do. Thanks a lot
Isn’t this currently possible by writing a small pipe utility function that converts functions passed as args to an array, then using the reduce prototype method to call each one with the previous returned value?
This is absolutely awesome. I've loved piping data through functions with stuff like lodash, it's sooo easy to grok but I've not been doing it as often as I'd like since lodash isn't exactly for everyone and it's massive. This is a game changer. Also Theo, yes to more videos like this. Newsy type of stuff is useful in its own way
In the meantime i've used the functional programming library "Ramda" which has a piping function to make piping a little less painfu. Its got some other pretty useful stuff too. But having piping adopted to native javascript would be *chefs kiss*
Pipe sounds great. Array reduce can be used for piping, for now. let y = [addTwo, square].reduce((a, f) => f(a), x). Additionally, create a small wrapper to do this, called pipe. e.g. pipe(x, [addTwo, square]). The array can be spread over lines (Prettier default for long ones).
I do really like this kind of video. I'm really bad at staying up to date with new innovations and I can already think of several use cases in my apps this would be awesome for. And please release another video when it is implemented. Thanks!
This is the quality comment I follow for. I probably wouldn't have known about this feature until months after its release without news-y stuff like this. Thanks a ton!
I'm up for more of these videos. It's best to know ahead of time why something was made so you can make a judgment on whether to use it or not past the hype (or unpopularity) when it comes out.
It’s cool I guess, buuuuut. It seems that I am the only one worried about adding new syntax to js. It’s shiny and fancy, but it has a real impact on perf. The parsers are now required to be more complicated, and as such, parsing perf is impacted by it. Moreover, we are shipping oodles and oodles of JS, which cannot run until it is fully parsed. We have already experienced parsing perf decrease with the introduction of ES6 waaay long ago. It is cool to see JS being pushed forward. Just hope we won’t get another C++, with whole “design by committee” shenanigans attached. Maybe we would require some kind of depreciation strategy going forward. Maybe something akin to "use strict", that axed a part of the language (remember “with” statement anyone?)
@@DryBones111 I'm referring to the future parsers perf (even on existing code, without the use of new features), not older ones compatibility. Of course you can transpile most of the new syntactic JS proposals.
Interested to see how they end up handling Promises and async in pipes. "I learned it in Elixir" I'd be willing to bet you learned it in the shell years before :D
I usually put the to-be-executed functions on [an] argument[s] in an array and then piped that array through a reduce method - no need for intermediary variable naming
2:19 "and we'll also be able to break this into a new line" Javascript return doesn't usually do that tho, I hope we will really be able to do that. It would be kinda hilarious if implicit statement termination remains the same as they implement this operator
I've been doing clojure for a few months and I love how we can seamlessly pipe many functions using the threading macros. This new feature will hopefully make things more readable in js. Kinda bummed that we have to call the func with % in every line of pipe, instead of just passing a function reference
It's better than Clojure, because with Clojure you have to choose where you pipe in the next function, either as the first or the last argument. Here with one syntax you get to pass it where you want.
Even better, allow piping of only arity-one functions, and supply a neat way to partially apply them without wrapping them in a new function. Then we can pipe function references AND reduce the ambiguity.
@@magne6049 Haskell has a very terse syntax for this because all functions are curried by default. Because of this I'd say it's a prime example. However because Javascript doesn't curry functions by default you'd need a new syntax for currying. Haskell also doesn't have a pipe operator in the same way, instead there is an application operator `$` which applies the right hand side (evaluated) to the left hand side. Which works like a pipe but the code reads right to left.
I’m kinda excited how this may impact library design. We all love method chaining for exactly the same reasons pipe operator is a thing. Right now you are required to put methods on an object / prototype to achieve that. Modern bundlers (generally*) don’t strip out object properties, since they cannot guarantee, that you won’t `Object.keys` them (or something similar). We might see a trend in libraries that expose just functions as opposed to methods on an object and expect you to use pipe to get ergonomics of method chaining. That way bundlers can tree-shake unused functionality more aggressively. *Compilers like Google Closure, can analyze through things like that. Kinda sad that almost nobody seems to use it (unless you are a Clojure JS developer). I feel like making JS compilers more accessible can be a HUGE positive change for the community.
I'm personally more of a fan of extension methods but in the case of javascript lacking explicit types I can see how that could be a problem. 3:46 I somehow doubt that. I think I get what you were trying to say but not the best choice of wording.
Good stuff! Firstly I though of this as a downgrade to readability. But after you said it will not perform assign operation, it sounds like it will be more performant. So the syntax becomes more bearable knowing it is ++ to perf :)
I really hope for functions that have only 1 param you can purely pipe functions together like in Unix. Eg: return x |> addTwo |> square |> square |> square
oh, i like doing the same with array types in js, because they have member functions that process the whole array so I'd do like, val = array. filter([find a particular thing in the array]). map([get a single part of every item]). reduce([combine them into a single result value]) return val or something like that, it looks like this is similar, but easier to use
I've always loved this feature without even knowing it existend! Glad to see it get closer to being a real thing. I wish the discourse online would show this kind of advancement in the language over other less useful/unnecessary ones such as the dreadful type annotation thing.
This is indeed a cool feature. Another feature I'm looking forward to using is the Temporal API (currently in stage 3), which solves issues with Date. Do check it out, if you haven't.
Elixir fans will be ecstatic! Btw it might be interesting to do a deep dive and show how you could use the pipe with promises... fetch is the first example that comes to mind (step 1: make a request and get the response, step 2: extract the response body, step 3: process the body somehow).
They should change that "chalk.dim()" example. (I guess it might make more sense as a "use case" for a proposal rather than a basic "showcase" to get the idea across) My initial reaction was "Oh god, more obscure, hard to read syntax...", but your example with add/square made so much more sense. Lot cleaner than function calls inside function calls.
While the pipe operator seems very cool and useful, you should be very careful with it 1. If you have too many pipes and one of them has a bug, good luck debugging, especially if they're one-liners 2. It makes it far less readable I'm a "const" kind of guy, i.e. I'd rather name everything to make the code readable than use "let" and reassign variables, making the code far less predictable
For 2, the thing is most of the time this is unnecessary and requires a lot of thought to name it something appropriate, where pipes allow you to just clearly show the flow of data from function of function. If you want to add a name, it’s very easy to add in an in line comment.
1. For implicit bugs, can easily add pipes in between pipes for logging the value tranformations. For explicit ones the stack trace can easily have "error at doSomething pipe#3". Or if not, then you still have at-line or at-function error logging and it shouldn't be too different 2. With one-off anonymous pipes I see your point. However at scale it should force creating smaller functions to make the piping readable which would improve readability and DRY throughout a codebase. Overall, people who write bad code will write bad functional code. There are tradeoffs but piping does make some situations more readable
Bugs aren't so much of an issue if you embrace functional composition, making use of strong static typing, and keeping the code declarative. And the few that sneak through will be caught in your tests, which are now extremely simple to write. Also, pipes are equivalent to using const at each stage. Nobody will be mutating those values before they're passed on to the next function.
Finally!!!! That feature will be the key for apply Railway programming in Javascript easier and more cleaner than ever !!!! Excited for this coming before 2030 !!!!!
I would be fine with being able to call any function on a type. So let x = 10; x.addTwo().squared(); return x; This would be difficult in JS though but in TS where the type information is available that would be great.
Piping will be insane! It's one of the reasons why bash is so powerful with a very basic "standard library", and I can't wait for Javascript to get it!
"programmers don't love naming things, programmers love programming"....amen! Nothing grinds my progress to a halt more than stopping to think of a name for something lol.
No way! One of the reasons I enjoy PowerShell scripting is the ability to pipe, similar to Bash scripting. It really lets you take advantage of the Unix mentality of single purpose programs/functions. Great content, I’ll be following this. I do hope they reduce it to a single character tho, the syntax is what makes it nice and feel so fluid.
I really hope they implement it in a way where I don't have to pass anything to the function, kinda of like `x |> addTwo |> square`. it seems a bit more readable to me then having a having a character as a the parameter, but might just be me.
big agree, or have it like lambda and you pick the carrier symbol, “x” being a common choice, that way you can use functions that take multiple arguments and you pass constants in or w/e // val is starting point, x then carries results, here we add two, then square it, then cube it return val.pipe(x |> addTwo(x) |> square(x) |> Math.pow(x, 3) );
@@viniciusataidedealbuquerqu2837 this is true, which is why this feature should be shipped with a clean syntax for partial application. Might as well double up that syntax for currying too. For the lack of better syntax: function(a, b, c) {...} To curry could be: functionA{} To partially apply: function{a, b} You can then pipe the arity-one function: c |> functionA{a, b} Or even better, if Typescript allowed us to curry all functions by default and we could just use the existing syntax: functionA(a, b) |> (c) === function(a, b, c)
This seems functionally similar to method chaining in fluent APIs. Am I right that it's basically that but without needing to explicitly write functions to work in a particular way?
Bash was my first language that exposed me to piping. You can also do something similar in Python called "method chaining" but that only works with methods not functions.
Are there any plans on making the return values usable multiple times? Using it like the last example is already achievable by making those functions available on the prototype (whether this is a good thing or not ) or use a promise. Both things will do for 95% of all applications out there. What I'd rather like to see is using the same value for multiple purposes.
Piping in js is amazing. My other favorite fp features are immutability by default, currying, match expression, pattern matching and expressions instead of statements, which it seems js will be lacking these for a long time. My preferences for a functional language are static typing and compiling ability. I am really interested in F# lately, it satisfies all those features and preferences i mentioned. It also can compile to js, which is amazing!
i think this may be a bit confusing because the return statement has stuff running after it, so if it gets added i would put it all in a temp variable and return that
We already have method chaining, which looks exactly the same, yet I don’t think it’s a concern when writing returns. Same goes for jsx, I feel like. There is a lot of code run, before return is evaluated. I don’t feel like this needs to be accounted separately for.
My most awaited feature (maybe together w/ Temporal). Hope it gets on the TypeScript roadmap as soon as they settle on the token for the topic reference. They could very simply compile it away into nested calls anyway. Right now, typing a pipe function is a huge pain in TS. Though that would probably be solved with partial generics inference too, which is on the roadmap after 5.0.
At last! One of the few things JS/TS is missing from being a full blown functional language. Write less, do more. I guess it's technically not less writing. Would be cool if it could optionally call the function if you don't use a % anywhere (so you could do return x|>addTwo|>square|>square, just pass the argument as the first param of the function) , but that seems quite complicated from the language point of view. I'd definitely curry everything if that was an option though. Just image, x|>add(3)|>pow(4), which would work like pow(add(x, 3), 4), but would translate to pow(4)(add (3)(x)). Issue with writing it longhand is, it kinda goes in reverse. you start with x, then add 3, then ^4 the result. Even if they stick with % or some other sign though, it'll be great.
I do like the longhand syntax there as it makes more sense. "Piping" is just a backwards version of an "application" operator. Consider the parenthesis () to be the application operator, and the piping syntax should be congruent with it.
I'm sure that this is well thought through not my initial reaction is that this still seems quite noisy. Isn't compose: piped = addTwo ° square (compose) I wonder whether something like piped = (x) => addTwo(%) |> square(%) Is allowed by this I'll take a look. It does seem great though.
I'm interested. I'm not a hardcore functional programming fan, but I only like using object oriented programming when it makes sense that data belong to certain objects and that I expect that if I were to scale my software, there would be many objects, not just one "______Factory" object that does a bunch of stuff. It's one reason why I love Python because I can mix and match as I see fit without being forced to write boilerplate.
"Programmers don't love naming things, programmers love programming."
Couldn't have said it better. As I was watching this I was thinking 'this is kinda like why Tailwind is great'. I suppose great minds think alike!
Typescript has really helped me not to worry about the names of things, since it's trivial later to do a 'rename' refactor on a name that no longer matches it's data or usage. I often start a type definition or variable declaration with 'let thinger = ...' so that I can fill in the variable first, use it, and then stare at my code and figure out what 'thinger' should be named now that it is filled in and used, it's funny that this works but it's super effective for me.
@@nathanfranck5822 I name stuff result more often than I'd like to admit. Though to be fair, it's a very good name for most scenarios. Since I tend to declare variables early, it also allows readers to know immediately what is going to be returned.
but do we "love" programming or do we love hating ourselves?
@@jonnylukejs I love calling people idiot, even if that idiot is me.
Id rather say programmers don't like to think about unnecessary stuff. I tried Tailwind and even though I don't have to think about naming, I have to make my way though long lines of utilitary classes. And that's really annoying. The same issue arises when U have to think how to put into Tailwind some stuff that I might easily do with Css or Scss
And another problem is that utilitary classes become so difficult to read especially when there are more than 10-20 of them for one JSX tag. I have to re-read again and again until I find what I'm looking for
Ugh I guess I'm finally gonna have to learn what functional programming is
It’s the best thing to have happened to me
TL;DR: Everything is a function, use them
only ever used functional programming
Functional programming is all about not repeating the same block of code but using this block inside a function and using the function instead of that block of code.
Oh you are in for a treat
I really like the pipeline operators from Elixir. It makes code based on functions (regardless of strictly FP paradigm) much more intuitive and readable.
I love how javascript is slowly more and more adopting fp patterns
This proposal will definitely have massive effect on the way we write our javascript code and the DX gains will be amazing
To be honest, when I first heard of a new feature coming to javascript, my first thought was "Another feature to bloat this old language even further". But now that I see what it does I think it is a good thing.
Javascript has been trying to be a lot of things for a long time. It is a language that is a little bit of everything, and it doesn't seem to be the best at anything. Its strength should be on the high level code. Turning into something closer to a functional programming could make more sense in the future. Similar to what Python does, where it has libraries compiled in C running in it's high level runtime with garbage collector.
I think that Javascript as a functional programming language would be easier to understand and debug.
@Angel developer experience.
@@rumplstiltztinkerstein js used to be functional until es6 classes and the frameworks pulled it to OOP
JavaScript was actually designed to be a functional language and then it was shoehorned into looking a bit like Java (Mostly syntactically, but also with things like adding null where undefined was just fine).
But FP things like first-class functions, anonymous function expressions, closures where there from the start. Also, at some point (2009 maybe?) we got the really nice array methods like map and reduce, keeping the momentum for FP in JS.
@@RaducuGabriel i'd argue that prototypes and objects arguably made it OOP before classes. Classes just made it more OO. Meanwhile, new additions like this make it more functional. While I don't really use JS anymore, it will remain in my heart as one of my favorite languages because it's the most innovative for developer experience. I mean, it evolved from being a simple browser scripting language as it was when I first used it (a.k.a. a complete joke language that everybody hated) to being used in backend systems for servers.
Don't like the hyping up too much, but seeing proposals is really cool.
Maybe you could do a video just digging trough a few proposals and explain the use-cases? (negative ones aswell, please)
Or a video for each one.
Seeing things move in javascript (and libraries) makes the ecosystem feel more alive and is great.
Disadvantages:
Another peculiar operator you need to know.
Awkward symbols, a pain for international keyboards.
If logging needs to be done, the chain needs to be broken which means refactoring the entire function to keep the result the same if you do not wish to add logging in the implementations.
Advantages:
No need for reassigning values.
Linear flow, makes it easier to read without the nesting.
Possible performance gains depending on implementation.
That's about all I can think of. I'd say better to have it than not, but I'm not too fond of it myself. I prefer the Visitor pattern in OOP, which is the equivalent of this. This is much faster to write out though, less structure necessary.
@@CottidaeSEA "Awkward symbols, a pain for international keyboards." - I don't agree with this, | and > are very common symbols for any programmer - you need | for "or" statement, and you need > when doing comparisons, so "pain for international keyboard" is invalid argument
@@TheChodex They are very common, but when typed separatedly.
In spanish keyboards for example, the keys are located in completely opposite sides of the keyboard, and you need to use two different modifiers (shift for > and altgr for |).
@@howdyimflowey4341 man of culture 👏👏
@@TheChodex |>% all three are necessary and they all need some sort of Alt/Shift combination. While they are all used, you rarely use so many of them in succession. That's why they are awkward.
I really like the equivalent in Clojure (called "threading macros" there).
They have things like:
thread-first (->) Inserts value of previous function as first parameter of next
thread-last (->>) Same but as last param
thread-as (as->) Give param a name, like %
So it would be something like:
(defn piped [x]
(-> x
add-two
square
square
square))
Great! Used in Elixir which is a great language
Another FP feature I hope will land into JavaScript is pattern matching
As someone who started web dev when most people were using Internet Explorer 6, I love how JS language and then ecosystem evolved over the past few years ❤
I started a year later after Explorer 7 came out. Glad things are getting better and better.
How do you feel about label statements?
I don't know if to love or hate this channel. Sometimes it's infuriating, sometimes enlightening. Guess that's properties of fire.
😂😂
Same opinion here, still the reason I haven't subscribed yet 💀
You can make your own pipe too:
function pipe(...fns) {
return function apply(arg) {
return fns.reduce((prev, curr) => {
return curr(prev)
}, arg)
}
}
And use it like this:
pipe(
toUpper,
trim,
removeNumbers,
)(" test123")
yes please do make more videos like this. We need them!
I saw your first video yesterday and immediately subscribed.
We need more videos that relate to the real life scenarios that developers face, not just tutorials.
great work man !
Hey Theo, love your videos a lot, always learning a bunch from you, as an entry level dev I could just watch your videos and see your approach to things and your rants and I can instantly know what not to do and what to do. Thanks a lot
Isn’t this currently possible by writing a small pipe utility function that converts functions passed as args to an array, then using the reduce prototype method to call each one with the previous returned value?
This is absolutely awesome. I've loved piping data through functions with stuff like lodash, it's sooo easy to grok but I've not been doing it as often as I'd like since lodash isn't exactly for everyone and it's massive. This is a game changer.
Also Theo, yes to more videos like this. Newsy type of stuff is useful in its own way
Anything that takes away the need to come up with names is massive DX improvement imo. Really excited about this.
what DX mean?
@@m3hdim3hdi Developer experience
yess! love to hear about stuff that's coming. I feel sharing it with more people is a good way to track its relevance
Pipes as type guards for typescript will be SO GOOD too. I can't wait for TS to support it after it's released xd
these sort of videos are rly cool and insightful, pls do them more often!!
I have used the single line approach before guess this is way more readable for later when you come back to that code.
Love a pipe operator. Can be better than extension methods tbh
Since I tested it in Elixir, I miss it in the other languages I have worked with. Good news for JavaScript!
In the meantime i've used the functional programming library "Ramda" which has a piping function to make piping a little less painfu. Its got some other pretty useful stuff too. But having piping adopted to native javascript would be *chefs kiss*
Love this kind of videos. Please post more of them
Pipe sounds great.
Array reduce can be used for piping, for now. let y = [addTwo, square].reduce((a, f) => f(a), x).
Additionally, create a small wrapper to do this, called pipe. e.g. pipe(x, [addTwo, square]).
The array can be spread over lines (Prettier default for long ones).
I do really like this kind of video. I'm really bad at staying up to date with new innovations and I can already think of several use cases in my apps this would be awesome for.
And please release another video when it is implemented. Thanks!
that seems super useful. looking forward to being able to use this in future apps
Thanks for hyping this up! Also, looking forward to this feature.
This is the quality comment I follow for. I probably wouldn't have known about this feature until months after its release without news-y stuff like this. Thanks a ton!
You finally sold me a pipe operator. Waiting for somebody to sell me decorators.
I think it can be nice in OOP, which I hate OOP so I don't care haha
I'm up for more of these videos. It's best to know ahead of time why something was made so you can make a judgment on whether to use it or not past the hype (or unpopularity) when it comes out.
It’s cool I guess, buuuuut. It seems that I am the only one worried about adding new syntax to js. It’s shiny and fancy, but it has a real impact on perf.
The parsers are now required to be more complicated, and as such, parsing perf is impacted by it. Moreover, we are shipping oodles and oodles of JS, which cannot run until it is fully parsed. We have already experienced parsing perf decrease with the introduction of ES6 waaay long ago.
It is cool to see JS being pushed forward. Just hope we won’t get another C++, with whole “design by committee” shenanigans attached. Maybe we would require some kind of depreciation strategy going forward. Maybe something akin to "use strict", that axed a part of the language (remember “with” statement anyone?)
This feature is easily transpiled, so if you want backwards compatability to older parsers, you can.
@@DryBones111 I'm referring to the future parsers perf (even on existing code, without the use of new features), not older ones compatibility. Of course you can transpile most of the new syntactic JS proposals.
can't this be already done with rxjs? or am I missing something here?
Would this pipe work with async functions or promises?
Interested to see how they end up handling Promises and async in pipes. "I learned it in Elixir" I'd be willing to bet you learned it in the shell years before :D
I usually put the to-be-executed functions on [an] argument[s] in an array and then piped that array through a reduce method - no need for intermediary variable naming
2:19 "and we'll also be able to break this into a new line"
Javascript return doesn't usually do that tho, I hope we will really be able to do that. It would be kinda hilarious if implicit statement termination remains the same as they implement this operator
Would you be able to define a pipe in a loop?
For example:
for (let i=0; i < 10; i++)
|> some expr (%)
Which would be the same as piping it 10 times.
I don't think so but you could do this right now
let something = "hello"
for(let i = 0; i < 10; i++){
something = someExpr(something)
}
LOVEIT functional array methods we're good but this is just godsend
I've been doing clojure for a few months and I love how we can seamlessly pipe many functions using the threading macros. This new feature will hopefully make things more readable in js. Kinda bummed that we have to call the func with % in every line of pipe, instead of just passing a function reference
% doesn’t call the func I think, but passes the result of the previous line explicitly. I think it’s much better than passing parameters implicitly.
It's better than Clojure, because with Clojure you have to choose where you pipe in the next function, either as the first or the last argument. Here with one syntax you get to pass it where you want.
Even better, allow piping of only arity-one functions, and supply a neat way to partially apply them without wrapping them in a new function. Then we can pipe function references AND reduce the ambiguity.
@@DryBones111 what is the best in class example of this? language and code?
@@magne6049 Haskell has a very terse syntax for this because all functions are curried by default. Because of this I'd say it's a prime example. However because Javascript doesn't curry functions by default you'd need a new syntax for currying.
Haskell also doesn't have a pipe operator in the same way, instead there is an application operator `$` which applies the right hand side (evaluated) to the left hand side. Which works like a pipe but the code reads right to left.
I’m kinda excited how this may impact library design. We all love method chaining for exactly the same reasons pipe operator is a thing. Right now you are required to put methods on an object / prototype to achieve that.
Modern bundlers (generally*) don’t strip out object properties, since they cannot guarantee, that you won’t `Object.keys` them (or something similar).
We might see a trend in libraries that expose just functions as opposed to methods on an object and expect you to use pipe to get ergonomics of method chaining. That way bundlers can tree-shake unused functionality more aggressively.
*Compilers like Google Closure, can analyze through things like that. Kinda sad that almost nobody seems to use it (unless you are a Clojure JS developer). I feel like making JS compilers more accessible can be a HUGE positive change for the community.
excited for this! Yea, please do more videos like it :)
I like these weird-newsy-thing-that-hasn't-happened-yet-but-you're-hyped-about-it videos
I'm personally more of a fan of extension methods but in the case of javascript lacking explicit types I can see how that could be a problem.
3:46 I somehow doubt that. I think I get what you were trying to say but not the best choice of wording.
Can't wait for this. I feel in love with pipe operators after using Elixir, this is gonna make Javascript hella fun to write
pipe in elixir is so good. I implemented something similar in Scala 3 using extensions
Good stuff! Firstly I though of this as a downgrade to readability. But after you said it will not perform assign operation, it sounds like it will be more performant. So the syntax becomes more bearable knowing it is ++ to perf :)
I really hope for functions that have only 1 param you can purely pipe functions together like in Unix. Eg: return x |> addTwo |> square |> square |> square
yes for more of these, i had no idea this was coming
oh, i like doing the same with array types in js, because they have member functions that process the whole array
so I'd do like,
val = array.
filter([find a particular thing in the array]).
map([get a single part of every item]).
reduce([combine them into a single result value])
return val
or something like that, it looks like this is similar, but easier to use
I've always loved this feature without even knowing it existend! Glad to see it get closer to being a real thing. I wish the discourse online would show this kind of advancement in the language over other less useful/unnecessary ones such as the dreadful type annotation thing.
Oh dear lord, can't wait to blow my brains out seeing juniors pruducing 50 part pipes with this stuff.
This is indeed a cool feature. Another feature I'm looking forward to using is the Temporal API (currently in stage 3), which solves issues with Date. Do check it out, if you haven't.
That’s great news. It’s absurd how cryptic vanilla JS is about handling time.
Elixir fans will be ecstatic! Btw it might be interesting to do a deep dive and show how you could use the pipe with promises... fetch is the first example that comes to mind (step 1: make a request and get the response, step 2: extract the response body, step 3: process the body somehow).
This is great! Nushell made me a convert to pipes recently.
They should change that "chalk.dim()" example. (I guess it might make more sense as a "use case" for a proposal rather than a basic "showcase" to get the idea across)
My initial reaction was "Oh god, more obscure, hard to read syntax...", but your example with add/square made so much more sense. Lot cleaner than function calls inside function calls.
100% enjoy these types of videos.
While the pipe operator seems very cool and useful, you should be very careful with it
1. If you have too many pipes and one of them has a bug, good luck debugging, especially if they're one-liners
2. It makes it far less readable
I'm a "const" kind of guy, i.e. I'd rather name everything to make the code readable than use "let" and reassign variables, making the code far less predictable
You missed the plot here entirely
For 2, the thing is most of the time this is unnecessary and requires a lot of thought to name it something appropriate, where pipes allow you to just clearly show the flow of data from function of function. If you want to add a name, it’s very easy to add in an in line comment.
1. For implicit bugs, can easily add pipes in between pipes for logging the value tranformations. For explicit ones the stack trace can easily have "error at doSomething pipe#3". Or if not, then you still have at-line or at-function error logging and it shouldn't be too different
2. With one-off anonymous pipes I see your point. However at scale it should force creating smaller functions to make the piping readable which would improve readability and DRY throughout a codebase.
Overall, people who write bad code will write bad functional code. There are tradeoffs but piping does make some situations more readable
Bugs aren't so much of an issue if you embrace functional composition, making use of strong static typing, and keeping the code declarative. And the few that sneak through will be caught in your tests, which are now extremely simple to write.
Also, pipes are equivalent to using const at each stage. Nobody will be mutating those values before they're passed on to the next function.
Finally!!!!
That feature will be the key for apply Railway programming in Javascript easier and more cleaner than ever !!!!
Excited for this coming before 2030 !!!!!
I would be fine with being able to call any function on a type. So let x = 10; x.addTwo().squared(); return x; This would be difficult in JS though but in TS where the type information is available that would be great.
Check out Dart, it has "extension methods" for exactly this use case.
Nim have something similar to this too, pretty neat
@@zzzyyyxxx yeah but it's dart... Many languages has this.
Awesome, always wanted pipe operator, now we just need to get some pattern matching
The operator has been a longtime coming. I thing it's been a TC39 proposal in some stage or another for many years.
This would be great to see in vanilla JS. Thanks for the update Theo!
Piping will be insane!
It's one of the reasons why bash is so powerful with a very basic "standard library", and I can't wait for Javascript to get it!
Ocaml has this as well. Javascript is my first love, so this would be awesome to see. Hope it makes it in!
Cap *^* is a XOR operator in JavaScript not a Power operator, Power operator is **.
1:41 `^` is a bitwise XOR operator. Exponentiation operator is `**`.
The idea is awesome.
The syntax makes me cry.
I really hope they reconsider the syntax.
"programmers don't love naming things, programmers love programming"....amen! Nothing grinds my progress to a halt more than stopping to think of a name for something lol.
Is this at all similar to `.then() ` in async javascript? Also reminds me a little of chaining jquery functions
yes! I've been using userland implementations of compose/pipe in JS for years! hopefully we'll get tc39/proposal-pattern-matching next,
No way! One of the reasons I enjoy PowerShell scripting is the ability to pipe, similar to Bash scripting. It really lets you take advantage of the Unix mentality of single purpose programs/functions. Great content, I’ll be following this. I do hope they reduce it to a single character tho, the syntax is what makes it nice and feel so fluid.
I really hope they implement it in a way where I don't have to pass anything to the function, kinda of like `x |> addTwo |> square`. it seems a bit more readable to me then having a having a character as a the parameter, but might just be me.
it's impossible to do this way since there's no function currying in JS. and this really hinders partial application in which this is being used
big agree, or have it like lambda and you pick the carrier symbol, “x” being a common choice, that way you can use functions that take multiple arguments and you pass constants in or w/e
// val is starting point, x then carries results, here we add two, then square it, then cube it
return val.pipe(x
|> addTwo(x)
|> square(x)
|> Math.pow(x, 3)
);
they are using this from clojure anonymous fn but clojure still has point free application
@@viniciusataidedealbuquerqu2837 this is true, which is why this feature should be shipped with a clean syntax for partial application. Might as well double up that syntax for currying too.
For the lack of better syntax:
function(a, b, c) {...}
To curry could be:
functionA{}
To partially apply:
function{a, b}
You can then pipe the arity-one function:
c |> functionA{a, b}
Or even better, if Typescript allowed us to curry all functions by default and we could just use the existing syntax:
functionA(a, b) |> (c) === function(a, b, c)
This seems functionally similar to method chaining in fluent APIs.
Am I right that it's basically that but without needing to explicitly write functions to work in a particular way?
I love the newsy type of stuff keep it up
Bash was my first language that exposed me to piping. You can also do something similar in Python called "method chaining" but that only works with methods not functions.
so when/if this done and widely adopted then apps will be faster? Due to less memory allocation for storing temp values ... I hope
Didn't know this was a thing this is awesome. I really hope it makes it too
How about debugging/breakpoints? Whether I will be able to egzamin the intermediate values and put breakpoint anywhere between those pipes?
Before I clicked on this video, I didn't know what piping was. Now I'm excited to get it!
Are there any plans on making the return values usable multiple times? Using it like the last example is already achievable by making those functions available on the prototype (whether this is a good thing or not ) or use a promise. Both things will do for 95% of all applications out there. What I'd rather like to see is using the same value for multiple purposes.
Piping in js is amazing. My other favorite fp features are immutability by default, currying, match expression, pattern matching and expressions instead of statements, which it seems js will be lacking these for a long time. My preferences for a functional language are static typing and compiling ability. I am really interested in F# lately, it satisfies all those features and preferences i mentioned. It also can compile to js, which is amazing!
Oooh man this would be amazing. I hope this goes through.
what's your thoughts on using Ramda for the FP piping things?
What I find really really cool in dart is the .. operator to chain function
I've been waiting for this (and pattern matching) for a very long time now. With those two I'd be a lot happier with the language.
i think this may be a bit confusing because the return statement has stuff running after it, so if it gets added i would put it all in a temp variable and return that
We already have method chaining, which looks exactly the same, yet I don’t think it’s a concern when writing returns.
Same goes for jsx, I feel like. There is a lot of code run, before return is evaluated.
I don’t feel like this needs to be accounted separately for.
@@yapet i forgot about method chaining because i dont use methods a lot, my bad
I love these kind of videos
Helpful video, educational on benefits of fp. Thanks 🙏
My most awaited feature (maybe together w/ Temporal). Hope it gets on the TypeScript roadmap as soon as they settle on the token for the topic reference. They could very simply compile it away into nested calls anyway. Right now, typing a pipe function is a huge pain in TS. Though that would probably be solved with partial generics inference too, which is on the roadmap after 5.0.
At last! One of the few things JS/TS is missing from being a full blown functional language.
Write less, do more.
I guess it's technically not less writing. Would be cool if it could optionally call the function if you don't use a % anywhere (so you could do return x|>addTwo|>square|>square, just pass the argument as the first param of the function) , but that seems quite complicated from the language point of view. I'd definitely curry everything if that was an option though. Just image,
x|>add(3)|>pow(4), which would work like pow(add(x, 3), 4), but would translate to pow(4)(add (3)(x)). Issue with writing it longhand is, it kinda goes in reverse. you start with x, then add 3, then ^4 the result.
Even if they stick with % or some other sign though, it'll be great.
I do like the longhand syntax there as it makes more sense. "Piping" is just a backwards version of an "application" operator. Consider the parenthesis () to be the application operator, and the piping syntax should be congruent with it.
So clean. I like it
thanks for sharing this
Hi Theo, Do you think zustand is better than context api and redux toolkit?
This is the best type of video imo
The exception from the naming things issue seems to be nominal types
There are libraries that implement pipe for example Rambda. I didn’t hear about it very popular. I would be sceptical.
I'm sure that this is well thought through not my initial reaction is that this still seems quite noisy. Isn't compose:
piped = addTwo ° square
(compose)
I wonder whether something like
piped = (x) => addTwo(%) |> square(%)
Is allowed by this
I'll take a look. It does seem great though.
I think in the example you did you could technically just write x = square(x) without defining a temp variable
I'm interested. I'm not a hardcore functional programming fan, but I only like using object oriented programming when it makes sense that data belong to certain objects and that I expect that if I were to scale my software, there would be many objects, not just one "______Factory" object that does a bunch of stuff. It's one reason why I love Python because I can mix and match as I see fit without being forced to write boilerplate.
That's dope!