@seiyab/do-expr
v1.0.1
Published
do expression as a package inspired by https://tc39.es/proposal-do-expressions/
Downloads
8
Readme
package of do
expressions
This package is inspired by proposal-do-expressions
- https://github.com/tc39/proposal-do-expressions
- https://tc39.github.io/proposal-do-expressions/
Motivation
- expression-oriented programming one of the great advances of FP
- expressions plug together like legos, making more malleable programming experience in-the-small
Installation
npm install @seiyab/do-expr
Examples
Write in an expression-oriented style, scoping variables as locally as possible:
import { do_ } from "@seiyab/do-expr";
let x = do_(() => {
let tmp = f();
return tmp * tmp + 1
});
Use conditional statements as expressions, instead of awkward nested ternaries:
let x = do_(() => {
if (foo()) { return f() }
else if (bar()) { return g() }
else { return h() }
});
Especially nice for templating languages like JSX:
return (
<nav>
<Home />
{do_(() => {
if (loggedIn) return <LogoutButton />;
return <LoginButton />;
})}
</nav>
)
Edge cases
var
declarations
var
declarations are allowed, with the hoisting to the parameter function's scope.
This behavior differs from proposal-do-expressions.
Empty do
do_(() => {})
is almost equivalent to undefined
.
Some lint tool might blame it.
await
Works fine.
To use await
, you need an await
before do_
and an async
before ()
.
const result = await do_(async () => {
const x = await fetchSomeData();
if (x.isSuccess) return "ok";
return "oops";
});
throw
Works fine. Does what you expect.
break
/continue
/yield
These won't work like proposal-do-expressions.
The major reason is technical one. And it's also for readability. Allowing these might induce confusion. These don't fit the motivation "expression-oriented programming".
return
It has a different functionality from proposal-do-expressions.
return
is used for declaring result of do_
, rather than return
ing from outer function.
Conflict with do-while
No problem at all.
Comparison
vs. IIFE
Yes, do-expr
is just IIFE as you noticed.
do-expr
still has some advantages.
The main advantage is readability. We need to read last part of the expressions to know whether expressions are IIFEs or not.
// plain IIFE
const x = (() => {
// ^^^^^ is x a function?
if (f()) return g();
return h();
})()
//^^ Finally I got it. this is an IIFE.
// do_
const x = do_(() => {
// ^^^ OK, this behaves like a do expression.
if (f()) return g();
return h();
})
As another idea, you can declare _do
argument to indicate it behaves like do expression.
const x = ((_do) => {
// ^^^ OK, this behave like a do expression.
if (f()) return g();
return h();
})()
In this case, you need to write coding guideline documents and notify colleagues.
Because this is not idiomatic yet.
If readers don't know this idiom, they are confused by a mysterious _do
argument and might consider that it is a function declaration until they reach the last ()
.
On the other hand, do_
already has README.md that you read now.
If readers don't know do_
, they are likely to google @seiyab/do-expr
and find this README.
vs. proposal-do-expressions
Functionality
Some features like break
/ continue
/ yield
doesn't work with @seiyab/do-expr
.
The reasons are not only technical ones.
It is an intended interface design.
The main motivation of @seiyab/do-expr
is expression-oriented programming.
Though the features are perhaps helpful, they don't fit the original motivation.
They will induce unnecessary complexity.
The following issue reports proposal-do-expressions vs IIFEs: https://github.com/tc39/proposal-do-expressions/issues/34
Availability
proposal-do-expressions is still stage 1 of the TC39 process.
But a babel plugin @babel/plugin-proposal-do-expression
is available.
@seiyab/do-expr
already has stable release.