Why APPEND of NULL fails, but VOID is a No-Op?

When the idea of NULL was first introduced, it was the only non-valued state...which one could be assured could not be put in a block. It was the result of conditionals that didn't take their branches, a failed PICK or SELECT, and it was the contents of an unset variable.

I sensed that there were two competing opportunities for using NULL with mechanical functions like APPEND.

  • The opportunity to have an "escape" out of a value bearing slot to say "no, I actually don't want to append a thing".

    >> append copy [<a> <b> <c>] (if 1 = 1 '[<d> <e>])
    == [<a> <b> <c> <d> <e>]
    
    >> append copy [<a> <b> <c>] (if 1 = 2 '[<d> <e>])
    == [<a> <b> <c>]
    
  • The opportunity to catch an error in intent when NULL is an accident.

    >> data: [<a> <b> <c>]
    >> block: [<d> <e>]
    
    >> append data third block
    ** Error: APPEND doesn't accept NULL as its value argument
    
    >> append data maybe third block
    == [<a> <b> <c>]
    

In the beginning I was excited about the coding styles afforded by the first choice.

But quietly accepting NULL loses the hot-potato benefit. If you say append data third block and there is no third element in the block, doesn't that seem like a good time to complain? Rebol code can pretty quickly get hard to read and debug, and wouldn't it be nice if the person who wrote that line could articulate that there may not be a third thing in the block by saying append data maybe third block?

Coming up with what MAYBE would return to "approve" the lack of an append ran up against a bit of a problem, because NULL was the only non-valued type. So for a time it was tried to make the default behavior of BLANK! to be to add nothing, and you need an /ONLY to override that. It seemed a missed opportunity for null to exploit its out-of-band status. But the thought was that "purposefully adding blanks wasn't all that common--certainly a lot less common than adding a block as-is, and that requires /ONLY!"

Hindsight 2022: In 2018 it was a long way from the tools and mechanics of generalized isotopes, which made as-is manipulation with APPEND, INSERT, etc. the universal default. It's funny to look back on it, and think about how difficult it was to try and make design decisions based on how often people appended blanks as-is or not. That kind of guesswork offers little grounding to those writing code, who should be able to be assured that if they pick an element out of one block and append it to another, that the default is to have moved the item intact.

1 Like