godotengine / godot-proposals

Godot Improvement Proposals (GIPs)
MIT License
1.07k stars 69 forks source link

Add `INT64_MAX`, `INT64_MIN`, etc. constants #2411

Open rainlizard opened 3 years ago

rainlizard commented 3 years ago

Describe the project you are working on

Learning gdscript.

Describe the problem or limitation you are having in your project

I was looking up how to use intersect_point() (though this applies to everything that uses collision_mask) and I repeatedly came across this random-looking string of numbers "2147483647" in other people's code in a bunch of different threads on https://godotengine.org/qa/ and discord, which left me wondering what it could mean. You might be thinking "well you're not supposed to be able to know what the collision_mask number means", however it appears to be a very common use case to want to have all collision layers checked and then just loop through the returned dictionary.

Describe the feature / enhancement and how it helps to overcome the problem or limitation

You will not memorize it, so a constant would save people from copy-pasting this number so often.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

Add the constant for ALL_COLLISION_LAYERS. Though I think 2147483647 has a lot of use cases being the largest 32 bit integer so you could also call it INT_MAX.

If this enhancement will not be used often, can it be worked around with a few lines of script?

It will be used often. It is for the benefit of new users to bring attention to what 2147483647 means - something other than a commonly occurring random set of numbers.

Is there a reason why this should be core and not an add-on in the asset library?

If it's not core then it defeats the purpose which is to help new users. It won't affect me all that much because I now know what it means and I don't mind copy-pasting - but is that the intended engine's philosophy, copy and paste code instead of memorize it?

I only found one other person requesting this in 2019, so I understand if no one cares.

mrjustaguy commented 3 years ago

It'd be better to add a var type that is a binary set, that can be turned into an int and back, for things like the cull masks, collision layers etc... Or allow for PoolByteArray to be viewed as a series of 1s and 0s, along the hex, that way you could use var2bytes and get binary output (as var2bytes returns PoolByteArray)

The constant you want on the other hand, is kind of pointless, as you could again ask for binary 11111111 to int as a constant and some such, which really doesn't make too much sense, and what needs to get worked on is dec<->bin conversion being built-in and made obvious, much like hex->dec is.

dalexeev commented 3 years ago

Why 2147483647 and not 4294967295?

print((1 << 31) - 1) # 2147483647
print((1 << 32) - 1) # 4294967295
print((1 << 16) - 1) # 65535
print((1 << 8) - 1)  # 255

Yes, it might be worth adding the following constants:

const UINT8_MAX  = (1 << 8)  - 1 # 255
const UINT16_MAX = (1 << 16) - 1 # 65535
const UINT32_MAX = (1 << 32) - 1 # 4294967295

const INT8_MIN  = -(1 << 7)  # -128
const INT16_MIN = -(1 << 15) # -32768
const INT32_MIN = -(1 << 31) # -2147483648
const INT64_MIN = -(1 << 63) # -9223372036854775808

const INT8_MAX  = (1 << 7)  - 1 # 127
const INT16_MAX = (1 << 15) - 1 # 32767
const INT32_MAX = (1 << 31) - 1 # 2147483647
const INT64_MAX = (1 << 63) - 1 # 9223372036854775807
aaronfranke commented 3 years ago

Godot's Variant type uses int64_t for integers, so the limit is 9223372036854775807 for storing ints in GDScript, so this constant would be misleading if it was 2147483647. The reason that 2147483647 comes up is because some parts of the engine use 32-bit integers. However, if bigger numbers are needed somewhere, then really we should just upgrade those parts to 64-bit. For collision layers, I don't know if there is use a case for needing more than 31 of them.

dalexeev commented 3 years ago

Why 2147483647 and not 4294967295?

The reason that 2147483647 comes up is because some parts of the engine use 32-bit integers

int collision_layer

The physics layers this area is in. Collidable objects can exist in any of 32 different layers. <...>

In theory, this should be unsigned, i.e. uint32_t, not int32_t.

Godot's Variant type uses int64_t for integers, so the limit is 9223372036854775807 for storing ints in GDScript, so this constant would be misleading if it was 2147483647.

Therefore, in my comment it is called INT32_MAX, not INT_MAX.

rainlizard commented 3 years ago

The docs also mention 2147483647 without any explanation as to what it does: https://docs.godotengine.org/en/stable/classes/class_physicsdirectspacestate.html https://docs.godotengine.org/en/stable/classes/class_physics2ddirectspacestate.html https://docs.godotengine.org/en/stable/classes/class_physicsshapequeryparameters.html https://docs.godotengine.org/en/stable/classes/class_physics2dshapequeryparameters.html

4294967295 comes up twice, it explains what it does for randi() which is good, but it's funny to see it on light_cull_mask, isn't that inconsistent with collision layers?: https://docs.godotengine.org/en/stable/classes/class_light.html?highlight=4294967295

cgbeutler commented 3 years ago

Having INT_MIN and INT_MAX as aliases for INT64_MIN and INT64_MAX would probly help newbies. A few of them kids in #help channels may not get the whole 64-bit thing, since the rest of the engine kinda hides that.

Calinou commented 3 years ago

Having INT_MIN and INT_MAX as aliases for INT64_MIN and INT64_MAX would probly help newbies. A few of them kids in #help channels may not get the whole 64-bit thing, since the rest of the engine kinda hides that.

I think explicit is better than implicit here. Implicit (and variable) int size is considered to be one of C++'s worst mistakes, so I wouldn't replicate it in GDScript.

Also, these constants are intended for fairly advanced users in the first place. It's very unlikely you'll need one of those if you are just starting out with Godot.

cgbeutler commented 3 years ago

I wasn't suggesting we use C++'s size thang. The main issue with that was that int could change, depending on the compiler or compiler settings. Having aliases in and of itself was not the issue. Course, I'll be happy to get whatever I can. At the very least, defining my int helper class will be easier.

akien-mga commented 1 year ago

As discussed in https://github.com/godotengine/godot/pull/48190, these can be added directly to the @GlobalScope instead of adding them to GDScript specifically. Then all language bindings can access it.

Going further, I think there could be value in adding a proper Math singleton that includes those constants + existing @GlobalScope math functions (abs, sin, etc.). Though that warrants more discussion and is outside the scope of this proposal.

raldone01 commented 1 year ago

Float.EPSILON would be useful too.

Calinou commented 1 year ago

Float.EPSILON would be useful too.

The correct epsilon to use depends on how large the floating-point number is (away from 0.0): https://floating-point-gui.de/

Therefore, there is no singular epsilon value you can use as a basis.

raldone01 commented 1 year ago

I was looking for this epsilon: https://en.cppreference.com/w/cpp/types/numeric_limits/epsilon

I come from a cpp background.

aaronfranke commented 1 year ago

@raldone01 We could expose epsilon to GDScript, it's already exposed in C#.

adamscoble commented 8 months ago

Hi all, in lieu of this not existing yet, could anyone help me with the bitshift operation to get the min/max float values? Haha. I can't figure out the float equivalent of the INT64_MAX example above.

AThousandShips commented 8 months ago

You can't use shifting to reach float values

adamscoble commented 8 months ago

You can't use shifting to reach float values

Ah, that'd be why! So the best alternative I can find is const FLOAT_MAX := 1.79769e308, is that right?

AThousandShips commented 8 months ago

I think so or there abouts

Zshandi commented 4 months ago

Having INT_MIN and INT_MAX as aliases for INT64_MIN and INT64_MAX would probly help newbies. A few of them kids in #help channels may not get the whole 64-bit thing, since the rest of the engine kinda hides that.

I totally agree, you really need to do a bit of research to find out that it uses 64-bit, not to mention that I think this wasn't the case in some older Godot versions, so this also helps with writing code that simply needs the highest possible value, in case that would ever change again in the future (though I don't think that's likely anytime soon 🙂).

Also, as @adamscoble pointed out, we should also have min and max values for floating point values. These could also follow the same pattern for float vs double precision equivalent in non-gdscript languages, which I believe should just be labelled as 32 vs 64 bit maximums, since that unambiguates it from the gdscript float which has 64-bit precision 😅

FLOAT_MIN
FLOAT_MAX
FLOAT_32_MIN
FLOAT_32_MAX
FLOAT_64_MIN
FLOAT_64_MAX
aaronfranke commented 4 months ago

The min and max float values are not very useful for practical purposes. Float steps get more coarse as the magnitude increases, meaning that the practical limit for useful calculations in a video game is far below the actual max float. I don't think it's worth including them in the engine when you can do the same with a constant in your project.

A similar argument could be made for the integer constants about just using constants in your project, although those are practically useful so make more sense to include as a part of the engine than the float max.

Another consideration is that if we have a constant for the minimum float, would that just be the negative of the max float? Some users instead want the minimum positive value, but again this value is not very useful as the min positive value is denormalized. The minimum normalized number is more useful, but still arguably not very useful, and since there are so many choices it may be better to let users define what they need in their projects. A value like Godot's CMP_EPSILON / UNIT_EPSILON would be even more useful to expose, and I think we should, but first we should change its value as it is currently 1e-5 or 1e-3 while it should be 1e-6. See https://github.com/godotengine/godot/issues/37241 and https://github.com/godotengine/godot/blob/master/core/math/math_defs.h#L34

geekley commented 3 months ago

It's great to add float constants too, but PLEASE use explicit specific-purpose names instead of an ambiguous "epsilon".

I made a gist with constants for GDScript, which should cover all cases. I've defined the values in terms of their calculations, as parsing of float literals in GDScript is not reliable for these values (it seems some of them can't be represented by a literal directly!). There's also FLOAT_* constants, which point to either their FLOAT32_* or FLOAT64_* equivalents, according to which one is used in vectors (64 bits when compiled with precision=double).

I would suggest using these float constants which are "notable values" (see Wikipedia on Float64, Float32, Float16). So this way people won't be mislead with an "epsilon" value that may confuse them about how floating point works.

The names I'm suggesting are very explicit and completely unambiguous, as per the pattern:

I'm using "negative limit" instead of "min" (to distinguish from a "close to zero" meaning) or even "max negative" (which could imply it's negation is "max positive", but in reality its positive overflows). For the positive constant, I'm using simply "max" as one could want e.g. -INT64_MAX, which is (arguably) not as weird as writing -INT64_MAX_POSITIVE IMO.

If you decide to implement this, you could make these constants global. Another option for GDScript is to put them inside float and int, which is where I'd expect to find them.