I think many people are even more surprised by this:
x=$a # not split! It means the same thing as x="$a"
They were taught that you have to quote everything, which is a reasonable rule to follow, but it's not true.
---
I never wrote about this on the Oils blog (https://www.oilshell.org/ ), but the post would be titled:
Shell Has Context Sensitive Evaluation
Basically the two contexts you should think of are:
(1) EVAL WORD SEQUENCE
This occurs in 2 places in POSIX shell:
ls $x$y # simple command is a sequence of words
for i in $x$y; do echo $i; done # for loop
And 1 place in bash:
a=( $x$y ) # array literal
In these cases, the shell "wants" a sequence of strings, not a single one. So it does splitting.
---
(2) EVAL WORD TO STRING
But there are many other contexts where the shell does not "want" a sequence of strings.
It wants a SINGLE string. And conversely, it actually JOINS arrays of strings, rather than splitting.
Usually "$@" is an array / sequence of strings, while $@ or $* is a string, roughly speaking.
But the shell doesn't want sequences of strings in MANY cases, e.g.
a=$@ # I only want 1 string here, so I JOIN rather than splitting
echo hi > "$@" # redirect arg (not all shells agree though!)
case "$@" in ... esac # as you point out
So the bottom line is that variables aren't really strings OR arrays of strings. Whatever the shell wants, it converts it to.
And shells also DISAGREE on the specifics of those rules. POSIX shell has the array "$@", but arrays in general are not in POSIX.
---
And even worse, think about this case:
local x=$a
Does it behave like an assignment, which wants a single string?
Or does it behave like a simple command, which wants a sequence?
You can look at it both ways. The bottom line is that assignment builtins are special and they don't follow the normal rules of simple commands. Shells have differed, but POSIX decided on this awhile ago.
---
This is all of course mind numbing trivia that has no real reason for existing ... YSH fixes it, and it's now pure native C++, no more Python.
YSH Doesn't Require Quoting Everywhere - https://www.oilshell.org/blog/2021/04/simple-word-eval.html (Oil was renamed to YSH since this blog post was written)
Simple Word Evaluation in Unix Shell - https://www.oilshell.org/release/latest/doc/simple-word-eval...
In YSH you can tell just by looking it's a single string or an array.
ls $a # identical to ls "$a"
ls @myarray # splice an array
It never "molests" your variables. There's no auto-conversion, and you can upgrade to those rules with
shopt --set ysh:upgrade