I understand your position.
And I do have good reasons to want it a certain way:
1. Storing empty strings really is an edge case.
2. Casting null values to a final data-type is easier and more precise/controllable then doing the same for zero-length strings (= less code and faster).
3. As an exception, I find using IsNULL( column, 'some-value' ) more elegant then using NullIf( column, '' ), followed by possibly even more processing (it is less direct so to speak).
An example is in order
Lets say we want to fill up a simple TABLE datatype that has two columns, both of type int.
Column 1 is the key and column 2 is a value which can be NULL.
We have as input two strings we have to split and each contains the same amount of elements.
declare @T TABLE
ID int not null primary key
, Value int
If the split function returns null for zero-length int values, a simple cast to the appropriate data type will do.
In fact, even implicit conversions would work out of the box here.
But what if we get zero-length string values instead?
Any straight up conversions of zero-length strings would result in a 0 value for datatype int and that is not what we want here.
In order to remedy this we first need to convert the item value to a null whenever it is a zero-length string using NullIf( value, '' ).
The reason to often want a table with typed columns instead of string columns can vary, but speed is one of the primary goals here.
1. Reuse of values in some complex batch or procedure
2. Application indexes and constraints
3. Data-type validation and one time conversion costs.
4. Collation control
5. Enriching of the worktable, possibly in multiple steps, before final output is returned.
I know many of the tests and examples surrounding splitting deal with splitting concatenated sting values. But in my experience dealing with int values and dates is actually more common. Regardless of the used data-types, treating them all the same way is preferable. This is why I lean to returning null values over zero-length strings. It works data-type agnostic, is the best fit for more types and incidentally those types are also the most common in my experience.
If you follow all this, you probably see why I consider a split function not really a string function.
It is rather more a table function that has string as input, but often the result does not end up being used as string values.
Practical applications go beyond splitting books into words simply for kicks :).