-
Notifications
You must be signed in to change notification settings - Fork 258
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[BUG] ==
and =
in declarations are confusing.
#824
Comments
The unifying functions and blocks as explained by @hsutter in here, will be changed like this: f: (x: int = init) { ... } // `x` is a parameter to the function.
f: (x: int = init) statement; // same, { } is implicit.
f: (x: int = init) = expr; // { return expr; } is implicit.
: (x: int = init) { ... } // `x` is a parameter to the lambda.
: (x: int = init) statement; // same, { } is implicit.
: (x: int = init) = expr; // { return expr; } is implicit.
(x: int = init) { ... } // `x` is a "let parameter" to the block.
(x: int = init) statement; // same, { } is implicit.
{ ... } // `x` is a "let parameter" to the block.
statement; // same, { } is implicit. As we see, terser lambda syntax EDIT: For example, we can have the following lambdas: : (x) -> void { print(x); }
: (x) { print(x); }
: (x) print(x)
: (x) -> _ { return x + 1; }
: (x) -> _ = x + 1
: (x) = x + 1
|
Other related discussions: #634, #761.
I think
|
It is statement (in layman word, it states a fact) that left side equals to right side. |
The same is true of |
@realgdman The fnc1: () -> i32 = x = { return y; } // ERROR
fnc2: () -> i32 = { return x; } = y; // ERROR
fnc3: () -> i32 = x = y; // OK Generally x: = something;
x = { /* ... */ }; // ERROR
x = another; // OK On the other hand, |
Does that works because |
No, I mean x: TYPE = 10;
x = { /* ... */ } // Syntax error Because it's meaningless to put a block statement in a side of assignment. |
More DiscussionLet's discuss the new syntax if we drop Consistency with Control StructursThe new syntax improves consistency with control structures. For example, this is how they look in old syntax: if x < 10 {
return x;
}
f: () -> i32 = {
return 0;
} Now, comparing them in new syntax: if x < 10 {
return x;
}
f: () -> i32 {
return 0;
} Both of Consistency of Variable and Function Declarations (and
|
Today, That makes declarations themselves inconsistent.
Although you haven't suggested these, I'll mention them. |
Today we have the following declarations: name: signature = block-statement
name: signature = statement
name: signature = expression;
name: parameter-list statement
name: parameter-list expression; Am I right? So we don't have only one declaration syntax today. I've explained why they are confusing.
My suggested syntax is: name: signature block-statement
name: signature = expression;
name: parameter-list statement Why do you find it inconsistent? It improves Cpp2 code, because it makes |
The first tree are covered by the second one.
Not all declarations follow the same syntax |
No, they can have defaults:
Yes, it doesn't treat statements and expressions in the same way. On the other hand, current Cpp2 tries to treat them in the same way. That's why I'm reporting this bug. |
I simply think that pursuing this issue is not worth it. Personally, while I was initially of the same opinion, cpp2 syntax has grown on me. Edit: About lists, zig uses |
Why is it a bug?This bug report is about New SyntaxThe ways we declare functions in new syntax are: // With new syntax
name: signature statement
name: signature = expression; That's it. Infact the second one is a variant of the first one. I mean Old SyntaxConsidering this with the current syntax // Today in current Cpp2.
name: signature = something
name: parameter-list something Just like the new syntax, the second is a variant of the first declaration in current Cpp2 (today). That's it. Today (in current Cpp2) Why has it to be fixed?In the current Cpp2's grammar: // Today in current Cpp2.
name: signature = something
name: parameter-list something The // Today in current Cpp2.
name: parameter-list = something
name: parameter-list something
a: (x) = fnc1(); // It doesn't set/return a value!
b: (x) fnc2(); // But it sets/returns a value! Please let's review it again, " It's absolutely inconsistent, and unfamiliar to C++ programmers. On the other hand, if a: (x) = _ = fnc1(); // It doesn't set/return a value!
b: (x) fnc2(); // But it sets/returns a value! How much do you find it readable/consistent? It's the main reason behind of this bug report. Also it's misleading, and also inconsistent with how we currently declare variables: fnc1: (x) = fnc1(); // It doesn't set/return a value!
var1: i32 = fnc2(); // But it sets/returns a value! Also Although it has a higher level view in the language, because the programmer writes code regardless of if it's a statement or an epxression, but it complicates the grammar of Cpp2 for parsing, tooling and reading the code. That's the reason I've created this issue as a bug report instead of a feature suggestion. What if we drop
|
Why the new syntax is necessary?To fix this bug:
We may consider the following solutions to fix the bug of the default return type. Solution 1Add a: (x) = fnc1(); // ERROR! It doesn't set/return a value!
b: (x) = fnc2(); // But it sets/returns a value! In this way we have to make a: (x) -> void = fnc1(); // It doesn't set/return a value!
b: (x) = fnc2(); // But it sets/returns a value! The problem is that for functions with block statements, the default return type will be deduced too:
This solution doesn't allow Cpp2 to have different default return types in terser function syntax when it's needed in different context. So we always have to write Solution 2Swap a: (x) fnc1(); // It doesn't set/return a value.
b: (x) = fnc2(); // But it sets/returns a value. It looks natural. The default return type is natural for both of them. The programmer simply looks at Hey, it has That's natural in other part's of the language. It improves readability. It makes b: (x) = fnc2();
x: i32 = 2;
x = 10; This change leads to drop a: (x) -> void { fnc1(); }
a: (x) { fnc1(); }
a: (x) fnc1();
b: (x) -> _ { return fnc2(); }
b: (x) -> _ = fnc2();
b: (x) = fnc2(); Also for consistency, other declarations have to be changed: f: (xy) { }
t: type { }
n: namesapce { }
g: (xy) = value;
v: TYPE = value; It's consistent with control flows, ConclusionTo fix this issue, solution 2 is superior to solution 1. Thanks. |
The number of up votes on this comment, is a data to consider that many Cpp2 programmers find
That's because programmers expect |
Now considering // {} defines a new type:
cls1: type {
// declarations...
}
// cls2 definition is set from cls1 definition:
cls2: type = cls1; It's similar to Considering lambda expressions (unnamed functions), it will be terser without : (x) -> void { print(x); }
: (x) { print(x); } While it's somehow similar to lambdas in Cpp1, but currently we have to write them in Cpp2 (today) with : (x) -> void = { print(x); }
: (x) = { print(x); } Discussion #793 is related to this topic. |
Description
Considering @hsutter's comment from discussion #623:
The part "we should closely follow the built-in operators' meanings" is important here.
To Reproduce
Notation
==
Considering type and namespace aliases:
A typical C++ programmer expects
==
to return the result of a comparison, but it setsv32
type definition from another type instead. Therefore==
is an assignment operator in declarations, but it is a comparison operator in expressions.Considering
constexpr
functions and variables,==
is more confusing:The first
==
setsfnc1
function definition, but the second==
compares two literals and returns the result. A typical programmer may ask why it's happening while they are next to each other.Considering
concept
declarations in Cpp2:arithmetic: <T> concept = std::integral<T> || std::floating_point<T>;
Unlike types and namespaces, it uses
=
instead of==
. Cpp2 is/was designed for C++ programmers of which they are more familiar with declaring stuff by=
than==
in Cpp1:Notation
=
Considering function declaration syntax:
If we ask programmers who are not familiar with Cpp2 that "What does
fnc1
function do?", they probably will answerfnc1
returns an empty list{}
. Because that's natural to programmers.=
puts the result of its right side to its left side.{}
is on the righ side, so it must have a value.But this known behavior doesn't work in Cpp2.
=
doesn't set anything in the example, and{}
doesn't have a value too! Of coursevoid
is nothing, it's not even similar tonull
andnullptr
which they are values.EDIT: Considering this note from this comment:
Looking at
fnc2
, a typical programmer which is not familiar with Cpp2, thinkssomething()
has a value and the function returns the value from the right side of=
, that's expected because of the assignment operator in the declaration. Although we had this natural behavior in Cpp2 before, but @hsutter changed this behavior (because of issue #257) because of the push-back he got on issues/comments as he explained it here.Why not bring back the original behavior for function declarations with
= expression
only?Additional context
To solve the issue, Cpp2 may have a simple defined rule to separate statements from expressions in declarations, if one extra
=
could be dropped from them:fnc1
is defined by a block statement, because it doesn't have=
, butfnc2
is defined by an expression, because it has=
. This rule allows to categorize function decleration to two syntaxes.First, the function declaration (also lambdas) with block statement: it has not a return type by default:
Second, the function declaration (also lambdas) with an expression after
=
: it has a generic return type by default:In a similar manner, types and namespaces would be (more familiar to C++ programmers):
In general
{}
is a block statement and= ...
is an expression or a name (or a fully qualified name).Also for
constexpr
functions and variables, other solutions such as using a keyword can be considered.Discussions #742 and #714 are related to this topic. Thanks.
Follow-up Readings
More discussion about how the new syntax may improve Cpp2 in this comment:
inspect
Expressions)"Why is it a bug?" from this comment:
=
from them?"Why the new syntax is necessary?" from this comment.
The text was updated successfully, but these errors were encountered: