Has anyone successfully written a failable function in Verse?

I copy and pasted the example code from the functions doc:

Find(X:[]int, F(:int)<decides>:void)<decides>:int =
    for (Y:X, F(Y)):
        return Y
    false?

This doesn’t compile because it complains about returning logic. I’ve run into the same issue in my code, I don’t know what to return or write to make a failable function actually compile. My function returns a user defined type.

2 Likes

FWIW, I was able to restructure my failable function to use logical comparisons and return void instead of returning a value, but I would still be interested in the right way to write a failable function that returns an actual typed value.

Thanks!

  1. You can’t return explicitly from a failable context. So that stops you from using return Y
  2. false? always fails, without returning any value. However, right now the compiler still wants to see the function return a value of its return type (int) since it can’t infer that anything after false? won’t execute.

You could wrap this in an option:

Find(X:[]int, F(:int)<transacts><decides>:void)<transacts><decides>:int =
    var RetInt:?int = false 
    for (Y:X, F[Y], not RetInt?):
        set RetInt = option{Y}
    RetInt?
4 Likes

That makes sense, thanks! Just an FYI that sample was taken from the documentation, so you may want to update it since it doesn’t compile. Appreciate the wrapping suggestion!

Do you know the reason for not being able to return from a failure context ?

I was thinking about rolling back erasing the value, but the return is the last statement so it cannot be it, is it ?

That’s an interesting question that got me thinking as well. I’m used to return and throws in a failable Swift context.

If that’s not the case then it means that when a function has decides specifier in verse, that it requires to provide the entire “failable context” with a matching return type at all its exit paths, hence no explicit return is permitted.

Please correct me if I’m wrong.

You might understand it better than me, because it doesn’t make sense to me still. :sweat_smile:

with a matching return type at all its exit paths

An explicit return is still a return, right ?

For why return (and break) cannot occur in a failure context: first, some background. Eventually, Verse will support lenient evaluation - where statements can effectively be reordered if it doesn’t affect the semantics of a program. For example,

X:int
Y := X
X = 1

would result in X and Y both having the value one. However, this means failure, in the decides sense, can be reordered as well. If return and break were allowed in such contexts, the effect of the program would observably change due to reordering. For example, in

X:int
Y := X
return
X = 1

should the program return or fail? Instead of making a choice, Verse disallows combining these effects (continuation-style return and break with decides effect).

4 Likes

Thank you for this detailled answer, as I see it, it’s obvious that the program should return and not fail since nobody would declare variables this way.

But I’m pretty sure this is a simple example and this can get way more complex, I’m glad to know why this is hapenning though, even though if it looks to me that the lenient thing is less important than being able to return in a <decides> function. (but I might be wrong)