-
Notifications
You must be signed in to change notification settings - Fork 251
Design note: Defaults are one way to say the same thing
In Cpp2 I work hard to avoid providing two ways to spell the same thing.
Well-designed defaults that allow omitting unused parts of a general syntax are not two ways to say the same thing... they are the same One Way, but you aren't forced to mention the parts you're not currently using.
Further, they actively help avoid pressure to proliferate different ways of saying a thing by providing a single general way that's convenient in many places.
Example: Cpp2's function syntax works well from big generic functions, down to tiny lambdas with captures, down to plain old blocks and statements... using only one general syntax
Consider these cases, all of which are supported:
f:(x: int = init) = { ... } // x is a parameter to the function
f:(x: int = init) = statement; // same, { } is implicit
:(x: int = init) = { ... } // x is a parameter to the lambda
:(x: int = init) = statement; // same, { } is implicit
(x: int = init) { ... } // x is a parameter to the block
(x: int = init) statement; // same, { } is implicit
{ ... } // x is a parameter to the block
statement; // same, { } is implicit
If we read those top to bottom, we see how the general function syntax just lets us omit more and more syntax if we aren't currently using it:
- declaring an anonymous function is exactly the same as any function, just has no name (and still has
:
because we're declaring something new); - a parameterized block or statement is exactly the same as a function used in just this one place, so it just drops
:
since we're not declaring a separate entity (and drop=
too because we're also not setting its value; and - an ordinary block or statement is exactly the same but with no parameter list, so it just omits the parameter list (and the ordinary block/statement syntax just falls out).
And if we read them bottom to top, we see how we can just add more and more power by opting into using it:
- any ordinary block or statement can optionally have parameters...
- ... and can be wrapped up to be called repeatedly and passed around...
- ... and can be given a name.
Even those last two lines show an existing default: It is already true in today's C and C++ that { statement; }
and statement;
have identical meaning (except for macro effects), the braces are just optional and we nearly never bother to write them around individual statements (except in today's C and C++ branch bodies to guard against macro effects, which Cpp2 eliminates as a problem).
For example, a C++ function with a default parameter, like int f(int i, int j = 0)
, can be called with f(1,0)
, but it can equivalently be called as f(1)
... but it's still just one function, and one way to call it. At the call site we just aren't forced to spell out the part where we're happy with the default (and we still can spell it out if we want).
Similarly, for a C++ class class C { private: int i; ... };
, we can equally omit private:
and say class C { int i; ... };
. There's still just one class syntax, but we get to not mention defaults if we're happy with them (and we still can spell it out if we want).
To me, allowing a generic function f:(i:_) -> _ = { return i+1; }
to be spelled f:(i) i+1;
is like that... there's only one way to spell it, but you get to omit parts where you're happy with the defaults. And that's especially useful when writing functions at expression scope (aka lambdas), such as examples like these:
std::for_each(first, last, :(x) std::cout << x;);
std::transform(x.begin(), x.end(), y.begin(), :(x) x+1;);
location_of_value = std::find_if(x.begin(), x.end(), :(x) x == value$;);
There seems to be demand for this, because we've had many C++ proposals for such a terse lambda syntax. For example:
- in ISO there's P0573
- in Boost.Lambda they had just such a terse body syntax before C++ language lambdas existed, and
- in GitHub projects using macros),
but none of those (or at least not their terse parts) have been accepted for the standard yet. So I'm trying to help satisfy a need other people have identified and explore what it would like like to fill it, to gather evidence and experience for whether and how it can be done in C++ for all C++ programmers.