There is no nil-like value in the domain of any other type. If you hold a value which satisfies stringp then you know you have a string of zero or more characters and not some null reference.
Because the typing is dynamic, then if you have a situation in which you would like to either have a string, or a value indicating "there is no string here now", you can use nil for that. But replacing a string variable with nil changes the type; it is not a string reference that has been nulled out, but a string object previously stored in the variable has been replaced with the nil object.
Not in all type systems. Particularly, type systems which has union types may chose to simply create a separate type for NULL. There are also variants that have separate NULL types for different base types, which also invalidate your claim.
I think this is inaccurate. We are talking about computer science, which is important and a constraint around the general type theory. A type system is different than how you interact with it, so dispensing with language-specific symbolic representation further normalizes the discussion.
Fundamentally, a (computer science) type is a representation of binary, for the most part, data. That representation has to inhabit some part of bounded memory. When that memory is initialized (empty), it's some form of NULL, for a lack of another term. It exists for every type system in computer science.
> There are also variants that have separate NULL types for different base types, which also invalidate your claim
That's not the same thing. Different NULL types make sense for different sized discrete (fixed bounds) memory allocation. A unicode character has a fixed size allocation, while a string might be unbounded allocation (it grows in some fashion, as needed).
Edit: Kneejerk downvoting, classy.
What a type is, depends on what the runtime operates on. You can make a runtime that just grabs random bits of data as a type and say "that's an integer" but it's not a useful construct/example. A runtime keeps track of types in some way external to the data itself. So I'll disagree that an all-zeros is not the same as a null, because it's a common way to initialize the data that is identified with a type (like in a pointer table). It's not a 1:1 but it's common. There's not always a formalized name, but it (an uninitialized state) always exists as part of the type system (when not reusing existing memory allocation, which is an initialized state). Always.
And strings may only grow if strings are mutable, which AGAIN is extremely language dependent.
From a category theoretic point of view a type would be nothing more then the constraints on how terms may be composed.
Either you simply view types as as objects in some category or, perhaps a bit more interesting, as a functor. See f.ex http://noamz.org/papers/funts.pdf
Or rather it seems to be a common theme in language design to conflate these two notions of types, and we should probably stop doing that.
All types are functors in practice...which always has an element of initialization to ensure the type is defined in the memory.
My belief is that we should stop conflating data types (input and state modeling) and program types (domain modeling) so we can advance to more productive workflows. F.ex runtime reflection should never have been a thing, instead the focus should have been on macros and staged compilation, most meta programming can probably be better evaluated design time rather than run time.
I was trying to say that having a NULL value that inhabits every type seems silly as not every set of values has the NULL value. Considering that NULL can be represented as a special case of sum types, it seems even sillier to mandate such a value on all types.
Using both NULL and nullable seems very confusing as well.
General code, not things specifically testing differentiation between undefined and null.