Add a postfix ! operator that unwraps a System.Nullable`1[T], or any other value type that provides a value property, and returns its value
Requirements
[ ] accept a postfix ! operator in secondary expressions with the same precedence as ?
[ ] ! applied to a value of a reference type should pass the value unchanged
[ ] ! applied to a value of a value type should look for a value field or property and return it, if present
[ ] ! applied to a value type where the 'value' member is not a field or a property should result in an error
[ ] ! applied to a value of value type with no 'value' member should result in an error
[ ] presence of a value member in a value of reference type is ignored
Optional
[ ] Handle the input sequence !. specially and tokenize as operator ! followed my member access .
Details
! applied to a reference type should be the identity operator - i.e. it should just return its operand unchanged, at least if its value is non-null.
The common use cases for ! on value types already throw when the value is accessed (ghūl's MAYBE[T] and .NET System.Nullable`1[T]) and so implementing a has-value check for value types might be redundant, and the runtime will (eventually) throw a null reference exception if an unwrapped reference is then dereferenced, although the user may be surprised if the exception isn't thrown at the point of unwrapping. For we will rely on the unwrapped value or the runtime throwing an error in most cases if a none value is wrongly unwrapped, but we may choose to implement a check in future. In any case, client code should assume unwrapping a none value is invalid, and that it may either throw or give undefined results.
Given
some_thing[T](value: T) -> THING[T] => new THING[T](value);
none_thing[T]() -> THING[T] => new THING[T]();
struct THING[T] is
value: T;
has_value: bool;
// some
init(value: T) is
has_value = true;
self.value = value;
si
// none
init() is
si
to_string() -> string =>
if self? then
"some THING {value}"
else
"none THING"
fi;
si
The following is valid, although the attempt to unwrap the none value may fail at runtime:
let some = some_thing(42);
let none = none_thing`[int]();
write_line(some!);
write_line(none!); // will compile but allowed to fail at runtime
The way ghūl tokenizes operators means that ! immediately followed by a . will be treated as a single !. operator, rather than a ! operator followed by a member access. If unwrap immediately followed by member access would need an intervening space to disambiguate. Given that this is likely to be a common use-case, we might want to special case it and recognize the sequence !. as unwrap + member access rather than a custom operator
Unwrap operator
Add a postfix
!
operator that unwraps aSystem.Nullable`1[T]
, or any other value type that provides avalue
property, and returns its valueRequirements
!
operator in secondary expressions with the same precedence as?
!
applied to a value of a reference type should pass the value unchanged!
applied to a value of a value type should look for avalue
field or property and return it, if present!
applied to a value type where the 'value' member is not a field or a property should result in an error!
applied to a value of value type with no 'value' member should result in an errorvalue
member in a value of reference type is ignoredOptional
!.
specially and tokenize as operator!
followed my member access.
Details
!
applied to a reference type should be the identity operator - i.e. it should just return its operand unchanged, at least if its value is non-null.The common use cases for
!
on value types already throw when the value is accessed (ghūl'sMAYBE[T]
and .NETSystem.Nullable`1[T]
) and so implementing a has-value check for value types might be redundant, and the runtime will (eventually) throw a null reference exception if an unwrapped reference is then dereferenced, although the user may be surprised if the exception isn't thrown at the point of unwrapping. For we will rely on the unwrapped value or the runtime throwing an error in most cases if a none value is wrongly unwrapped, but we may choose to implement a check in future. In any case, client code should assume unwrapping a none value is invalid, and that it may either throw or give undefined results.Given
The following is valid, although the attempt to unwrap the
none
value may fail at runtime:The way ghūl tokenizes operators means that
!
immediately followed by a.
will be treated as a single!.
operator, rather than a!
operator followed by a member access. If unwrap immediately followed by member access would need an intervening space to disambiguate. Given that this is likely to be a common use-case, we might want to special case it and recognize the sequence!.
as unwrap + member access rather than a custom operator