godot icon indicating copy to clipboard operation
godot copied to clipboard

GDScript: Unexpected behavior of `match` on float variable with integral constants

Open resistor opened this issue 2 years ago • 3 comments
trafficstars

Godot version

4.0 stable

System information

macOS 13.2.1

Issue description

When performing a match on a float variable, the match will fail if the match arms are written as integral constants. That is, if the variable contains the value 5.0, a match arm of 5 will fail to match. This is non-obvious behavior for users coming from most other programming languages.

Steps to reproduce

See minimal GDScript snippet

Minimal reproduction project

func test():
	var a: float = 20.0
	match a:
		20:
			print("PASS")
		_:
			print("FAIL")

resistor avatar Mar 06 '23 03:03 resistor

This is intentional. match is more strict than ==. In 3.x the behavior is the same.

dalexeev avatar Mar 06 '23 05:03 dalexeev

So match's documentation needs to be improved: https://github.com/godotengine/godot-docs/blob/b8eb2d2a6ea4f3abb29ba79f6a99092abdfad95e/tutorials/scripting/gdscript/gdscript_basics.rst#match

It doesn't tell how exactly comparisons are done (e.g. if they're type-strict). Besides that I'm not sure if it's up to date (if / what has changed since it was written).

Also it says:

It's the equivalent of the switch statement found in many other languages

which may lead to confusion like in here (as these are not necessarily equivalent, rather similar).

kleonc avatar Mar 06 '23 11:03 kleonc

It seems that, with static typing information, there should at least be a warning for impossible match arms based on types.

resistor avatar Mar 07 '23 04:03 resistor

Hi, I noticed the same thing. Match statement and if/elif work differently with numbers, see code below. I think it is necessary to add an explanation to the documentation on match, if/elif and JSON (All number parsed from JSON became float).

var f : float = 8 var i : int = 2 var dictionary = {"some": 5, "random": i, "numbers" : f} var array = [5, i, f]

for n in array.size(): print("> for i in array: ", array[n], " type of: ", typeof(array[n])) if array[n] == 5: print("Is equal to 5") elif array[n] == 2: print("Is equal to 2") elif array[n] == 8: # <-- here we compare float 8 to 8, and it is ok print("Is equal to 8") else: print("The numbers are not equal!")

for n in dictionary: print("> For n dictionary: ", dictionary[n], " type of: ", typeof(dictionary[n])) match dictionary[n]: 5: print("> Wow it's matched to 5") 2: print("> Wow it's matched to 2") 8: print("> Wow it's matched to 8") # <-- here the same comparison will fail _: print("No match!") ` Output will be:

for i in array: 5 type of: 2 Is equal to 5 for i in array: 2 type of: 2 Is equal to 2 for i in array: 8 type of: 3 Is equal to 8 For n dictionary: 5 type of: 2 Wow it's matched to 5 For n dictionary: 2 type of: 2 Wow it's matched to 2 For n dictionary: 8 type of: 3 No match! `

Paladin-Caffeine avatar Apr 02 '23 06:04 Paladin-Caffeine