`first` in `if` doesn't work without `true?`

Summary

Expression first doesn’t work in failable context (if condition clause) if you don’t have true? or any other failable expression in first after the generator or array

Please select what you are reporting on:

Verse

What Type of Bug are you experiencing?

Verse

Steps to Reproduce

Here’s an example from my project in the context of a custom Scene Graph component. You can see I am trying to find the first descendant entity with custom_tag. I am using this syntax because I know that there is supposed to be one entity with such tag

custom_component := class<final_super>(component):

    OnBeginSimulation<override>():void =
        if:
            PlayerPoint := first(FoundEntity : Entity.FindDescendantEntitiesWithTag(custom_tag)) . FoundEntity
        then:
            # doing stuff with `PlayerPoint`
        else:
            Print("No entity with custom_tag found!")

Here’s an example with an array and not a generator

MyArray := array{1, 2, 3, 4 ,5}
if:
    FirstElement := first(Element : MyArray). Element

Expected Result

Code compiles without a problem

Entity.FindDescendantEntitesWithTag(custom_tag) returns generator of all entites with custom_tag

If there is no entities found: first fails and “No entites with custom_tag found!” is printed

If there is at least one entity: first succeeds, it returns FoundEntity, saves it to the PlayerPoint and then Verse doing everything else with Playerpoint

Observed Result

Compiler throws an error (3503) “Expected an expression that can fail in the ‘if’ consition clause”

The error can be fixed by placing true? besides the generator in first like this:

custom_component := class<final_super>(component):

    OnBeginSimulation<override>():void =
        if:
            PlayerPoint := first(FoundEntity : Entity.FindDescendantEntitiesWithTag(custom_tag); true?) . FoundEntity
        then:
            # doing stuff with `PlayerPoint`
        else:
            Print("No entity with custom_tag found!")

with an array:

MyArray := array{1, 2, 3, 4 ,5}
if:
    FirstElement := first(Element : MyArray; true?). Element

Platform(s)

PC

Additional Notes

I don’t understand why there must be true? in first. This is a really strange syntax and there is no reason for it to be written like this

I know that first is usually used when you want to iterate through array/generator and get the first result that succeedes in condition. Here’s an example from the Book of Verse:

# Find the first player with a score above the threshold
FindTopScorer(Players:[]player, Threshold:int)<decides>:player =
    first (Player : Players; GetScore[Player] > Threshold):
        Player

But what if I just want to get the first result from a generator? Why I must have unfailable expression in first when it iterates through the first item in the generator? Finding the first value in itself can be considered a “success” especially if there is a possibility of getting no items in array/generator. true? doesn’t hold any meaning whatsoever in this context

What is a philosophy behind this if it is working as intended?

1 Like

Here’s another funny thing. THIS compiles without true?

if:
    CameraEntity1 := first(CameraPoint : Entity.FindDescendantEntitiesWithTag(camera_point_1)) . CameraPoint
    Camera1 := CameraEntity1.GetComponent[camera_component]

Like??? What???

1 Like

FORT-1147008 has been created and its status is ‘Unconfirmed’. This is now in a queue to be reproduced and confirmed.

Even if this is intended behavior, I would say we have odd error messages in the following cases right now.

Container := for. __:=0..1

first. __:Container # This first has the 'decides' effect, which is not allowed by its context. The 'decides' effect indicates that the first might fail, and so must occur in a failure context that will handle the failure. Some examples of failure contexts are the condition clause of an 'if', the left operand of 'or', or the clause of the 'logic' macro.  (3512)

# Ok. Let's do it in a <decides> context.
if. first. __:Container # Expected an expression that can fail in the 'if' condition clause  (3513)

The first error message says that first has the decides effect, so it can fail. The second one says that we require an expression that can fail inside the if condition. Would this not make the two error messages to contradict each other?