Why am i getting Invalid operands 'Callable' and 'float' in operator '<=' error?

4.4

I’m trying to setup procedural generation for my game, and I am clueless so I followed a tutorial and figured I could mess with it until it works, but I’m getting a Invalid operands ‘Callable’ and ‘float’ in operator ‘<=’ error and I have no clue what I’m doing, Anyway here’s my code.

Blockquote
extends Node

const GENERATION_BOUND_DISTANCE = 8
var player
var noise

func _ready() → void:
noise = FastNoiseLite.new()
player = $“…/Player”
generate_new_cubes_from_position(player.position)

func _process(_delta: float) → void:
pass

func get_color_from_noise(noise_value):
if noise_value <= -.4:
return Color(1,0,0,1)
elif noise_value <= -.2:
return Color(0,1,0,1)
elif noise_value <= 0:
return Color(0,0,1,1)
elif noise_value <= .2:
return Color(.5,.5,.5,1)
elif noise_value > .2:
return Color(.3,.8,.5,1)

func create_cube(position, color):
var box_size = Vector3(1,1,1)
var static_body = StaticBody3D.new()
var collision_shape_3d = CollisionShape3D.new()

collision_shape_3d.position = position
collision_shape_3d.shape = BoxShape3D.new()
collision_shape_3d.shape.size = box_size

var mesh = MeshInstance3D.new()
var boxmesh = BoxMesh.new()
boxmesh.size = box_size

var material = StandardMaterial3D.new()
material.albedo_color = color

boxmesh.material = material

mesh.set_mesh(boxmesh)
mesh.set_position(position)

static_body.add_child(mesh)
static_body.add_child(collision_shape_3d)

add_child(static_body)

func generate_new_cubes_from_position(player_position):
for x in range(GENERATION_BOUND_DISTANCE*2):
x += (player_position.x - GENERATION_BOUND_DISTANCE)
for z in range(GENERATION_BOUND_DISTANCE):
z += (player_position.x - GENERATION_BOUND_DISTANCE)
generate_cube_if_new(x,z)

func generate_cube_if_new(x,z):
create_cube(Vector3(x,0,z), get_color_from_noise(noise.get_noise_2d))

Could you please put your code between tick marks: ```

Blockquote is not very helpful in reading code.

Because get_noise_2d is a function, not a property. You should use it with parameters.

[...]
func get_color_from_noise(noise_value):
    if noise_value <= -.4:

[...]

    create_cube(Vector3(x,0,z), get_color_from_noise(noise.get_noise_2d))

Your call to get_color_from_noise() takes noise.get_noise_2d as an argument. You’re handing in the function itself, not calling it. You need to:

noise.get_noise_2d()

With the brackets. Otherwise you’re handing the function reference (as a Callable, a thing which can be called as a function…) into get_color_from_noise(), at which point you get:

    if [function reference] <= -0.4

Which throws the error you see.

What parameters should I use?

Looks like noise.get_noise_2d(x, z) according to:

thank you

var callable_function = is_under_ten    # Set to a "Callable"
var result            = is_under_ten(5) # Calls function.

func is_under_ten(val: int) -> bool:
    if val < 10:
        return true
    return false

func demonstrate_callable(val: int) -> bool:
    return callable_function.call(val)

In the above, result will get true, but callable_function is a function pointer you can hand around and call later. The demonstrate_callable() function invokes the function pointer as a function.

There’s all sorts of useful stuff you can do with this, but it does mean you have to be aware that referring to a function without trailing parens gives you a reference to the function rather than executing it.

In your code, you called get_color_from_noise() with a function pointer (that is, a Callable). Since get_color_from_noise() isn’t picky about its argument type, it accepts that function pointer, even though that’s not what you intended. get_color_from_noise() assumes it got a float and tests to see if it’s less than or equal to some values, but it didn’t get a float, it got a Callable, so you get the error about comparing a Callable to a float.

If you had instead done:

func get_color_from_noise(noise_value: float) -> Color:
    if noise_value <= -0.4:
        return Color(1, 0, 0, 1)
    [...]

You would have got an error when calling get_color_from_noise() because it was expecting float and you called it with Callable. When people talk about strong vs. weak types, this is what they mean; your version of the function is weakly typed, and doesn’t specify the types of value it accepts or returns. The version I wrote above is strongly typed because it’s explicit about what it accepts and returns.

NOTE! Weak typing can be good! Arguably the tradeoff is that weak typing provides more flexibility, and strong typing (sometimes, for certain types of bug) provides earlier bug detection.

Ok that makes sense the thing that was confusing me was the errors location so i was just copy pasting the video which yes i know does technically put me in tutorial hell but i think i am becoming a better dev so thank you hexgrid and everyone else who replied