Redefining false, Introducing never and None for Optionals and Failures
Summary
This proposal suggests a redefinition of several core semantic constructs in Verse by deprecating the current overuse of false. Specifically, it replaces false as a type and a sentinel value in optional and failure contexts with clearer, distinct concepts: never as the bottom (uninhabited) type, none as the type of unset optionals, and None as the corresponding canonical value.
Motivation
In the current Verse language design, the literal false is overloaded to represent three semantically distinct concepts:
- A logic value (: logic = false).
- A sentinel for unset optionals (: ?false = false).
- The bottom type, used to represent unreachable or non-returning code : false = Err().
This overloading leads to decreased readability, difficulty in type reasoning, and ambiguity in failure handling and optional resolution.
V := array{false, option{true}, option{false}}
# V: []comparable for whatever reason
...
False := false
Optional: ?false = False #Not allowed because `False: logic`
By disentangling these responsibilities, we enhance the clarity of code, enforce type safety more effectively, and prepare the language for more expressive failure and result-handling mechanisms.
Design
Introduced Constructs
The proposal replaces and introduces the following constructs:
never := false          # `never` replaces `false` as the bottom type.
none := ?never          # `none` becomes the type of an unset optional.
None: none = false      # `None` becomes the value for an unset optional.
Optional and Failure Handling Semantics
New semantics for the ? operator allow it to propagate failure or indicate success depending on the value:
Fail()<decides><computes>: never = external{} #This function just fails
operator'?'(X: type{false})<decides><computes>: never = 		# type{false} is the singleton/literal type for `false` - not to be confused with the current bottom type. 
    Fail[] # Propagate failure
operator'?'(X: type{true})<computes>: void = 					# type{true} is the singleton/literal type for `true` - not to be confused with the current `void` alias. 
    external{} # Successful case
logic would look like this (which it basically is already):
logic := type{true} | type{false} 		# not to be confused with the current `true`(/void) and `false`(/bottom) types
Optional types are redefined with clearer semantics:
prefix'?'(t: type) := t | none 			# basically the same as `?t`
This ensures that unset optionals are typed with none rather than ambiguously typed as ?false and set to false.
Summary of Semantics
- neveris the new bottom type for unreachable code paths.
- none := ?neverserves as the canonical unset optional type.
- None: none = falseis the new canonical value for unset optionals.
- Fail[],- Err(), and- false?all return- never.
- true?returns- void.
- SomeLogicVar?returns- voidregardless of whether its value is- trueor- false, allowing concise logic gating.
Example: Optional Logic Value
MaybeLogic: ?logic = None  	#currently:  `MaybeLogic: ?logic = false`
MaybeLogic: ?logic = false 	#currently:  `MaybeLogic: ?logic = option{false}`
MaybeLogic: ?logic = true  	#currently:  `MaybeLogic: ?logic = option{true}`
# alternative to prefix'?'
MaybeLogic: logic | none = None  	
MaybeLogic: logic | none = false
MaybeLogic: logic | none = true 
This now unambiguously represents an optional logic value without overloading false.
Drawbacks
- Backward incompatibility: Any existing code using falseto represent failure or unset optionals will need to be updated.
Alternatives or Additional Considerations
- Retain the current overloaded use of false, accepting the semantic ambiguity and reduced expressiveness. Perhaps even embrace it with this and get rid oflogic
bool := ?void
True : ?void = option{void()}
False : ?false = false
- Also disambiguate true(simply get rid of it as alias forvoid)
Unresolved Questions
- I don’t have anything in particular, but let me know.
Future Possibilities
- Introduction of a resulttype built atopoption, enabling richer and more structured error handling, potentially with an additional result type argument forFail[FailureResult]
- Consider some minor improvements like