-
Notifications
You must be signed in to change notification settings - Fork 266
Description
Preface
Statement-expression is a solution to have a group of statements in place of an expression.
I suggest to have statement-expressions in Cpp2 with syntax : = { ... } and the result of them are returned with result keyword. In this way, the following code:
call(: = { n: = num(); result n + 0; },
: = { n: = num(); result n + 1; });... is somehow equal to the following code except that we don't have to specify the type of arguments:
arg0: int; { n: = num(); arg0 = n + 0; }
arg1: int; { n: = num(); arg1 = n + 1; }
call(arg0, arg1);Statement-expressions can be used to declare variables too:
// The type of `variable` is `int`.
variable: = {
value: int;
//: statements...
result value;
}Suggestion Detail
Currently we declare functions in Cpp2 in the following syntax:
// function or lambda style
func0: (param) = {
return param;
}
// expression style
func1: (param) = param;In a similar syntax, we can declare variables in Cpp2 with statement-expressions:
// statement-expression style
var0: = {
result 0;
}
// expression style
var1: = 0;Statement-expressions are unnamed variables in a similar manner that lambdas are unnamed functions:
- We have to use
resultinstead ofreturnwithin statement-expressions. - We can use a statement-expression everywhere that an expression is required.
- A declaration within their
{ ... }has the lifetime of that scope. - Their
{ ... }will be executed one time in their place. - They don't create a new function scope, therefore variables from outer scope don't have to be captured within their
{ ... }.
Statement-expressions will be not allowed to be used in place of statements. Because it's an error to have an unused value (literal or identifier) in Cpp2:
main: () = {
// ERROR! It has to be in place of an expression not an statement.
: = {
x: = 0;
result x + 1;
}
// ERROR! Because `x + 1` is an unused value (literal or identifier).
}Expressions, Functions and Blocks
Now { ... } has different meanings in the following categories:
: Type = { ... }is a statement-expression in whichTypecan be omitted and deduced from{ ... }.- The execution of statements in
{ ... }ends withresult something;. - It can be a part of variable declaration, or in place of an expression (e.g. function argument):
x0: = 0; x1: = { result 0; } call(: = { result 0; })
- The execution of statements in
: (params) -> Type = { ... }is a function or a lambda in which-> Typecan be omitted if the return type isvoid.- The execution of statements in
{ ... }ends withreturn something;or the end of}. - It can be a part of function declaration, or in place of an expression (e.g. function argument):
x0: (param) = param; x1: (param) = { return param; } call(: (param) = { return param; })- The execution of statements in
(params) { ... }is a parameterized statement block. Whereas{ ... }is a statement block without(params)in which()must be omitted.- The execution of statements in
{ ... }ends with:- ... the end of
}. - ...
breakandcontinuein loop control structures. - ...
result something;when their outer scope is a statement-expression. - ...
return something;when their outer scope is a function or a lambda.
- ... the end of
- It can be a part of control structures:
for items do (item) { call(item); } if condition { call(); }
- The execution of statements in
In all of the above categories, they have this similarity:
- A declaration within their
{ ... }has the lifetime of that scope.
Additinally they have different behaviours in statement execution and variable capturing:
- Statement-expressions (case 1) have to execute their
{ ... }one time in their place.- But other cases can execute their
{ ... }multiple times in any place.
- But other cases can execute their
- Functions and lambdas (case 2) create a new function scope therefore variables from outer scope have to be captured within their
{ ... }.- But other cases don't create a new function scope, therefore variables from outer scope don't have to be captured within their
{ ... }.
- But other cases don't create a new function scope, therefore variables from outer scope don't have to be captured within their
I should mention that statement-expressions, functions and lambdas, statement blocks and parameterized statement blocks can be nested inside each other.
Your Questions
Will your feature suggestion eliminate X% of security vulnerabilities of a given kind in current C++ code?
Yes. In a way that it helps Xto organize code and separate related statements in nested blocks to easily fix or prevent unwanted bugs which are a result of having mixed unrelated statements together.
Will your feature suggestion automate or eliminate X% of current C++ guidance literature?
Yes. In the following ways:
- It will make the declaration syntax of variables and functions to be similar and consistent.
- It helps programmers to separate related statements easily without defining extra variables.
- It allows programmers to use
if,whileand other control structures as an expression that is more readable in variable assignment, because the intention is clearly written in code, see the example below. - It allows programmers to be less specific about types in generic programming, see the example below.
Consider how the following code:
variable: = {
if condition {
result hello();
}
else {
result bye();
}
}... is more readable and generic than the following code which we have to also specify the type of the variable:
variable: int;
if condition {
variable: = hello();
}
else {
variable: = bye();
}Considered Alternatives
Instead of result keyword, it's possible to use symbols such as => or nothing (like in Rust). For example:
variable: = {
if condition {
=> hello();
}
else {
=> bye();
}
}... or this one (like in Rust):
variable: = {
if condition {
hello() // without ;
}
else {
bye() // without ;
}
}Howerver I think that having a keyword like result or a notation like =>, is more readable than having nothing.
References
This suggestion is inspired from discussions in this issue and this paper mentioned by @JohelEGP and this informative comment from @hsutter which describes Unifying Functions and Blocks.