Skip to content

[SPEC] Constexpr Specification#97

Open
Sir-NoChill wants to merge 5 commits into
gazprea-2026-changesfrom
spec/constexpr
Open

[SPEC] Constexpr Specification#97
Sir-NoChill wants to merge 5 commits into
gazprea-2026-changesfrom
spec/constexpr

Conversation

@Sir-NoChill

Copy link
Copy Markdown
Collaborator

No description provided.

Add spec/constexpr.rst defining a constexpr as a property of a const variable
whose initializer is fully evaluable at compile time: the composition rules,
the recursive validation requirement, and the aggregate (array and tuple)
cases. This is the analysis-derived notion used to size statically-sized
arrays and to constrain global initializers. Examples are written against the
staging array model (no spread operator).
Add spec/constexpr to the Language Specification toctree, after declarations,
so the new page is included in the rendered docs.
Replace the old single-scalar-literal restriction on global initializers with
the constexpr rule (see sec:constexpr). Globals may now reference other globals
and use arithmetic and constexpr aggregates, provided the initializer is fully
evaluable at compile time. Spell out the consequences: no function/procedure/IO
in initializers, no dynamically-sized array globals, and all globals are
implicitly constexpr. The list of legal global statements is unchanged.

@novo52 novo52 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typedef.rst says an array-alias size may use only "arithmetic operations on scalar literals … not constant propagation." constexpr rule 5 explicitly permits "Other variables that are themselves valid constexprs," and the array example sizes with integer[WIDTH] / integer[ELEMENT]. So typealias integer[WIDTH] foo; is illegal per typedef.rst but should be legal under the constexpr model.
My suggestion: array-alias sizes should be constexpr

array.rst does not speak on statically-sized or dynamically-sized arrays at all. These are different from explicit vs inferred size. Are explicitly sized arrays necessarily statically-sized? See the example on line 121, this is an explicit-and-dynamically-sized array. Clarify either here or in arrays.rst.

Comment thread gazprea/spec/globals.rst Outdated
* Functions, procedures, and I/O operations may not appear in a global's
initializer.
* A global may not have a dynamically-sized array type (e.g. ``integer[*]``),
because its size would not be known at compile time.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
because its size would not be known at compile time.

Not true: integer[*] X = [1,2,3]; is known.
Conflation of inferred size and dynamic size; will be confusing without clarification here or elsewhere.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apologies, these are artifacts from my vector/array proposals. Updating accordingly, thank

Comment thread gazprea/spec/constexpr.rst Outdated
An expression is a valid ``constexpr`` if it is composed exclusively of:

1. Literals of base types (``boolean``, ``integer``, ``real``, ``character``).
2. Operators, including ``+``, ``-``, ``*``, ``/``, ``not``, ``and``, ``or``,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
2. Operators, including ``+``, ``-``, ``*``, ``/``, ``not``, ``and``, ``or``,
2. Operators ``+``, ``-``, ``*``, ``/``, ``not``, ``and``, ``or``,

"Exclusively" does not work with "including". I assume these are the only valid operations.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you consider an expression like var a <- std_input to have the <- operator? I think this is what I'm gating against. Maybe a better wording is The operators ``+``, ``-``, ...

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is good. The problem with "including" is that it implies other operators can also be constexpr, but (I believe) your intent is to communicate that this is an exhaustive list of `constexpr '- compatible operators.

Comment thread gazprea/spec/globals.rst Outdated

* Functions, procedures, and I/O operations may not appear in a global's
initializer.
* A global may not have a dynamically-sized array type (e.g. ``integer[*]``),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* A global may not have a dynamically-sized array type (e.g. ``integer[*]``),
* A global may not have a inferred-sized array type (e.g. ``integer[*]``).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However a global may have an inferred sized array type, we just need to make sure that the array type size is inferrable at compile time (eek that sounds circular). I can't think of a way this does not hold in the current spec.

Array-alias sizes must be valid constexprs (permitting constant
propagation), updating typedef.rst away from the literals-only rule.

Disentangle inferred size from dynamic size: integer[*] denotes an
inferred, compile-time-known size, while the dynamically-sized type is
the vector. Explicit array sizes must be constexprs, so a runtime-sized
collection requires a vector. Updates globals.rst, constexpr.rst, and
array.rst accordingly.

Assisted-by: Agent (claude) <ai@blobfish.icu>
@Sir-NoChill Sir-NoChill requested a review from novo52 June 30, 2026 15:14
@Sir-NoChill

Copy link
Copy Markdown
Collaborator Author

Note that there is an issue declaring all array lengths as constexpr:

What happens to the range operator with a non-constexpr index? var i; i <- std_input; var b = 0..i

Should b be a vector or an array? I think this was my principle motivation for folding arrays and vectors into the same array idea, which would allow us to test student's ability to optimize and identify static arrays.

@novo52

novo52 commented Jun 30, 2026

Copy link
Copy Markdown

Should b be a vector or an array? I think this was my principal motivation for folding arrays and vectors into the same array idea, which would allow us to test students' ability to optimize and identify static arrays.

We might consider making all arrays statically sized, and only vectors may have dynamic size. This would achieve this goal.

Edit: I see this is your idea as well, lol

@novo52 novo52 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the two changes I suggested, this is overall an excellent change. I think that making arrays static in size is a win for student learning. They will have the opportunity to do optimizations that would be complicated by dynamically-sized arrays, and the distinction between vectors and arrays allows student compilers an "easy-out" if they do not wish to do the same optimizations for vectors; they can implement vectors with {cap, len, ptr}, but arrays are an easy optimization win for them.

Comment thread gazprea/spec/constexpr.rst Outdated
aggregates as their size is not known at compile time.
A ``vector`` (the dynamically-sized type) can never be a ``constexpr``
aggregate, since its size is determined at runtime. An inferred-size array
such as ``integer[*] X = [1, 2, 3]`` *can* be a ``constexpr`` when its

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I feel "can" is the wrong language--an inferred size array must be constexpr, as all arrays must be. Therefore, for [*], the RHS must be constexpr.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch

Comment thread gazprea/spec/constexpr.rst Outdated
An expression is a valid ``constexpr`` if it is composed exclusively of:

1. Literals of base types (``boolean``, ``integer``, ``real``, ``character``).
2. Operators, including ``+``, ``-``, ``*``, ``/``, ``not``, ``and``, ``or``,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is good. The problem with "including" is that it implies other operators can also be constexpr, but (I believe) your intent is to communicate that this is an exhaustive list of `constexpr '- compatible operators.

@Sir-NoChill

Copy link
Copy Markdown
Collaborator Author

he problem with "including" is that it implies other operators can also be

I agree. exhaustive it is, shall change wording

@Sir-NoChill Sir-NoChill requested a review from rcunrau June 30, 2026 23:48
@Sir-NoChill

Copy link
Copy Markdown
Collaborator Author

Should b be a vector or an array? I think this was my principal motivation for folding arrays and vectors into the same array idea, which would allow us to test students' ability to optimize and identify static arrays.

We might consider making all arrays statically sized, and only vectors may have dynamic size. This would achieve this goal.

Edit: I see this is your idea as well, lol

I am thinking about this, would that mean that a range always returns a vector and never an array? And I can't remember if we deleted the iterator for loop, but if not that would mean that we can iterate over the vectors?

I think this direction makes sense if we do not want to unify arrays/vectors, but I opine that optimization becomes significantly less interesting in this case.

@rcunrau

rcunrau commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Taking executive privilege here: arrays are statically sized and vectors are not. Note that statically sized does not mean the size is known at compile time, only that the size can't change. Note also that both arrays and vectors:

  • are dense (specifically and especially multi-dimensional arrays)
  • work with slices
  • can be optimized

@novo52

novo52 commented Jul 7, 2026

Copy link
Copy Markdown

Ron:

What does it mean for vectors to be dense? Should, for example, vector[10] or vector<integer[10]> be a single allocation? If we allow nested vectors and arrays and try to make them work together (i.e. as a single multidimensional array with some growable dimensions) we run into issues with the vectors all having different lengths, AKA ragged vectors.

I was wondering what your vision of this is.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants