Using unset vs. setting a variable to empty

I'm currently writing a bash testing framework, where in a test function, both standard bash tests ([[) as well as predefined matchers can be used. Matchers are wrappers to '[[' and besides returning a return code, set some meaningful message saying what was expected.

Example:

string_equals() {
    if [[ ! $1 = $2 ]]; then
            error_message="Expected '$1' to be '$2'."

            return 1
    fi
}

So, when a matcher is used, and it fails, only then an error_message is set.

Now, at some point later, I test whether the tests succeeded. If it succeeded, I print the expectation in green, if it failed in red.

Furthermore, there may be an error_message set, so I test if a message exists, print it, and then unset it (because the following test may not set an error_message):

if [[ $error_message ]]; then
    printf '%s\n' "$error_message"

    unset -v error_message
fi

Now my question is, if it is better to unset the variable, or to just set it to '', like

error_message=''

Which one is better? Does it actually make a difference? Or maybe should I have an additional flag indicating that the message was set?


Mostly you don't see a difference, unless you are using set -u:

/home/user1> var=""
/home/user1> echo $var

/home/user1> set -u
/home/user1> echo $var

/home/user1> unset var
/home/user1> echo $var
-bash: var: unbound variable

So really, it depends on how you are going to test the variable.

I will add that my preferred way of testing if it is set is:

[[ -n $var ]]  # True if the length of $var is non-zero

or

[[ -z $var ]]  # True if zero length

As has been said, using unset is different with arrays as well

$ foo=(4 5 6)

$ foo[2]=

$ echo ${#foo[*]}
3

$ unset foo[2]

$ echo ${#foo[*]}
2

So, by unset'ting the array index 2, you essentially remove that element in the array and decrement the array size (?).

I made my own test..

foo=(5 6 8)
echo ${#foo[*]}
unset foo
echo ${#foo[*]}

Which results in..

3
0

So just to clarify that unset'ting the entire array will in fact remove it entirely.