degory / ghul

compiler for the ghūl programming language
https://ghul.dev
GNU Affero General Public License v3.0
4 stars 0 forks source link

Add an unwrap operator #1128

Open degory opened 8 months ago

degory commented 8 months ago

Unwrap operator

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

Optional

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