Please Consider creating a Gravity 2.0 with this fixed as a compile error, you will save a lot of debugging time to your users.
Please Consider creating a Gravity 2.0 with this fixed as a compile error, you will save a lot of debugging time to your users.
At best it could perform definite assignment analysis on variable declarations, but it can't go very far. In particular, it would do nothing for function return values.
As a result, the best it could give you is runtime errors when you e.g. access the value of a dynamic Maybe without checking for presence first. Without static analysis, this isn't hugely useful.
(For context: a language without null pretty much implies an Option type, which is mostly useless (or no better than null itself) without static typing. Once you're that far you're probably gonna want to get monads to make them workable and congratulations you're reinventing Haskell)
As an example, imagine an "updateDB" call that returns void. Totally could exist, and be useful, but all it does is a side effect; as a function you haven't expressed its functionality via its type. From a 'pure' perspective, it would be fair for the compiler to remove that call entirely, since you do nothing with the result (since there is no result). Instead you need a monad or something to express that side effect.
Obviously, many languages don't choose to express side effects within their type systems. It's not that means the language isn't useful, just that its type system isn't complete; you have things happening without a type attached to them (and in that way it's dynamically typed).
In the end, type systems (all of them, static as well as dynamic) are just a tradeoff between safety and practicality.
If you just mean that a program has certain properties (like performing IO) that are not expressed in its type, then I can see what you mean. But even in Haskell, some properties like “this function might fail to terminate or throw an exception” are not expressed in the type (although you can use monads for those things in languages where all functions terminate by default). There are no distinctions between a function that performs network accesses and one that does not, or functions that never return odd numbers, etc. There are infinitely many program properties that you can come up with which are not expressible in Haskell types.
Even dependently typed languages with very expressive type systems cannot capture all possible program properties due to logical incompleteness results.
I was using the term more informally. In fact it is the operational semantics of your hypothetical language that is not complete in the sense that you will have a hard time putting it into a form that allows you to do anything meaningful (e.g. proof absence of certain errors) with it.
Interestingly, you can define such a language with side effects (think ML), by actually pulling the state monad into your meta-level (for instance by turning your reduction relation into an instance of a state monad).
But cmoon it's not about FP. Checkout C# value types nullable<T> for example. C# 8 brings same principles to reference types (however being non-safe since you cannot break compatibility). Only good reasons to have (Java like) null is to either because you already did it and you cannot take away or you are in ecosystem where it's fundamentally in.
And to be precise it's not about null per se. Null can be just fine but it shouldn't be valid value for every type. You can solve it either by boxing (traditional option type) or some Type Scripty flat: Car | null ideology.
In some sense all languages with Java like null have some option types buuut they are missing regular non-nullable types.
And in languages that lack static types altogether, it's a moot point.
I really don't get it because in many years of programming, in practice, null pointers are one of the least of my worries.