New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
In 4.0 generic max() and min() global functions should work as expected for Vector* types #45320
Comments
One could make an argument that the current behavior is the expected behavior. The current behavior is very consistent across types because it always uses the inequality comparison operators. I doubt this should be changed, it's good as-is, but maybe additional documentation would be a good idea. |
To start with I don't know the possible use cases for either way. With a vector what max is could be defined however we want (The highest total components vs the highest length). I would be inclined to keep it as is unless there is no use case for the current usage and there is a great need to break consistency. Right now you can easily work around this by providing your own max\min_vector_length functions
|
Response:
Lol, now that's just trolling... But both these comments miss the whole point of what I said. And I'm sorry, whatever the underlying implementation reason for the behaviour is not a very good reason for 'why it's awkward'. As well, this doesn't 'break consistency' because it's not even available in 3.2. It's new in 4.0 (added a month ago), and it's awkward for this type. The fact is absolutely nobody in their right mind is going to expect that max(Vector2, Vector2) is going to return the vector who's x-coordinate is the largest. Zero, nobody. It's awkward default behavior, and probably just straight up wrong. Pick any vector math library in any language and I will guarantee that this is not the behavoir of a max function on two vectors. The point of bringing this up is to improve usability, nothing else. If you are aware of the underlying implementation then that's great for you but not intuitive for anyone else. And of course I can and will work around it. It's trivial, but that's totally missing the point. |
When did I say that I disagree with that statement? Additional documentation is a good idea. Your feelings were right on that documenting the behavior is a solution.
Except for people who need to take a set of vectors and sort them in a defined order. |
You're misinterpreting me. My point is that's not desired, and it's becoming too common to solve usability problems through 'documentation'. You don't want to use software that's unintuitive and have on documentation. The goal is to be MORE intuitive and MORE usable by default. That's a productivity win for everyone.
Sorting a set vectors has nothing to do with taking the max of two vectors, I'm sorry. The only reason these are currently coupled together is an implementation detail. And an implementation that relies on the Anyways, like i mentioned, this won't be the default behavoir in any other vector math library in any language. If you want to expose max() to Vectors in 4.0, it should do the right thing. |
What is the desired functionality and what is your use case? There is no defined 'right thing' as what constitutes a 'higher' vector it could be length or could be component based or it could be normalised most positive direction or even just highest y value. GLM\Kronos have less than functions that return a vector bool (So each component) and so does matlab it looks like. https://github.com/g-truc/glm/blob/master/glm/detail/func_vector_relational.inl Here is the less than implementation of a Vector2, isn't this the one invoked by < operations in max? This only compares x if x is not equal, otherwise it compares y.
|
Yep, lets define the current behaviour as expected behaviour. Now what? I'm asking you what you think is intuitive or expected exactly. For me, none of the vector max potential implementations are intuitive and you can define anything to be the expected behaviour (Including returning an array of bools).
By right thing, I'm also saying no more intuitive or generally preferred expected result either.
I don't think naming conventions matter...we can determine a Vector2\3 type and handle them specifically. The question is what do you think is intuitive and why? Even if we agree there is a problem you haven't given the replacement implementation. EDIT: There is a PR open right now that implements what I think you might be after (At least for vector2i): https://github.com/godotengine/godot/pull/45278/files in core/math/vector2.h |
I was just bitten by this in the latest godot beta (8). I expected the max(vector, vector) function to return a vector with component-wise max values. I think it is the most useful (and expected use case) that way. It allows for straightforwardness, in cases where otherwise I have to unwrap a vector, do component-wise max, and then rewrap it in another vector a simple use case would be finding a bounding box for possibly unordered values like so: var world_space_start = Vector3(...)
var world_space_end = Vector3(...)
# first I project to screen space
var screen_space_start = camera.unproject_position(world_space_start)
var screen_space_end = camera.unproject_position(world_space_end)
# then find min and max in screen space
var screen_space_min = min(screen_space_start, screen_space_end)
var screen_space_max = max(screen_space_start, screen_space_end)
# otherwise i would have to do something like this:
var screen_space_min = Vector2(min(screen_space_start.x, screen_space_end.x), min(screen_space_start.y, screen_space_end.y))
var screen_space_max = Vector2(max(screen_space_start.x, screen_space_end.x), max(screen_space_start.y, screen_space_end.y))
# which impacts on readability, and maybe also on performance hopefully this can be taken into consideration, although I am very sorry if this is being discussed elsewhere, I posted it here because it is the first place I found where its discussed |
I disagree, I think the I am not against a warning in the documentation though, as I understand it might be confusing. Something like: |
I disagree entirely, This is fundamentally an issue around |
This is not how min/max functions are implemented in most languages. If you want a component-wise operation, then you should be able call a specific method on the Vector2 itself, not a global operator that should behave more or less the same for all types. Something like
What you expect is not necessarily what other expect. The We discussed on rocketchat to disable this built-in function for vectors or arrays, as it's indeed confusing to newcomers. That would be ok to me as is min/max operators when you can use |
Absolutely correct, but please consider this also applies to yourself as well.
You are conflating the issue by relating |
Of course. My point was that, considering one behavior does not seem to be 100% consensual (which is fine), then we should make sure that such function are at least consistent. Either max/min should always return the highest/lowest of the two element (using the But a single function should not do both IMO. |
But in shading languages, which are very related, it is how it works.
I don't understand why this would be useful. I would understand when used with arrays (for example, for getting which would be first when alphabetically sorted). But for vectors, I see this as imposing ourselves a constraint that I can't come up with a use case for. And in that case, I agree with jordo, min/max shouldn't be related to sorting problems. if anything, I would say that Arrays shouldn't have a min/max implementation, although they could still use the < operator.
I think the opposite. having it do component-wise min/max makes it more consistent with what people expects. (at least, experienced people I think.). I understand that it would add complexity to the underlying system. but I think the example given above shows how it reduces complexity for user problems. |
Any standard mathematical operation performed on a vector should be performed component-wise. That is the conventional behavior, and the expected behavior for anybody who has ever used vector math to accomplish anything non-trivial, including myself. If I perform a comparison between two vectors, I expect to either receive a vector of bools, or, failing that, an error. If I compare two vectors and get a lexographic comparison as a result, I file a bug report, because That's Not How Vector Math Works. The min/max scenario is even worse, because not only does it produce a value you don't expect, it produces a value you don't expect in a type that you do. This is a bug that absolutely would have bitten me in the ass eventually, and frankly, I'm surprised it hasn't already, so props to jordo for that. To call this a documentation error is thoroughly asinine. |
I'll just remove those methods since there's no consensus on what they should do. |
I suppose even no implementation is better than the current one. |
So... I did a bit of research :)
Some like Irrlicht, OGRE or O3DE seemingly don't have min/max functions defined for vector types.
|
Oh no, somehow I overlooked/forgot the fact that this issue is about the global min/max functions. That changes some things. I think we should definitely expose component wise min/max functions for each vector type, but regarding the global ones I tend to agree that the current behavior is expected and probably the most consistent. I decided to keep the answer above, maybe it can still add some value to the discussion. |
Godot version:
4.0 latest
OS/device including version:
all OS/device
Issue description:
Notes this issue is 4.0 specific as 3.2.X doesn't expose these functions to any argument type and number of arguments
So I'm working on a project and doing a bunch of vector math in GDScript, and to my surprise I end up getting some really weird results with some computations. After the loss of a few hours trying to figure out what was going on it ended coming down to the addition of the generic global func
max(Variant...)
implemented in @reduz refactor to Variant operators here: f239780 (which I wholly appreciate as imo more refactoring and cleanup is greatly appreciated over new features).But at the core of my issue was some GDScript that roughly looked like this:
var c
in the above scenario evaluates to {0,0}. After discussion on IRC it was revealed that it's due to the implementation of max() in the generic case (or iterating the ...varg in a loop and comparing with Variant::OP_LESS for more than 2 arguments.
I just want to point out that this was really unexpected to me. GDScript compiler/parser/VM & editor will happily run that code and return {0,0}. When brought up on IRC, the solution is just to 'document' it. Document that
max()
andmin()
use the<
operator for arguments of the same type. I guess I sometimes feel the solution to just 'document the behaviour' is starting to be the solution to too many usability issues right now.Anyways, I could totally be in the wrong. Maybe I'm totally off base with what
max(Vector2, Vector2)
should return, as I discovered a few believe my posted GDScript sample was what should be expected.For myself, from a usability standpoint, I don't really want to read the docs on the
max()
function. If the function happily accepts two vectors, I expect the function to do vector math. Or, alternatively not be available at all (as is the case in 3.2.X), or perhaps give me a compiler/parser/runtime error.** Steps to reproduce **
Run this Gdscript in 4.0:
The text was updated successfully, but these errors were encountered: