Unwrapping nullable variables in Vala non-null mode

I have two questions about Vala’s non-null mode. I’m trying to work with it, but there seem to be some major limitations that make it really hard to work with in realistic code.

As far as I can tell from the Vala tutorial, the only ways to work with nullable values are with the ?? operator and by using the (!) cast. However, these are quite difficult to use in some cases that I’ll outline.

First, is there a way to safely check for a null value, and return if it’s null? I’m aware of the ?? operator to “unwrap” a value, but sometimes there’s no valid value to assign. Here’s my example, from the elementary Calendar app:

public ECal.Component? copy_ecal_component (ECal.Component? original) {
    if (original == null) {
        return null;
    }

    ECal.Component copy = original.clone ();
    E.Source source = original.get_data<E.Source> ("source");
    copy.set_data<E.Source> ("source", source);
    return copy;
}

This of course won’t work in non-null mode, because Vala doesn’t know that original isn’t null in the code block at the end. In this case, there’s really no way to continue the function if original is null. My question is: is there a way to unwrap a nullable variable and return if it fails?

In Swift, there’s a built-in way to deal with this case. It has a guard let operator that assigns a non-nullable variable to a value, and otherwise executes a block if the value would be null (which typically returns). I would look something like:

guard let unwrapped = original else {
    return nil
}
// Use unwrapped as a non-nullable variable from now on

As it is, I’m not sure how I could possibly implement something like this in Vala, where I execute a totally different behavior like returning if I encounter a null value.

Second, how do I call a method on a nullable variable? In another case, I have the existing code

private DateTime get_page () {
    Settings? state_settings = new GLib.Settings ("io.elementary.calendar.savedstate");
    string? month_page = null;
    if (state_settings != null) {
        month_page = state_settings.get_string ("month-page");
    }
}

I need to call a method of state_settings. However, since it’s nullable, Vala won’t let me, and I can’t figure out how to get a non-nullable version of it to call from. I can’t use the ?? operator, because there’s no reasonable non-null value for state_settings. I would prefer to avoid the (!) cast if possible, since it seems to me like dangerous casts shouldn’t be necessary for what I expect is a common occurrence (variables that have no feasible default value). Again, Swift has a way of working with this. It has a if let statement that only executes its body if a variable binding doesn’t evaluate to null. That’s basically equivalent to the if block we have in the current code, but I don’t know how to do that safely in non-null Vala.

Is there a way to implement either of these behaviors in Vala? We have existing ways that are completely safe, but I’m not sure how to convince the compiler that they are.

In Swift, there’s a built-in way to deal with this case. It has a guard let operator that assigns a non-nullable variable to a value, and otherwise executes a block if the value would be null (which typically returns). I would look something like:

I don’t speak Swift, but wouldn’t an if-block do the same thing?

if (original == null) {
   return null
}
var original_non_null = (!) original;

Which is a bit more clumsy compared to what Swift has, but should do the same thing.

Second, how do I call a method on a nullable variable? In another case, I have the existing code

You can put parenthesis around (!):

private DateTime get_page () {
    Settings? state_settings = new GLib.Settings ("io.elementary.calendar.savedstate");
    string? month_page = null;
    if (state_settings != null) {
        month_page = ((!) state_settings).get_string ("month-page");
    }
}

I would prefer to avoid the (!) cast if possible, since it seems to me like dangerous casts shouldn’t be necessary for what I expect is a common occurrence

Well, you checked before that state_settings isn’t null, so the cast is entirely safe (and Vala actually inserts an assert to make sure that values that are casted via(!) are actually not null. It’s not quite as comfy as if-let or similiar constructs, but it basically does the same thing.

Hope that helps :slight_smile:

Thanks! That all makes sense, and they’d certainly work. I suppose I was hoping there was something more built-in than peppering my code with (!) casts, but it works. I also didn’t know it added an assert, that makes me a lot more confident in its safety.

I suppose this would probably mean adding more language constructs, but it would be nice to not have to jump through the manual casting hoops for common cases. I suppose that’s why I mentioned Swift, which has pretty robust built-in support for optionals so you almost never have to force unwrap a variable.

Yup, something like what Swift has or Rust’s if-let would certainly be welcome additions to Vala. FWIW there’s https://gitlab.gnome.org/GNOME/vala/-/merge_requests/90 which at least makes accessing members of nullable objects more comfortable, maybe that’ll make it for Vala 0.52.

1 Like

That’s a nice addition, thanks for pointing it out.

Maybe a related issue
https://gitlab.gnome.org/GNOME/vala/-/issues/1058
But with the current speed vala develops, I doubte that it would make it any sooner in the current code base.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.