Live data from Hacker News

'Do' More with 'Run'

maxgreenwald.me

11–20 of 33 posts

Re: 'Do' More with 'Run'

#11
post #7

Parentheses phobia strikes again. This is 1 character longer than an IIFE (since you replace "()" with "run"

i'd say that it's a bit more readable:

  run(() => { return foo })
looks better than, and assuming pre-existing knowledge of what `run` does, is more understandable than

  (() => { return foo })()
but this is also a fairly contrived example

Re: 'Do' More with 'Run'

#12
Another short utility I often add (that I wish were a language feature):

  function given(
    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(
    val: T,
    fn: (val: T) => R
  ): R {
    return fn(val)
  }

  const x = 
    having(2 * 2, prod =>
      prod + 1)

Re: 'Do' More with 'Run'

#13
post #2

In the "Use as a `do` expression" section, the example which uses `run` does not need the `else` cases and could be simplified: function doWork() { const x = run(() => { if (foo()) return f(); if (bar()) return g(); return h(); }); return x * 10; }

Can also get rid of the `run` and move parens to simplify even further: function doWork() { const x = () => { if (foo()) return f(); if (bar()) return g(); return h(); }; return x() * 10; }

[deleted]

Re: 'Do' More with 'Run'

#14
One control flow function I use often in JavaScript is my `runIfUnhandled` function:

    export const UNHANDLED: unique symbol = Symbol("UNHANDLED");
    export function runIfUnhandled(
      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;
              }
            }
          },
        );

Re: 'Do' More with 'Run'

#15

Feels like code golf. The two run examples are basically the same, but now I have to reason about what ‘run’ is and I’ve made my stack trace more complicated. 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 the…

> 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'm currently doing a lot of audio work, where I kind of want to define some parameters early on that won't change, except if something "magic" happens. So, a kind of "unlockable" constant. Think in terms of, a bunch of filter coefficients that are predetermined by the design of the filter but need to be calculated to match a given sample rate.

Just a kind of "set and forget" variable, that ought not be written to more than once, or maybe only written to by the thing that first wrote it.

Re: 'Do' More with 'Run'

#16
post #6

Earlier quoted context omitted.

Can also get rid of the `run` and move parens to simplify even further: function doWork() { const x = () => { if (foo()) return f(); if (bar()) return g(); return h(); }; return x() * 10; }

And a step further into the past, no need for a lambda - I find this clearer: function doWork() { function calcX() { if (foo()) return f(); if (bar()) return g(); return h(); } return calcX() * 10; } Where "calc" can be "gen[erate]" or "find" or at least more descriptive.

Well you definitely can do that to my somewhat contrived example that is loosely based off of an example from the `do` expression proposal, but I'm not sure its better.

Part of the beauty of `run` is that you don't have to declare and name a function `calcX`. In longer and more complex examples, declaring a function inline like this is potentially confusing because you don't get to see where it is used, whereas with `run` you assign the return value immediately to a variable.

Re: 'Do' More with 'Run'

#17
post #2

In the "Use as a `do` expression" section, the example which uses `run` does not need the `else` cases and could be simplified: function doWork() { const x = run(() => { if (foo()) return f(); if (bar()) return g(); return h(); }); return x * 10; }

Completely agreed, and I use this if-based early return syntax frequently! That being said, I like using `if` and `else if` and `else`, but maybe that's just me! I don't think there's a substantial difference in readability or utility.

Re: 'Do' More with 'Run'

#18
post #7

Parentheses phobia strikes again. This is 1 character longer than an IIFE (since you replace "()" with "run"

Yes, I do think the extra parens are less readable.

Its not about number of characters, its about reasoning that the inline function that you just wrapped in parens is then called later, potentially after many lines. At least with `run` it's immediately clear based on the name that you are running the function.

Edit: This is pretty funny. I'm a parensaphobe! (not really) https://www.reddit.com/r/ProgrammerHumor/comments/qawpws/the...

Re: 'Do' More with 'Run'

#19

Feels like code golf. The two run examples are basically the same, but now I have to reason about what ‘run’ is and I’ve made my stack trace more complicated. 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 the…

> I am in love with “everything is an expression” from my time with Rust

Totally agreed! I wish JS had if expressions (maybe in the future?). It doesn't seem like such a huge change if it were rolled out slowly like other new syntax features but maybe I have no idea what I'm talking about.

Hopefully things like `run` can help move the needle on this. I like it because it feels more FP and intentional than IIFE's everywhere.

Re: 'Do' More with 'Run'

#20
post #10

I like it! Another one-liner I'm constantly adding is const wait = ms => new Promise(resolve => setTimeout(resolve, ms)) Whatever runs the main function should probably do more, like handling rejections.

Same, I've written this so many times. Node just added this as a built-in utility FWIW

https://nodejs.org/api/timers.html#timerspromisessettimeoutd...

Post reply on HN