capi icon indicating copy to clipboard operation
capi copied to clipboard

`Rune.spread` util for convenient merging of tuple/object runes

Open harrysolovay opened this issue 2 years ago • 7 comments

Let's say we have the following:

const a = Rune.constant(["a", "b", "c"])
const b = Rune.constant(["d", "e", "f"])

A Rune.spread util could be used as follows.

const merged = Rune.spread(a, b)

Instead of...

const merged = Rune
  .tuple([a, b])
  .map(([a, b]) => [...a, ...b])

harrysolovay avatar Feb 12 '23 20:02 harrysolovay

(there would have to be two different functions, one for arrays and one for objects; JS distinguishes them by syntax, but we haven't such a luxury here)

tjjfvi avatar Feb 13 '23 15:02 tjjfvi

Would it be possible for us to boil this into Rune.array, Rune.tuple and Rune.rec without too wild of typings? Aka.

const a = Rune.constant(["a", "b", "c"])
const b = Rune.constant(["d", "e", "f"])

const merged = Rune.tuple(a, b, ["g", "h"], Rune.constant(["i", "j"]))

harrysolovay avatar Feb 13 '23 17:02 harrysolovay

The typings would probably be fairly hairy, and it would make the error of Rune.tuple("a", "b") much more confusing.

tjjfvi avatar Feb 13 '23 17:02 tjjfvi

Having to tuple/record/array-ify some values in order to map them into their merged counterpart is... a lot.

Is there another approach that would offer the same usability gain?

harrysolovay avatar Feb 15 '23 13:02 harrysolovay

I'll play with the API and see what seems most ergonomic

tjjfvi avatar Feb 15 '23 15:02 tjjfvi

How about a .spread property? That way we can use spread in any position like in vanilla TS

For tuples:

const a = Rune.tuple(["a", "b", "c"])
const b = Rune.tuple(["d", "e", "f"])

// merged: Rune<["a", "b", "c", 1, 2, 3, "d", "e", "f"], never>
const merged = Rune.tuple([a.spread, 1, 2, 3, b.spread])

For a simple array, I think it'd be easier to add the concat method to Array rune.

const a = Rune.array(["a", "b", "c"])
const b = Rune.array(["d", "e", "f"])

const merged = a.into(ArrayRune).concat(b)

Additionally, we could add a merge method for arrays and objects on something like ValueRune.

const a = Rune.constant(["a", "b", "c"])
const b = Rune.constant(["d", "e", "f"])

const merged = Rune.merge(a, b)

const c = Rune.constant({ hello: "world" })
const d = Rune.constant({ hello1: "world1" })

const merged = Rune.merge(a, b)

Not sure where to keep this last one though, it could be on Rune.merge or ValueRune.merge (not static) or ArrayRune.concat. I think it's worth it to think about where we should handle common behavior amongst Rune, ValueRune, ArrayRune, Rune.tuple and etc.

nythrox avatar Apr 10 '23 20:04 nythrox

Regarding this...

const merged = Rune.tuple([a.spread, 1, 2, 3, b.spread])

... it has the same problem as one of the aforementioned designs: in T6's words:

The typings would probably be fairly hairy

Each factory's types (tuple, array, rec) would become far more complicated.

Regarding this approach...

const a = Rune.array(["a", "b", "c"])
const b = Rune.array(["d", "e", "f"])

const merged = a.into(ArrayRune).concat(b)

... this might be nice. One other idea:

Rune.spread(Rune.tuple, [[], [], []])
Rune.spread(Rune.rec, [{}, {}, {}])

harrysolovay avatar Apr 10 '23 21:04 harrysolovay