Author Topic: Syntax of const pointers  (Read 21853 times)

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Syntax of const pointers
« on: July 17, 2013, 07:39:26 PM »
I'm currently working on the Type system of C2 and ran into a syntax issue that
I would like to think about more and get more input about.

I'll start by briefly describing the syntax of (ansi-)C in this regard:
Code: [Select]
const intmeans an integer that cannot be changed.
Code: [Select]
int*a pointer to an integer. So far so good. Now for the tricky part:
Code: [Select]
const int*
int const*
Both are equal and describe a pointer to an integer that cannot be changed. The pointer itself can be changed to point
at something else. Syntax here is already becoming more vague.
Code: [Select]
int* constOkaaaay So this is a constant pointer to an int. The int can be changed (through the pointer), but the pointer itself
will always point to the same int.
Code: [Select]
const int* constThe final version, both the pointer and the value it points to cannot be changed.

Since C2 tries to improve C, this piece of trickery begs to be upgraded.
I currently see 3 options:
1. Add some parentheses
ansi-C  ->    C2
const intconst int
const int*(const int)*
int* constconst (int*)
const int* constconst (const int*)
This does make it a bit more clear, but the syntax suffers also.

2. Require 2 steps for certain types:
ansi-C  ->    C2
const intconst int
const int*(const int)*
int* consttype IPtr int*;
const IPtr
const int* consttype CIPtr const int*;
const CIPtr

3. <Your idea here>

So please feel free to post.

DerSaidin

  • Newbie
  • *
  • Posts: 13
    • View Profile
Re: Syntax of const pointers
« Reply #1 on: July 24, 2013, 10:43:56 AM »
Now for the tricky part:
Code: [Select]
const int*
int const*
Both are equal and describe a pointer to an integer that cannot be changed. The pointer itself can be changed to point
at something else. Syntax here is already becoming more vague.

I think this is the main problem with const in C, the order of const is varying/inconsistent/different.
It becomes confusing when you usually use 'const int *', and you see 'int const *' and think it means something different. I think it would be an improvement to restrict to specific positioning.

3. Limit positioning
ansi-C  ->    C2
const intconst int
int constconst int
const int*const int*
int const *const int*
int* constint* const
const int* constconst int* const
const int * constconst int* const
const int * const *const int* const *
const int * const *constconst int* const * const

This positioning is what I usually see and write.
I think this would reduce confusion, and is compatible with C.

However, this is a bit inconsistent:
Code: [Select]
const int a = 4;
int * const b = &c;
The variables a and b are both constant, but in one case the const qualifier is before the type,
in the other case const is before the identifier and after the type.                                                                               

To make it more consistent, you could move the first const, so the const comes after the type it qualifies.
Parentheses shouldn't be needed, think of it as a tightly binding suffix operator.

4. Const qualifier after type
ansi-C  ->    C2
const intint const
int constint const
const int*int const *
int const *int const *
int* constint * const
const int* constint const * const
const int * constint const * const
((((int) const) *) const)  // parentheses to clarify ast structure
const int * const *int const * const *
((((int) const) *) const) *)  // parentheses to clarify ast structure
const int * const *constint const * const * const
(((((int) const) *) const) *) const)  // parentheses to clarify ast structure

Now the const qualifier is consistently after the type, and is still compatible with C.
It doesn't have the usual adjective-noun order if you read it left to right, but right to left is ideal:
Code: [Select]
int const * const X = &b;"X is a constant pointer to a constant int"

It could also be made consistent by always putting the const qualifer before the type.
This takes the * token as the position of the pointer type.

5. Const qualifier before type
ansi-C  ->    C2
const intconst int
int constconst int
const int*const int *
int const *const int *
int* constint const *
const int* constconst int const *
const int * constconst int const *
((const (int)) (const *))  // parentheses to clarify ast structure  :/
const int * const *const int const * *
const int * const * constconst int const * const *

This is consistent, and it is in the usual adjective-noun order (and the [probably] more common qualifier ordering use in C).
One disadvantage with this is that It breaks compatbility with C. I realize that C compatibility is not a goal, but it does make it less confusing for C developers, who are probably the main audience.

Also, the AST structure isn't nice/clear/elegant to me.



One of the features of type qualifiers is that they can be added to an existing type, you don't need to define a new type for the qualifier. For this reason I don't like Option 2.


If you don't know the language Options 3, 4 and 5 aren't as implicitly obvious as Option 1, but they're still simple and easy to apply once known and save syntactic cluttering of parentheses.


My preference is Option 4 for being consistent, C compatible, and nice to say aloud (by saying tokens right to left).

bas

  • Full Member
  • ***
  • Posts: 220
    • View Profile
Re: Syntax of const pointers
« Reply #2 on: July 26, 2013, 01:06:06 PM »
I like option 4 as well. The only minor thing is that 'const int' changes to 'int const', so that'll take
a bit getting used to.

It also works well during parsing, since the const qualifier is added to the type (that was parsed left
of it). So we have the type already by then.

To be consistent, the same will apply to other qualifiers (volatile and restrict) as well,
so in case 4, those will be like:
int volatile reg1;
int volatile * const;  // const pointer to volatile int (the most common case in low-level programming).

I'll be away for the next 2 weeks, but i'll keep grinding my head about this.

kyle

  • Newbie
  • *
  • Posts: 48
    • View Profile
Re: Syntax of const pointers
« Reply #3 on: June 20, 2014, 11:34:47 PM »
Hmm, I've been programming in C since about 1979 and I never really thought about all the ways const can be stuffed into a type declaration.  I really like #4.

One of the things that Go changed from C was the order of declarations.  At first this seemed a little bit gratuitous.  However, the more Go code I see, the more it makes sense to me.  It is really a fair amount easier to read complicated declarations.

The Go people also did this to simplify the compiler. 

Thanks for writing all these tables up.  This is really useful!

Best,
Kyle

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Syntax of const pointers
« Reply #4 on: October 30, 2018, 03:19:04 PM »
Upvote for implementing 4.

lerno

  • Full Member
  • ***
  • Posts: 247
    • View Profile
Re: Syntax of const pointers
« Reply #5 on: January 02, 2019, 02:45:37 AM »
I've thought about this some more and I'm actually leaning towards 5 now, since that would make things easier when reading.

Do we want to write:
Code: [Select]
int volatile x = 10;
Foo const foo = { ... };
int * const y = &x;

// or
volatile int x = 10;
const Foo foo = { ... };
int const* y = &x;

Maybe it's just me, but in the simple case then the prefix keyword really rules.

And for the complex ones, maybe () isn't such a bad idea:

// 4
Code: [Select]
int* volatile x = 10;     // volatile pointer to int
Foo* const foo = { ... }; // const pointer to Foo
Foo const* foo = { ... }; // pointer to const Foo
int* const y = &x;        // const pointer to int
int const* y = &x;        // pointer to const int

// 5
Code: [Select]
int volatile* x = 10;     // volatile pointer to int
Foo const* foo = { ... }; // const pointer to Foo
const Foo* foo = { ... }; // pointer to const Foo
int const* y = &x;        // const pointer to int
const int* y = &x;        // pointer to const int

// 1
Code: [Select]
volatile (int*) x = 10;     // volatile pointer to int
const (Foo*) foo = { ... }; // const pointer to Foo
(const Foo)* foo = { ... }; // pointer to const Foo
const (int*) y = &x;        // const pointer to int
(const int)* y = &x;        // pointer to const int

Note that it looks very different visually depending on where you put the "*". (1) shines when the star is put next to the type.

One more thing to consider should be the parsing. For example: an expression starting with '(' can be deducted to always be an expression on C, but with ( ) in the type names, that would not be obvious.