It's Time To JOIN Together

As @Brett's critique of yesteryear pointed out, REJOIN sucked.

We now have much more palatable options and strategies. Most notably DELIMIT+SPACED+UNSPACED, which have become nicely defined foundations for one's daily string work.

So REJOIN is in the trash heap, but what about JOIN?

If naming were consistent, you might think from this pattern:

append a reduce b <=> repend a b

...that the following would have been true:

join a reduce b <=> rejoin a b  ; one would have perhaps thought?

But no...REJOIN was single arity (and was a mess).

JOIN implicitly reduced, and was basically this:

join a b <=> append copy a reduce b

But b didn't have to be a BLOCK!, so if it was not, it wasn't reduced and just left as-is.

rebol2>> join "abc" [1 + 2 3 + 4]
== "abc37"  ; so the block was reduced

rebol2>> d: 10
rebol2>> join "abc" 'd
== "abcd"  ; not abc10, so the word was *not* reduced

Ren-C Drops JOIN's Implicit Reduce Semantics

Almost all of JOIN's usages turn out to be just adding one thing onto a URL! or FILE!

>> base-path: %/foo/bar/
>> filename: %something.txt

>> data: read join base-path filename

That's a good solid most of it. But Ren-C leans more heavily onto JOIN to produce PATH! and TUPLE!, because APPEND doesn't work on them.

>> item: [c d]

>> join 'a/b/ item
== a/b/[c d]

(Note that the real power tool for PATH! and TUPLE! building is COMPOSE, e.g. compose a/b/(spread block)...but this is awkward to use in the simple appending case JOIN is serving.)

Because it's plenty legitimate to want to stick a block "as is" onto the end of a PATH! and not REDUCE it, we make JOIN fit in with APPEND and the other functions by making you be explicit when you want reducing or spreading.

>> join "abc" spread reduce [1 + 2 3 + 4]
== "abc37"

>> join "abc" spread [1 + 2 3 + 4]
== "abc1+23+4"

 >> join "abc" [1 + 2 3 + 4]
 ** Error: Cannot JOIN blocks onto strings (use SPREAD for itemwise appending)

It's more typing, but I feel like it's the right amount of typing to be explicit about what you are doing.

2 Likes

It's not so alien. I have experimented with rootless paths on Rebol2 but using a neutral word, as they always need one position 1 on that language. Paths are one of the expressive ways I have accumulated the most ideas. Also, other than non-active words, I would like to have the ability to append paths/refinements to a word without conversion, so you can do something like:

cmd: 'play
ref: /loud
val1: %TheDarkSideOfTheMoon.mp3
action: [cmd val1]
cmd: append cmd ref
do reduce action

PATH! and TUPLE! in Ren-C are immutable, so you cannot APPEND to them.

However, you can COMPOSE them.

 >> de: [d e]

 >> compose '(if false [<ab>])/c/(de)/(spread de)
 == c/[d e]/d/e

(Note: A failed IF returns void... so the path segment vanishes completely. If you want to preserve the leading slash, you need to evaluate to a "blank" (like a NONE!))

And you can also JOIN paths (see above posts, it's why I moved your comment). It's a work in progress, but a few things have been pinned down...like that Ren-C's JOIN does not reduce implicitly.

I am not necessarily against making JOIN able to handle this:

>> join cmd ref
== play/loud

But it does not do this at the moment...as the code is styled that it must know the result type before doing any of the appends to the temporary block. It is then converted to the type at the end.

What you are suggesting would mean that it would have to delay figuring out the return type of the join until it looked at what was being appended. e.g.:

cmd: 'play
tup: .headphones

>> join cmd tup
== play.headphones

So you would get a TUPLE! in such a case. But then, what if you did both, like this:

>> join 'play spread [.headphones /loud]
== play.headphones/loud

That's a PATH! whose first element is a TUPLE! and whose second element is a WORD!.

This is a by-product of the rule that paths may contain tuples, but not vice-versa.

Perhaps you can see why it's simpler to say that the decision on whether what you are ultimately making is a PATH! or a TUPLE! be made already.

As I say, I'm not necessarily opposed to there being operators with these semantics. People are welcome to try writing them (JOIN is usermode). There are just higher priorities at the moment.