Skip to content

RFC: Convenience syntax to unwrap Nullables (à la Swift if let) #15174

Closed
@nalimilan

Description

@nalimilan

I'd like to discuss the opportunity and possible implementations of a syntax similar to Swift's if let. The idea is to offer a compact syntax to check whether a Nullable is null, performing an action on its value if it isn't (with an optional fallback if it is).

This was mentioned recently on julia-users: https://groups.google.com/d/msg/julia-users/pgaw6VnBJ34/bBe2lJ1mAQAJ

I gave a try at writing a macro offering a similar feature in Julia, and as expected it can be made to work quite easily. There are a few issues to discuss, though:

  1. First, do people think it would be worth having in Base? I think making it easy to work with Nullable in a rigorous way is a major feature, and this seems to be a quite common opinion nowadays.
  2. @if let cannot be used because of parsing issues. That's not a big deal IMO, as I'm not a fan of that naming choice. I've retained @unwrap if, but we could find a better name (if is required to allow else).
  3. I've chosen to override the same variable binding using let x=get(x) (i.e. you access the value with the same name as the Nullable). I think this is clearer as there's no reason to need both variables in the same context, and it avoids prompting people to use artificially different names for the "same" thing.
  4. I think an alternative solution to this ad-hoc macro would be extend the do syntax to allow for an else part, which would be implemented by passing two functions to get (one for when a value is present, one for when it isn't). The advantage is that it could be useful in other places: for example to allow working efficiently with dicts, with code to update a value if found, and code returning a default value (?= "get or set" operator #2108).

So, here's the macro, and examples of how it can be used:

macro unwrap(ex)
    if !isa(ex, Expr) || ex.head != :if
        throw(ArgumentError("@unwrap expects an if or if...else block"))
    end

    x = esc(ex.args[1])

    if length(ex.args) == 3
        quote
            if !isnull($x)
                let $x = get($x)
                    $(esc(ex.args[2]))
                end
            else
                $(esc(ex.args[3]))
            end    
        end
    else
        quote
            if !isnull($x)
                let $x = get($x)
                    $(esc(ex.args[2]))
                end
            end
        end
    end
end

v = Nullable(1)

@unwrap if v
    res = v + 1
end

@unwrap if v
    res = v + 1
else
    res = 0
end

Cc: @johnmyleswhite

Metadata

Metadata

Assignees

No one assigned

    Labels

    missing dataBase.missing and related functionalityspeculativeWhether the change will be implemented is speculative

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions