Invisibles are a novel and important concept. But they introduce a lot of wrinkles.
While there's a lot of technical complexity--I'm not terribly worried about that (technical problems have technical solutions). But usability and semantic problems need to be confronted.
Early on, I wanted to avoid situations where an invisible could be in a position where it might look like it was an assignment:
x: elide print "It's confusing when X gets [a]" append  'a
Since the ELIDE vanished, the result of the APPEND is what X gets. Confusing!
So at first, I figured it should be illegal to do that. But I later backed off on ruling it out when I thought about a vanishing BREAKPOINT:
x: breakpoint append  'a
Why shouldn't you be able to put a breakpoint wherever you want, I wondered? So it became legal.
Now I'm having serious second thoughts about the lenience. I don't know this tradeoff is ultimately worth it; it becomes very slippery when you are dealing with constructs that you aren't necessarily noticing are invisible. This problem feels like it gets worse in PARSE, if plain GROUP!s are invisible and people accidentally put them in slots where they think they are the value, but the value actually comes later:
>> uparse [1 <whoops>] [return collect [ keep integer! keep ("that was a number!") tag! ]] == [1 <whoops>]
The person thought they were keeping a string literal in their rule. But plain GROUP! is invisible, so they actually kept the rule after the string. (They actually wanted
keep @("that was a number!"))
Anyway, these situations are very much parallel. So I'm thinking that the error on invisibility for non-interstitials (e.g. assignment sources or argument slots) may make sense...to say that invisibility is something that can only happen in interstitial locations.
You can still get your breakpoint at odd positions, just introduce a GROUP! so it's not picked up:
x: (breakpoint append  'a)
Of course, a group might interfere with something like a COMPOSE, so you might need to use DO or be otherwise creative:
x: do [breakpoint append  'a]
We might lament the need to worry more about restructuring the code to accommodate the breakpoint in ways that could disrupt the code. But with dialecting, the appearance of the word BREAKPOINT even just in itself could have caused a disruption. It's the cost of doing business in this paradigm.
What might this imply for other cases, like do  ?
It may suggest that
do  can be invisible and vanish... just not have the result used in assignments. Which might be perfect; if you get frustrated with that, you can always consciously put a value in-between.
So instead of:
You could say:
x: (<default-value> thing-that-may-be-invisible)
There needs to be some way of specifically evaluating something and finding out if it was invisible...much like there needs to be a way of evaluating something and knowing if it threw, or raised an error, etc. Not everything fits cleanly as a "result value". But this shows there'd be at least one way of dealing with it besides that.