Skip to content
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

Enforce Plane invariants via private fields & setters #994

Open
chitoyuu opened this issue Dec 7, 2022 · 2 comments
Open

Enforce Plane invariants via private fields & setters #994

chitoyuu opened this issue Dec 7, 2022 · 2 comments
Labels
breaking-change Issues and PRs that are breaking to fix/merge. c: core Component: core (mod core_types, object, log, init, ...) feature Adds functionality to the library

Comments

@chitoyuu
Copy link
Contributor

chitoyuu commented Dec 7, 2022

Created during survey of commented code (#377).

There are a number of invariants expected mathematically of the Plane type, that cannot currently be enforced due to the fields being public.

A few issues to consider:

  • Should validation be performed when getting values from Godot, or should we just trust the engine with those invariants?
  • What about floating point errors? Should we just accept the drift or attempt to normalize after each operation? It could be useful to see what Godot does in its own source regarding this.

A test should also be added for contains_point_eps.

@chitoyuu chitoyuu added feature Adds functionality to the library c: core Component: core (mod core_types, object, log, init, ...) breaking-change Issues and PRs that are breaking to fix/merge. labels Dec 7, 2022
@Bromeon
Copy link
Member

Bromeon commented Dec 7, 2022

There are a number of invariants expected mathematically of the Plane type, that cannot currently be enforced due to the fields being public.

This is also true to a lesser extent for Basis, Transform2D and Transform:

  • Basis vectors should be linearly independent. Not sure if Godot enforces that, but the type is geometrically useless otherwise.
  • The Rust docs currently call the Transform to represent an "affine transform", but Godot docs don't. In order to be affine, certain mathematical properties need to hold. I'm not sure if that's realistically enforcible, anyway -- but maybe it's just a documentation issue and the transform doesn't need to be affine.

Should validation be performed when getting values from Godot, or should we just trust the engine with those invariants?

Considering this, I'm always asking myself: what do we lose if we validate?

  • if it's performance we can't afford -> use debug_assert! instead of assert!
  • if there are valid use cases to violate invariants -> they are not invariants, and thus don't need validation

Not directly related, but GDScript has the tendency to use questionable values to represent "invalid" states, since it doesn't support real error handling, e.g.

  • Rect2.clip() (renamed to intersect in Godot 4) returning an empty rect at position (0, 0).
  • Basis.invert() returning the original basis for zero determinants.

These are not violating invariants of the type itself, but may surprise users.

@chitoyuu
Copy link
Contributor Author

chitoyuu commented Dec 8, 2022

The Rust docs currently call the Transform to represent an "affine transform", but Godot docs don't. In order to be affine, certain mathematical properties need to hold. I'm not sure if that's realistically enforcible, anyway -- but maybe it's just a documentation issue and the transform doesn't need to be affine.

I think the presence of affine_inverse(), judging from how its docs are worded, kind of implies that Transform can indeed contain non-affine transforms (emphasis mine):

Returns the inverse of the transform, under the assumption that the transformation is composed of rotation, scaling and translation.

If so, then it should be a documentation error on our side indeed.

if there are valid use cases to violate invariants -> they are not invariants, and thus don't need validation

Not directly related, but GDScript has the tendency to use questionable values to represent "invalid" states, since it doesn't support real error handling, e.g.

This is in fact the main concern of mine regarding the input validation problem: the overall API surface is huge, and there might just be some method that use the types in an undocumented way. In other words, it might be the situation that there's something we think is an invariant but is actually not.

Also related is the problem of floating point drift, where in a series of operations small errors add up and eventually become larger than EPSILON -- in this case we can cause panics in perfectly good code (in the sense that for humans it totally work), just because we decided to try to be clever.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Issues and PRs that are breaking to fix/merge. c: core Component: core (mod core_types, object, log, init, ...) feature Adds functionality to the library
Projects
None yet
Development

No branches or pull requests

2 participants