[2.0] Stabilize the undocumented dimensions field of p5.Vector
This issue involves two parts: a bug fix and a new API. I plan to cleanly separate these parts into actionable sub-issues.
Sub-issue 1: Bug fix
Problem
The dimensions field isn't currently documented, but it appears to users when they use the command console.log(myVector), and it may sometimes have inaccurate values, as observed here and here. Thanks to @sidwellr for the following summary:
The gist of the comments linked above is that dimensions does not always reflect the true dimensions of the vector. For example, createVector() (with no params) creates a 3D vector [0, 0, 0] but sets dimensions to 2. And p5.Vector.sub(createVector(1, 2), createVector(1, 2, 3)) will return a 3D vector with dimensions set to 2.
Solution
These bugs should be readily fixable by implementing the property with the JS get syntax, and having the getter retrieve the current, correct value whenever a user accesses it.
Sub-issue 2: A strong API, refined through community discussion
The original API proposal has been withdrawn and can be viewed in the details section further below, for continuity. It's been replaced with a stronger proposal that incorporates community feedback. The new .shape/.rank API would replace dimensions, and would work as follows:
| Data structure |
Proposed read-only property |
Example value |
Data type |
Vector [x, y, z] |
.shape |
[3] |
Array |
Vector [x, y, z] |
.rank |
1 |
Number |
| Matrix (3 rows, 4 cols) |
.shape |
[3, 4] |
Array |
| Matrix (3 rows, 4 cols) |
.rank |
2 |
Number |
Benefits
-
Predictability: Enjoys strong precedents in both math and creative coding
- This API is used by TensorFlow.js. The original motivation for $n$-dimensional vectors was to provide an onramp to exactly this kind of library.
- Using an array for the shape of a vector also enjoys a strong precedent in creative coding: babylon.js, a major peer library backed by Microsoft. It uses
[3] for the shape of a vector [x, y, z], rather than 3.
-
Consistency and extensibility: Offers type consistency and extends to other classes
- Using an array for
.shape (e.g., [3] for a vector) ensures the property always returns the same data type (Array), unlike a property that might return a Number for vectors and an Array for matrices.
- This API extends naturally to matrices, tensors, and even scalars (where
.shape would be [] and .rank would be 0).
-
Readability: Replace ambiguity with clarity
- This API eliminates the confusion around the overloaded term "dimension." A vector like
[2, 3, 5] might be called "3-dimensional," but as a data structure, it's 1-dimensional (like a list), while a matrix is 2-dimensional.
- Replacing
dimensions with a .shape of [3] and a .rank of 1 provides standard, unambiguous terms for these distinct concepts.
Original, withdrawn renaming proposal for `dimensions`
~~This would likely be a useful feature, with precedent in other libraries, e.g. [babylon.js has `dimension`](https://doc.babylonjs.com/typedoc/interfaces/BABYLON.Tensor#dimension). But, prior to release, it may be renamed to `dimensionSize`, which works better in the context of p5. This name would be clearer, and it'd allow a consistent interface across vectors, matrices, and potentially tensors:~~
Data structure |
Proposed property |
Example value |
Data type |
Vector [x, y, z] |
.dimensionSize |
3 |
Number |
Matrix (3 rows, 4 cols) |
.dimensionSizes |
[3, 4] |
Array |
Matrix (3 rows, 4 cols) |
.dimensionCount |
2 |
Number |
This naming scheme prevents users from falling into type traps and ambiguity traps, as described in this comment.
Previous note regarding settable properties (this point has been settled)
Writability:
Also, there would need to be discussion about whether to (a) protect this field from modification or (b) support modification, e.g. by padding a vector with zeros or truncating it if needed. Right now, as @sidwellr noted, "users can currently set dimensions to any value, including nonsensical ones like 2.5 and 'frog'."
Update: The shape and rank are derived properties, based on the underlying data. Directly modifying the shape doesn't allow users to specify their intent (e.g. if the new shape is bigger, how should it be filled?). For vectors and matrices, the rank is a property of the class as a whole, so it's not something that should be modified. The standard, user-friendly approach is to provide explicit methods for reshaping and resizing that allow users to clearly specify their intent. The newly proposed .shape/.rank API adheres to this pattern by making these read-only properties.
Tasks
Edits:
- Added points from @sidwellr.
- Added table to illustrate naming scheme, and clarified its benefits.
- Added task list.
- Reorganized post to reflect community feedback.
[2.0] Stabilize the undocumented
dimensionsfield ofp5.VectorThis issue involves two parts: a bug fix and a new API. I plan to cleanly separate these parts into actionable sub-issues.
Sub-issue 1: Bug fix
Problem
The
dimensionsfield isn't currently documented, but it appears to users when they use the commandconsole.log(myVector), and it may sometimes have inaccurate values, as observed here and here. Thanks to @sidwellr for the following summary:Solution
These bugs should be readily fixable by implementing the property with the JS
getsyntax, and having the getter retrieve the current, correct value whenever a user accesses it.Sub-issue 2: A strong API, refined through community discussion
The original API proposal has been withdrawn and can be viewed in the details section further below, for continuity. It's been replaced with a stronger proposal that incorporates community feedback. The new
.shape/.rankAPI would replacedimensions, and would work as follows:[x, y, z].shape[3]Array[x, y, z].rank1Number.shape[3, 4]Array.rank2NumberBenefits
[3]for the shape of a vector[x, y, z], rather than3..shape(e.g.,[3]for a vector) ensures the property always returns the same data type (Array), unlike a property that might return aNumberfor vectors and anArrayfor matrices..shapewould be[]and.rankwould be0).[2, 3, 5]might be called "3-dimensional," but as a data structure, it's 1-dimensional (like a list), while a matrix is 2-dimensional.dimensionswith a.shapeof[3]and a.rankof1provides standard, unambiguous terms for these distinct concepts.Original, withdrawn renaming proposal for `dimensions`
~~This would likely be a useful feature, with precedent in other libraries, e.g. [babylon.js has `dimension`](https://doc.babylonjs.com/typedoc/interfaces/BABYLON.Tensor#dimension). But, prior to release, it may be renamed to `dimensionSize`, which works better in the context of p5. This name would be clearer, and it'd allow a consistent interface across vectors, matrices, and potentially tensors:~~Data structureProposed propertyExample valueData typeVector[x, y, z].dimensionSize3NumberMatrix (3 rows, 4 cols).dimensionSizes[3, 4]ArrayMatrix (3 rows, 4 cols).dimensionCount2NumberThis naming scheme prevents users from falling into type traps and ambiguity traps, as described in this comment.Previous note regarding settable properties (this point has been settled)
Writability:
Also, there would need to be discussion about whether to (a) protect this field from modification or (b) support modification, e.g. by padding a vector with zeros or truncating it if needed. Right now, as @sidwellr noted, "users can currently set dimensions to any value, including nonsensical ones like 2.5 and 'frog'."
Update: The shape and rank are derived properties, based on the underlying data. Directly modifying the shape doesn't allow users to specify their intent (e.g. if the new shape is bigger, how should it be filled?). For vectors and matrices, the rank is a property of the class as a whole, so it's not something that should be modified. The standard, user-friendly approach is to provide explicit methods for reshaping and resizing that allow users to clearly specify their intent. The newly proposed
.shape/.rankAPI adheres to this pattern by making these read-only properties.Tasks
getsyntaxEdits: