Skip to content

Language: accept untyped global constant definitions - #547

Open
chqrlie wants to merge 1 commit into
c2lang:masterfrom
chqrlie:untyped-constants
Open

Language: accept untyped global constant definitions#547
chqrlie wants to merge 1 commit into
c2lang:masterfrom
chqrlie:untyped-constants

Conversation

@chqrlie

@chqrlie chqrlie commented Jul 25, 2026

Copy link
Copy Markdown
Contributor
  • type is inferred from init value
  • cannot take the address of an untyped global constant
  • add tests
  • need bootstrap to use in the compiler or libraries

@chqrlie
chqrlie force-pushed the untyped-constants branch from 94620a4 to 39b7c01 Compare July 25, 2026 14:04
@bvdberg

bvdberg commented Jul 26, 2026

Copy link
Copy Markdown
Member

I'm playing around with this. I think we can tighten some checks:

fn void test1() {
    const foo = 20;
    const bar = "hallo";
    const faa = bar + 1; // allowed?!  also allows bar + 7
    
    printf("[%s]\n", faa);  // will print 'allo'
}

Maybe we can also enforce local const to be Capital cased (perhaps only for untypes at first? to make it easier)

Code-wise there seems to be some duplication between analyseGlobalVarDecl and analyseDecl, maybe we can refactor that into a common function?

The error messages contain 'untyped global constant'. I think this tshould be 'untyped constant' since it should also apply to local constants.

@chqrlie
chqrlie force-pushed the untyped-constants branch from 39b7c01 to bec19b1 Compare July 26, 2026 13:09
@chqrlie

chqrlie commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

I'm playing around with this. I think we can tighten some checks:

fn void test1() {
    const foo = 20;
    const bar = "hallo";
    const faa = bar + 1; // allowed?!  also allows bar + 7
    
    printf("[%s]\n", faa);  // will print 'allo'
}

Forbidding pointer arithmetics would be consistent with the rejection of the & operator, but I am not sure what problem this would solve or prevent. bar gets an inferred type of const char[6] and faa gets an inferred type of const char* const, which is probably what the user would expect albeit most programmers would not even know how to specify it.

const char* bar = hallo + 7; would be accepted too... The analyser should be able to reject it, with or without the full type specification.

Maybe we can also enforce local const to be Capital cased (perhaps only for untypes at first? to make it easier)

I would not do that, local variables are not global constants, defining them as const is just a programming style where people name intermediary results that are not meant to be modified in the rest of the function's proceedings. Other languages may this the default and require an explicit qualifier to allow mutability (mut in Rust, var in Swift, Kotlin, Mojo...)

There is a fundamental semantical difference between global constants that name concepts that are given for the whole program or system interface and const local variables that are computed from other stuff and may get a different value each time. These are variables that no longer vary once computed but should be usable like other variables, hence have the same naming restrictions (if any) and be usable the same way.

Code-wise there seems to be some duplication between analyseGlobalVarDecl and analyseDecl, maybe we can refactor that into a common function?

Yes, I shall look into that, but for a separate PR

The error messages contain 'untyped global constant'. I think this it should be 'untyped constant' since it should also apply to local constants.

Indeed, it should not mention global for local variables, but as coded it only applies to global identifiers.

@chqrlie
chqrlie force-pushed the untyped-constants branch 3 times, most recently from 2af17be to 7931fd7 Compare August 4, 2026 13:24
* type is inferred from init value
* accept `const` blocks: `const { ONE = 1, TWO = 2 }`
* cannot take the address of an untyped global constant
* add tests
* need bootstrap to use in the compiler or libraries
@chqrlie
chqrlie force-pushed the untyped-constants branch from 7931fd7 to 7e7dc34 Compare August 6, 2026 07:30
@bvdberg

bvdberg commented Aug 22, 2026

Copy link
Copy Markdown
Member

merged!

@bvdberg bvdberg closed this Aug 22, 2026
@bvdberg bvdberg reopened this Aug 22, 2026
@bvdberg

bvdberg commented Aug 22, 2026

Copy link
Copy Markdown
Member

I had to revert this on Main, since it broke on attributes..

const u32 Max @(unused) = 10; //ok
const Max @(unused) = 10; // breaks

I tried fixing it in c2_parser.c2 Parser.parseSingleTypeSpecifier() by changing also checking if next token is an At, but that broke a lot of stuff..

When I debugging I was looking at the const blocks again and I dont really like the added syntax complexity. It is different than the rest. Multiple simple lines are just clearer I think.

@chqrlie

chqrlie commented Aug 22, 2026

Copy link
Copy Markdown
Contributor Author

I had to revert this on Main, since it broke on attributes..

const u32 Max @(unused) = 10; //ok
const Max @(unused) = 10; // breaks

I think both of the above are wrong.
The only accepted syntax with attributes should be const Max = 10 @(unused);, with or without a type

Restricting the attributes to occur only before ,, ; and { might even simplify the parser in other places.

Another direction is the new [[attribute list]] syntax introduced in C2y. For consistency with the evolution of C, we might want to follow this direction. Look at chapter 6.7.12 Attributes of n3886.

With this new syntax, we could have equivalently:

const [[unused]] Max = 10;
[[unused]] const Max = 10;

or

[[unused, deprecated("use i32.max instead")]]
const Max = 10;

I do not particularly like this new stuff inherited from C++, like most of the C++ syntax indeed. My preference would be:

@unused const Max = 10;

or

const Max = 10 @unused;

and

@deprecated("use i32.max instead")
const Max = 10;

or

const Max = 10 @deprecated("use i32.max instead");

and in combination

@unused @deprecated("use i32.max instead")
const Max = 10;

or

const Max = 10 @unused @deprecated("use i32.max instead");

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants