by mgreenw on 5/19/23, 2:06 PM with 30 comments
by Waterluvian on 5/19/23, 10:30 PM
I am in love with “everything is an expression” from my time with Rust. I regularly use a ‘let’ and wish I could just have the entire conditional feed into a ‘const’ given it’s never going to change after the block of code responsible for assignment.
I wish there were more generations of ‘use strict’ so that we could make bolder, more breaking changes to the language without breaking stuff or dying in a horrible fire of “just roll your own dialect using compiler plugins.”
by gtsop on 5/20/23, 3:53 PM
The actual solution is to extract a function. What is the legitimate excuse for not extracting a function (other than being lazy, which i will not accept as an argument)
Edit: Just to enhance my comment, having a separate function with a distinct name enhances readability and maintainability. Readability is enhanced because a clear name lets the reader understand what is happening in the function (this attribute is lost with self calling nameless functions). Also, less lines need to be read to understand the wider context. Maintainability is enhanced because 1) more readable code is easier to reason about and change and 2) extracting a function means it can be reused
by tln on 5/20/23, 2:06 AM
const wait = ms => new Promise(resolve => setTimeout(resolve, ms))
Whatever runs the main function should probably do more, like handling rejections.by SirensOfTitan on 5/20/23, 12:59 PM
export const UNHANDLED: unique symbol = Symbol("UNHANDLED");
export function runIfUnhandled<TReturn = void>(
ifUnhandled: () => TReturn,
run: (unhandled: Unhandled) => TReturn | Unhandled,
): TReturn {
const runResult = run(UNHANDLED);
if (runResult === UNHANDLED) {
return ifUnhandled();
}
return runResult;
}
I often use it to use guards to bail early, while keeping the default path dry. In particular, I used it heavily in a custom editor I built for a prior project, example: runIfUnhandled(
() => serialize(node, format),
(UNHANDLED) => {
if (
!Element.isElement(node) ||
!queries.isBlockquoteElement(node)
) {
return UNHANDLED;
}
switch (format) {
case EditorDocumentFormat.Markdown: {
const serialized = serialize(node, format) as string;
return `> ${serialized}`;
}
default: {
return UNHANDLED;
}
}
},
);
by brundolf on 5/20/23, 4:41 AM
function given<T, R>(
val: T|null|undefined,
fn: (val: T) => R
): R|null|undefined {
if (val != null) {
return fn(val)
} else {
return val // null|undefined
}
}
function greet(name: string|null) {
return given(name, name => 'Hello ' + name)
}
This is equivalent to eg. Rust's .map()Can also do a version without the null check for just declaring intermediate values:
function having<T, R>(
val: T,
fn: (val: T) => R
): R {
return fn(val)
}
const x =
having(2 * 2, prod =>
prod + 1)
by haburka on 5/20/23, 9:40 PM
Additionally for ever developer that hasn’t seen this, they have to look up the run function and try to grasp WTF it is doing. And god forbid someone modifies the run function.
by jlhawn on 5/19/23, 10:17 PM
function doWork() {
const x = run(() => {
if (foo()) return f();
if (bar()) return g();
return h();
});
return x * 10;
}
by aidenn0 on 5/20/23, 1:48 AM