Justifiable Asymmetry: TO on BLOCK!?

I've previously pitched the following stakes in the ground for TO conversions:

  1. A TO conversion won't run arbitrary code that you pass to it. It won't even GET any variables, much less evaluate.
  2. Every TO conversion targeting a series type performs a new allocation
  3. A TO conversion of a value to its own datatype will do the same thing as COPY

These rules are mechanical, and aren't saying much about what TO means "semantically". It feels like we should be able to say that TO TEXT! 10 is "10" and TO INTEGER! "10" is 10. But it gets a bit more vague from there.

As additional guidance, I've also proposed a rule for APPEND and its bretheren:

"If the type of the value being appended doesn't match the type of what you are appending to, it will act as equivalently as if it had been converted with TO into the target type first."

So whatever append copy [a b c] 'x/y/z does, it would be the same as append copy [a b c] to block! 'x/y/z.

Should there be symmetry?

The historical ergonomics of splicing by default are not always good:

>> block: copy [a b c]
>> path: 'd/e
>> append block path
== [a b c d e]

We know that [a b c d/e] would be more useful in almost all cases. If you have a PATH! in your hand, the path-ness is likely relevant to what you want to do.

I've proposed weird rules like "only splice if the types match", but that can be a bit awkward:

>> group: copy quote (a b c)
>> append group collect [keep 'd | keep [e f]]
== (a b c [d e f])

Due to their nature (and special logographic [o] status), blocks really are just a good generic carrier for material. Hence their BLOCK!-ness quite well not be that important. So here, I'd think that having to say append group as group! collect [...] is kind of annoying.

So I suggested "only splice blocks" might be a more predictable-feeling rule. This way, you're not worrying about the combinatorics of what you're inserting and what you're inserting into.

Merging that with the rules above would give you some asymmetry, however:

>> to block! 'a/b/c
== [a/b/c]

>> to path! [a b c]

>> to block! quote (a b c)
[(a b c)]

>> to group! [a b c]
(a b c)

TO BLOCK! of any non-block array would just put it into a block, while TO PATH! or TO GROUP! of a block array would act more like COPY AS PATH! and COPY AS GROUP!.

But looking a bit closer, it seems that maybe the rule should really just apply to not breaking up paths.

So what if the difference is just PATH!s?

>> to block! 'a/b/c
== [a/b/c] ;-- 1 new element when APPENDed to BLOCK!

>> to group! 'a/b/c
== (a/b/c) ;-- 1 new element when APPENDed to GROUP!

>> to block! quote (a b c)
== [a b c] ;-- 3 new elements when APPENDed to BLOCK! (splice)

>> to group! [a b c]
== (a b c) ;-- 3 new elements when APPENDed to GROUP! (splice)

>> to path! [a b c]
== a/b/c ;-- 3 new elements when APPENDed to PATH! (splice)

>> to path! quote (a b c)
== a/b/c ;-- 3 new elements when APPENDed to PATH! (splice)

This puts BLOCK! and GROUP! into the same category of "things that splice by default". They certainly -look- more similar to each other than either looks to path due to the elements being not glued together...perhaps "spaces mean splices"?

It also reduces the likelihood of creating 1-element paths via TO (you'd only get that for 1-element GROUP!s and BLOCK!s).

It's an asymmetry, but feels sort of explainable. Note that the AS operators are fully symmetric, and you can say copy as block! 'a/b/c and get [a b c]. So this is really just about making the TO and APPEND/INSERT/CHANGE matrix more useful.

So...are people on board with this?

Seems plausable. The thing the path is representing is important, and splitting up the path, although that can have its uses, is commonly not wanted either.

As with most cases, proof and pudding.

1 Like

Something I still think is a good idea:

Something I no longer think is a good idea:

I think my proposal from a few years ago is more on track

When the semantics of TO were first being debated, I suggested that if v1 is a value of type1, then the following is either true or it fails:

 v2 = to type2 to type1 (v2: to type2 v1)

The premise here would be that a TO conversion preserves a value well enough to convert it back, in a process that reaches steady state after one conversion.

Not all types can represent all other types. So if there's to integer! some-block you can't put every possible block in an integer somehow. That's where the errors come in.


>> once: to block! "abc"
== [#"a" #"b" #c]
>> to text! once
== "abc"  ; reached steady state after one round trip conversion

>> once: [#"a" #"b" _ "c"]
>> temp: to text! once
== "abc"
>> twice: to block! temp
== [#"a" #"b" #"c"]  
>> to text! twice
== "abc"  ; reached steady state after two round trip conversions

Being able to turn TEXT! into a BLOCK! of CHAR! is an important facet of UTF-8 everywhere, as complex string algorithms can benefit from the fixed-cell-size access. So this isn't a frivolous example.

Also, trying to shoehorn things into the other idea meant to block! 'a/b/c gave back [a/b/c]. Now that PATH! is immutable, this isn't very good. Also, we now have BLOCKIFY and ENBLOCK (and GROUPIFY and ENGROUP).

So I think this idea of information-preserving-and-settling or error is probably the right one. The splicing rule for blocks comes specifically from ANY-ARRAY! now, and ANY-PATH! is not an ANY-ARRAY! so that takes care of that. Hence there's no TO conversions done by APPEND.

1 Like

So ENBLOCK was conceived as the idea of making it easy to put something in a block:

>> value: second [a (10 + 20) b]
>> enblock value
== [(10 + 20)]

>> enblock 300 + 4
== [304]

I don't know if it's a terrible idea to have such a function, but I noticed that with GET-BLOCK! being committed to REDUCE behavior, there's another option that generally looks clearer:

>> value: second [a (10 + 20) b]
>> :[value]
== [(10 + 20)]

>> :[300 + 4]
== [304]

The special case of what to do about ENBLOCK of NULL was to give an empty block:

>> enblock null
== []

I'm still on the fence about vaporization in blocks due to potential problems with positional usages...though UNPACK changes the game a bit on that.

Anyway, I just want to mention this because I went to reach for ENBLOCK and realized that GET-BLOCK! was a lot clearer to look at in the case I was writing. (!)