However the declaration-mirrors-use idea does not apply to function arguments. If you have "void (* f)(int * arg)", you would not use it like "(* f)(* arg)" unless your arg is actually "int * * ".
This could be fixed. Instead of "void (* f)(int * x)" we would write "void (* f)(x &int)". Now it makes sense, the declaration says that we could call the function if we pass the address of some int y, as if by "(* f)(&y)". The specific syntax "x &int" says that the address of an int is x, the same way as "int * x" says that dereferenced x is an int.
What about "void (* f)(int x[10])" (pretending arrays could actually be passed)? With the pointer we relied on the existing opposite of the dereference operator, but there is nothing like that for arrays, that would make an array out of an element. Let's look to Python for inspiration, where the expression "[y]* N" will make a list of N elements with the value y. This gives us: "void (* f)(x [int]* N)". See how the declaration tells us that we could call the function using "(* f)([y]* N)" for some int y.
There's one more we need to solve: "void (* f)(void (* g)(int))". Since the parameter g of * f is a function pointer, we need to pass the address of a function, so clearly & will be involved. But we need a function to take the address of, and we don't have any available. Inspired by the C++ lambda syntax, let's invent function conjuration: "(Args) -> Ret" is an expression that conjures a function taking Args and returning Ret. Hence the solution: "void (* f)(g &(int) -> void)". It says that you could write "(* f)(&(int) -> void)", to call * f with the address of a conjured function taking an int and returning void.
We do need to be aware that the syntax for arguments in function conjuration expressions is the same as in top-level declarations. So we would need to rewrite "void (* f)(void (* g)(void (* h)(int * x)))" as
"void (* f)(g &(void (* h)(x &int)) -> void)". So for each function pointer, its arguments must be declared in the other declaration mode.
Since this makes no sense at all, we have to conclude that the original C declaration syntax forms needs to be deprecated and only the newly invented syntax forms should be used.
x ∫ (int * x)
x &∫ (int * * x)
f &(x &int) -> void; (void (* f)(int * x))
f &(x [int]* 10) -> void; (void (* f)(int x[10]))
The new syntax can also be used for function declarations:
main (argc int, argv [&char]*?) -> int
{
return 0;
}
See how we've invented a different declaration syntax (some sort of dual of C's current syntax), that actually respects "declaration-mirrors-use" better than C does and makes much more sense to humans.
1) The use of the Python feature for arrays I find confusing as it is not orthogonal to the rest of your new and improved syntax for C.
Everywhere else, you change C's declaration order of <declaration-specifier> <declarator>, in your new syntax to place the identifier of the declarator first, followed by any pointer ops, and lastly the type. You are changing the pointer op "" from a prefix that needed to be read right-to-left, after locating the identifier of the declarator, into a suffix "&" following the identifier, to be read left-to-right.
I agree that your change to left-to-right declaration order is definitely more readable.
2) But in your array syntax, borrowed from Python, the type is placed inside the array brackets, which used to hold the constant-expression denoting the array size.
The array size is moved from within the brackets to be last, instead of the type being last, as in all your other syntax "rules".
So, for arrays, the declaration syntax no longer reads simply left-to-right, since type is between declarator identifier and array size.
Wouldn't this be clearer, to have the type last and the constant-expression remain inside the array brackets?
C syntax:
(void ( f)(int x[10]))
use this instead for your new C syntax:
f &(x [10] int) -> void;
3) I have a similiar problem with your function syntax:
instead of:
main (argc int, argv [&char]*?) -> int
{
return 0;
}
why not put the type last, so as to be consistent with all your other syntax?
main (argc int, argv [] &char]) -> int
{
return 0;
}
This is how the Go programming language does it, except for the preceding "func" reserved word and "string" in place of pointer to char:
func main(argc int, argv [] string) int ...
5) The biggest problem I have is with adding "C++ lambda syntax" to C, to solve the problem of passing a function as actual parameter argument.
That would mean you have 2 styles of pointers, one as a prefix and one as a suffix to the declarator identifier.
So you now have to read both right-to-left and left-to-right, which seems to cancel out the benefits of only reading declarations in left-to-right order!
Would it be simpler, and preserve left-to-right declaration order, to provide a FunctionType as in the Go programming language?
A parameter that is passed a function as argument is declared to have a FunctionType.
Pointers to function are not apparently needed, at least not at the user level.
6) Q: How do these proposed changes affect the parsing of the new C syntax?
Current C syntax can be parsed with predictive, non-backtracking parsers, in linear-time.
I don't want to use backtracking, GLR, or other complex methods, if they are avoidable.
At least C can now be parsed with with Yacc or Bison.
(See A13 Grammar in K&R, "The C Programming Language" or
Jacques-Henri Jourdan, François Pottier "A Simple, Possibly Correct LR Parser for C11")
For functions, I think the -> syntax is the only thing that makes sense. It's just natural, first you need the arguments then you get the return value.
> That would mean you have 2 styles of pointers, one as a prefix and one as a suffix to the declarator identifier. So you now have to read both right-to-left and left-to-right, which seems to cancel out the benefits of only reading declarations in left-to-right order!
I'm not following. There are not two styles of pointers, a pointer is declared like "&type". Functions are declared like "(args) -> ret" which is read left-to-right (function taking such arguments and returning such value). A function pointer is simply a pointer to a function like "&(args) -> ret".
> Q: How do these proposed changes affect the parsing of the new C syntax?
I guess I should have added </sarcasm>? C would never adopt such a radical change. In any case, I don't see how it would be fundamentally more difficult to parse than the current declaration syntax. There would be problems disambiguating the two (what is "foo bar;" if foo and bar are both typedefs?). Maybe changing to require a colon after the name would make that simpler "fun: (arg: int) -> int".
By 2 styles of pointers used in functions, see below taken from your examples.
By reading both left-to-right and right-to-left I mean:
"star" pointer in front of the identifier read right-to-left with return function type on the left
and ampersand pointer read left-to-right with return function type on the right of "->"
Here are 2 of your function examples you gave:
This example has both an outermost "void" function return type on the left and another to the right of "->"
"void (* f)(g &(int) -> void)"
Instead use the following to always read left-to-right and get rid of the "star" pointer:
"f &(g &(int) -> void) -> void"
Your next example has 2 "void" function return types on the left, and one "void" to the right of "->"
"void (* f)(g &(void (* h)(x &int)) -> void)"
Instead use the following to always read left-to-right:
"f &(g &(h &(x &int) -> void) -> void) -> void"
I did say "original C declaration syntax forms needs to be deprecated and only the newly invented syntax forms should be used". So the new invented syntax alone is complete (you can express anything with &, (args)->ret and [count]type).
I did something wrong and the asterisk or star, representing C's pointer op, has been dropped from my prior posting. I apologize, also for poor formatting.
This could be fixed. Instead of "void (* f)(int * x)" we would write "void (* f)(x &int)". Now it makes sense, the declaration says that we could call the function if we pass the address of some int y, as if by "(* f)(&y)". The specific syntax "x &int" says that the address of an int is x, the same way as "int * x" says that dereferenced x is an int.
What about "void (* f)(int x[10])" (pretending arrays could actually be passed)? With the pointer we relied on the existing opposite of the dereference operator, but there is nothing like that for arrays, that would make an array out of an element. Let's look to Python for inspiration, where the expression "[y]* N" will make a list of N elements with the value y. This gives us: "void (* f)(x [int]* N)". See how the declaration tells us that we could call the function using "(* f)([y]* N)" for some int y.
There's one more we need to solve: "void (* f)(void (* g)(int))". Since the parameter g of * f is a function pointer, we need to pass the address of a function, so clearly & will be involved. But we need a function to take the address of, and we don't have any available. Inspired by the C++ lambda syntax, let's invent function conjuration: "(Args) -> Ret" is an expression that conjures a function taking Args and returning Ret. Hence the solution: "void (* f)(g &(int) -> void)". It says that you could write "(* f)(&(int) -> void)", to call * f with the address of a conjured function taking an int and returning void.
We do need to be aware that the syntax for arguments in function conjuration expressions is the same as in top-level declarations. So we would need to rewrite "void (* f)(void (* g)(void (* h)(int * x)))" as "void (* f)(g &(void (* h)(x &int)) -> void)". So for each function pointer, its arguments must be declared in the other declaration mode.
Since this makes no sense at all, we have to conclude that the original C declaration syntax forms needs to be deprecated and only the newly invented syntax forms should be used.
The new syntax can also be used for function declarations: See how we've invented a different declaration syntax (some sort of dual of C's current syntax), that actually respects "declaration-mirrors-use" better than C does and makes much more sense to humans.