On Monday, 21 October 2013 at 10:33:01 UTC, Regan Heath wrote:
null strings are no different to null class references, they're
not a special case.
True. That's an implementation detail which has no meaning for
business logic. When implementation deviates from business logic,
one ends up fixing the implementation details everywhere in order
to implement business logic. That's why string.IsNullOrEmpty is
used.
People seem to have this odd idea that null is somehow an
invalid state for a string /reference/ (c# strings are
reference types), it's not.
That's the very problem: null and empty are valid states and must
be treated equally as "no data", but they can't for purely
technical reasons.
People also seem to elevate empty strings to some sort of
special status, that's like saying 0 has some special status
for int - it doesn't it's just one of a number of possible
values.
In fact, int having no null like state is a "problem" causing
solutions like boxing to elevate the value type to a reference
in order to allow a null state for int.
You want to check ints for null everywhere too?
Yet, in D we've decided to inconsistently remove that
functionality from string for no gain. If string could not
actually be null then we'd gain something from the limitation,
instead we lose functionality and gain nothing - you still have
to check your strings for null in D.
Huh? Null slices work just like empty ones - that's why this
topic was started in the first place. One doesn't have to check
slices for nulls, only for length.
If you want clear nullable semantics, you have Nullable, it works
for everything, including strings and ints. You would want this
feature only in rare cases, so it doesn't make sense to make it
default, or it will be a nuisance.
both of them are just "no data", so you end up typing
if(string.IsNullOrEmpty(mystr)) every time everywhere.
I only have to code like this when I use 3rd party code which
has conflated empty and null. In my code when it's null it
means not specified, and empty is just one type of value - for
which I do no special handling.
Equivalence between null and empty is a business logic's
requirement, that's why it's done.
And, yeah, only one small feature in this big mess ever needs
to differentiate between null and empty.
Untrue, null allows many alternate and IMO more direct/obvious
designs.
The need for those designs is rare and trivially implementable
for all value types.
I found this one case trivially implementable, but nulls still
plague all remaining code.
Which one case? The readline() one below?
No, it was an authentication system in third-party code for one
special case. I also had to specify this null value in app.config
- guess how, explicitly specify, not substitute missing parameter
with a default.
Another possibility for readline is to return a tuple
{bool eof, string line(non-null)} - this way you have easy check
for eof and don't have to check for null when you don't need it.
I use this all the time:
http://msdn.microsoft.com/en-us/library/system.io.streamreader.readline.aspx
It has never caused me any issues. It explicitly states that
null is a possible output, and so I check for it - doing
anything less is simply bad programming.
It works if you read one line per loop cycle, but if you read
several lines and assume they're not null (some multiline data
format),
There is your problem, never "assume" - the documentation is
very clear on the issue.
you're screwed or your code becomes littered with null checks,
but who accounts for all alternative scenarios from the start?
Me, and IMO any competent programmer. It is misguided to think
you can ignore valid states, null is a valid state in C, C++,
C#, and D.. You should be thinking about and handling it.
Here null is a valid state for readline, not for the caller: if
the caller parses a multiline data format, unexpected end of file
is an invalid state.
And what do you gain by littering your code with those null
checks? Just making runtime happy and adding noise to the code?
You could use that time to improve the code or add features or
even relax. It's exactly nullable strings, which gain you only a
time waste.
You don't have to check for it on every access to the variable,
but you do need to check for it once where the variable is
assigned, or passed (in private functions you can skip this).
From that point onward you can assume non-null, valid, job done.
You just said "never assume". The assumption may fail, because
the string type is still nullable, compiler doesn't save you
here, this sucks. And in order to check for everything everywhere
on a level near that of the compiler, you must be not just
competent, but perfect.
I believe there's no problem domain, which would like to
differentiate between null and empty string instead of
treating them as "no data".
null means not specified, non existent, was not there.
empty means, present but set to empty/blank.
Databases have this distinction for a reason.
Oracle makes no distinction between null and empty string. For a
reason?
A database is an implementation detail of a data storage, it
doesn't implement business logic, it only provides features,
which can be used with more or less success to implement business
logic. Ever heard of advantages of OO databases over relational
ones? That's an illustration of technical details, which don't
precisely map to business logic.
If you get input from a user a field called "foo" may be:
- not specified
- specified
and if specified, may be:
- empty
- not empty
If the user doesn't fill a text box, it's both empty and not
specified - there's just no difference. And it doesn't matter how
you store it in the database - as null or as empty string - both
are presented in the same way. Heck, we use these optional text
boxes everywhere - can you tell if their content is empty or not
specified?
And what if the value is required? Would you accept an empty
value? And if your database treats empty string as not null,
would you allow to register a user with an empty login name? And
how to express this constraint in the database? In SQL "not null"
means "required value", but it's not equivalent to the business
logic'a notion of a required value. I wouldn't be surprised if
Oracle did that in order to reject empty strings in not null
fields.
Let's consider a process of specifying user's data. What text
fields do we have?
1. Login. No difference between null and empty - both invalid -
"no data", must enter something.
2. First name. No difference between null and empty - both are
"no data" and are presented as empty text box.
3. Middle name. ditto.
4. Last name. ditto.
5. Country. ditto.
6. State. ditto.
7. City. ditto.
8. Address. ditto.
9. Building. ditto.
10. Flat. ditto.
11. Zip code. ditto.
12. Phone. ditto.
13. Fax. ditto.
14. E-mail. ditto.
15. Site. ditto.
16. Passport number. ditto.
17. Birth place. ditto.
18. Comment. Hell! Comment!
See? Not a single field in the list requires distinction between
null and empty. And slices don't differentiate between them. Just
as planned.
If we have null, lets use it, if we want to remove null the
lets remove it, but can we get out of this horrid middle ground
please.
*sigh* people just don't buy the KISS principle...