REJOIN ugliness and the usefulness of tests

Short summary: We need more tests and should ask ourselves if they make sense.

Discovering a bug in REJOIN motivated me to create some tests for it (it had none) and the outcome of that was I was quite surprised at how weird REJOIN's current behaviour is.

Though I have used REJOIN extensively in my R2 code, I must be using it in a way that avoids some behavioural ugliness.

Have a look at the tests added to Ren-c for REJOIN.

Thought train:

  • Why is REJOIN so weird?
  • Maybe I don't want to REJOIN in my code anymore if it is that odd.
  • I only became aware of how weird it is by writing the tests.
  • Tests serve as documentation and can therefore draw attention to weirdness perhaps motiving a better solution.
  • I wonder if it would be useful to formalise the "tests as documentation" notion?
1 Like

And REJOIN suggests that you join pieces of something that broke back together again. Most of us have started out using JOIN to put things together, then found out it did not do what they wanted and so they got pointed to REJOIN that does the expected thing.
Long story short, JOIN is seldom used and we all use REJOIN all the time, where we initially want to read just JOIN.

The name REJOIN is unlucky too because in an alphabetic list of functions it does not show up next to JOIN and will easily be overlooked, where JOIN-ALL will be found because is is right underneath JOIN.
Perhaps a longer name like JOIN-ON-FIRST will be better describing that the JOIN will result in something of the TYPE! of the first item.
SPACED and UNSPACED, I will have to get used to those. Perhaps I am better of with alias JOIN-SPACED and JOIN-UNSPACED for those.

About the code of REJOIN in https://github.com/metaeducation/ren-c/blob/622d376b4504f828e35a18bf9b1c394c29efc527/src/mezz/mezz-legacy.r#L300 there are still a few unfamiliar functions for me in there (CHAIN, SPECIALIZE) so I cannot directly say what is wrong in its definition.

The link I gave was to the commit.

You can find the current REJOIN here, which I have written to emulate R3, it is not using the newer functions.

Well, now you know why I made SPACED and UNSPACED!

1 Like

I Think We Finally Have An Answer For Wiping Out REJOIN

Let's say you want to make a BINARY! out of some reduced material with REJOIN. You'd have done something like this:

>> rejoin [#{} "ABC" 1 + 2 3 + 4]
== #{4142430307}

But let's imagine a world where JOIN not only does not implicitly REDUCE, but also allows a datatype as the thing to "join to". Since you can't join to a datatype, it assumes that's what you want.

>> join binary! reduce ["ABC" 1 + 2 3 + 4]
== #{4142430307}

And wait... Ren-C has the generic GET-BLOCK! as a shorthand for REDUCE.

>> join binary! :["ABC" 1 + 2 3 + 4]
== #{4142430307}

Kablammo. And hey, now we have the name for a non-reducing JOIN. It's JOIN.

:fireworks:

We can still add a /REDUCE refinement to APPEND, INSERT, CHANGE, JOIN, etc. This would avoid the creation of an intermediate block...the reduced products could be merged into the built result as you go.

I doubt I'd put the names REJOIN, REMOLD, REFORM etc. "in the box". But if there was a REJOIN, it would be arity-2 and mean JOIN/REDUCE, where the default JOIN does not reduce. The old notion of REJOIN is now dead as a doornail. :door: :hammer:

It's going to always be possible to add sneaky optimization refinements to things. However, I don't think you should have to use them...and we should stylize for the best and clearest experience. This points in that direction.

2 Likes

REJOIN will only exist in Redbol, so I'll defer to Red's tests for it. Whatever they do, we should be able to do (whether we think it's useful or not).

For the sake of not throwing things away completely, here were the REJOIN tests that were still hanging around despite not having any uses in Modern Ren-C:

([] = rejoin [])
([] = rejoin [[]])
("~null~" = rejoin ["" null])
([] = rejoin [null null])
([[]] = rejoin [[][]])
([[][]] = rejoin [[][][]])
(
    block: [[][]]
    not same? first block first rejoin block
)
([1] = rejoin [[] 1])
("" = rejoin [{}])
("1" = rejoin [1])
(
    value: 1
    "1" = rejoin [value]
)
[
    https://github.com/metaeducation/ren-c/issues/1084
    (#ab = rejoin [#a #b])
]