[SPEC]: Vector Semantics? - #106
Conversation
|
I'm sorry, but I don't understand what your diagram is trying to say. In general, vectors are pretty close to interchangeable with 1D arrays, but vectors of vectors are completely different than 2D arrays. For most math ops, vectors and arrays are compatible, I think. For parameters, slices of vectors can be passed as array arguments, but arrays cannot be passed as vector arguments. vectors should be usable as iterators wherever arrays can be used as iterators. Like other languages, if you mutate the vector/array inside the loop, you can make bad things happen. We do not need to protect users from themselves. I suppose a good compiler would warn about yuckiness. It might also be fun to give some examples of programs stomping themselves. Functions must be pure, so they should be able to take const vectors. I would think changing the size is a side effect, unless the vectors are passed by deep copy. The compilers can either check that a vector is not modified, or pass by deep copy and let function do what it wants. Which do you think is better? |
|
BTW, I cannot find anything anywhere that uses the term elaboration as you do. The C99 spec seems to call them "variable length arrays", and Wikipedia indicates that VLAs are in 10 different languages, including Ada. I have to admit I do not understand where this is coming from. Can you show me the email trail of confused students who couldn't comprehend the array sizing semantics of Gazprea? |
|
All that said, I think your writing is beautiful, and explains everything wonderfully. If you rewrite the rest of the spec to match this level of clarity it will be amazing :-) |
|
In terms of the diagram, here is my updated diagram after flushing this out for clarity and noting a few of my mistakes:
Legend
Scalars
This denotes the set of scalar (or primitive) types in gazprea. More formally, So this reads that booleans, characters, integers and reals are each an individual component of the set of scalar types, with a one-way implicit conversion existing between integers and reals. It also notes that there is no type from which we can promote (implicitly) to get a boolean, character or integer (which would be
So integers can automatically promote to reals but not the other way around and there are no other implicit scalar promotions. Aggregate types
Aggregate types here read that we can use any scalar type to construct an aggregate type of known, definite size.
The errata above notes that this should actually read that any type in the universe of types can be used to construct an aggregate type. Two things that I should make clear:
Composite types
This is just a grouping of other, arbitrary types, so it just reads that a composite type is the composition of multiple instances of U. I have thus far dropped the requirement that a struct/tuple have more than one composing type, but that can be made explicit. I have this 'unit struct' type gated behind a feature flag in the solution compiler. |
|
As a note, I found VHDL and Verilog use elaboration to talk about the stage of expanding the source into usable gates, but you are right, none of the current language specifications define elaboration. I believe they all call this 'runtime', so our arrays would still be 'runtime' sized, but such that size is const... I don't really like that definition, to be discussed further. |
|
There seem to be ambiguities surrounding the implicit casts between vectors, arrays, and strings, especially surrounding strings. I'd resolve it by removing the implicit conversion from
What you can do: What you can't do: The aliasing case needs no new machinery: Slicing always yields an array, for strings as much as for vectors. Recovering a string from a substring is just This also settles what The What do you two think? |
|
This is good work, the array-vector stuff is much more explict now. I worry that if this same approach is applied to everything in the spec, we may end up with a spec I'd like a rebase before we approve it finally; There have been changes since branching that are relevant to this. |
|
I think this is totally unnecessary. In the case where the argument is |
|
@rcunrau when you say that this is unnecessary, is that because it seems obvious? I agree that there is no need to pass by value, but with MLIR it is easier to pretend like we are. Bufferization handles the actual lowering to pass by reference or pass by value, in general by reference as you said. I'll do a rebase here, I am working on another set of fixes for the spec grammar and self consistency and then I'll fold this into that PR stack. @novo52 Some questions regarding your comment:
I don't think this exists after my revision, see this:
There is only an implicit upcast to a vector via initialization or from a char[*] to a string to a vector. I'm open to making that require an explicit cast.
This provides a nice constraint to the type lattic (monotonicity), which will be nice for students, I will add that as a note.
Does that mean we should say that
Does this mean vectors have no output semantics? |
|
I mean the
|
|
I tend to agree:
|
Open the type system to the settled "arbitrary nesting and arbitrary structs" decision. Vectors, structs, tuples, and arrays may now hold any storable element or field type, and fixed-size arrays generalize from the two-dimensional matrix ceiling to arbitrary rank (T[n1]...[nk]). This reverses the vector element-type restriction and the bans on nesting structs/tuples inside structs and tuples. A single authoritative rule lives at ssec:storable_types (types.rst): everything except streams is storable; nesting is unbounded but must be acyclic through value types; recursion is legal only through a vector, the sole point of indirection. Each per-type page now defers to it, and array.rst's element-type list is widened to match. The >=2 field/element arity requirement is unchanged. Rank-agnostic operations (a shape interface, n-d matrix multiply, broadcasting) are left to a follow-up revision. Refs: #132 #106 #82 #71 #101 #86 Assisted-by: Agent (claude) <ai@blobfish.icu>
Begin folding PR #106 into the consolidated spec, with review decisions. - glossary: define `initialization` (renames #106's contested "elaboration") and `zero value` (RAII-const default; array padding). - types/array.rst: new Sizing section and an Array-vs-Vector table, both stated for arrays of any rank per #138 -- not 2-D / base-type-only. - Remove the `by` (stride) operator and `StrideError` entirely (it implies array views, which have no efficient implementation): the Stride operation, the precedence-table row, and the stride examples are gone. - Concatenating two scalars is now a `TypeError`; at least one operand of `||` must be a composite value. Refs #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Renames the implicit-conversion vocabulary from 'promotion' to 'implicit cast' (heading of sec:typePromotion becomes 'Implicit Casts', label kept), and adds two-way array/vector casting sections. Part of folding #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
string is now a language-supplied typealias for vector<character> (not a sub-type). Methods are defined as procedures with a self parameter; only vector/string have them. Adds ragged rules: vector<vector<T>> may be ragged, vector<T[*]> may not; no broadcasting or shape(). Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Assignment sizing (array pads/SizeError vs vector replaces), generators always yield arrays, vectors print as arrays, length() on a vector is current-length. Replaces the shape() built-in with rows/columns. Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>
Explicit-size array params are part of the signature; inferred [*] is initialized at the call; var array can't resize but var vector can. Single source-of-truth list of legal procedure-call positions; call results are castable. Folds #106. Assisted-by: Agent (claude) <ai@blobfish.icu>





I am not entirely sure I understand the current reading of vectors and would like to clarify it. I have a type lattice proposed that looks as follows:
Does this align with what you are going for? Are arrays and vectors able to be used interchangably? Can a vector be used as an iterator? If so what happens if the vector is mutated inside the iterator scope? Do we need to COW it?
Procedures returning vectors? Procedures taking vectors as arguments makes sense but can functions take vectors as arguments?