Or both, right? I thought the keyword would be required to use something other than the last expression, or for clarity even in the last expression.
Beyond then
another keyword proposed from generators was yield
:
https://forums.swift.org/t/pitch-multi-statement-if-switch-do-expressions/68443/17
As for indicia beside a keyword, since this feature hinges on rules of definite assignment:
- a new block-assignment operator
:=
- assigning to the target variable in the outer scope
- and consider naming function results for this purpose? (oh no it's Go!)
These alternatives were not popular and are not complete, but might be reasonable.
https://forums.swift.org/t/pitch-multi-statement-if-switch-do-expressions/68443/188
Overall I'm a little concerned that the focus on syntax and ceremony obscures the question of the programmer's mental model.
In Python developers have dealt with variable argument splatting, context managers, and a whole host of meta-programming, and the mental model of an interpreter feeds into the notion of the last-expression as function result.
Swift for error-handling purposes has guards and early returns that make the explicit return statement for the function pretty essential, so ambiguating return
is more problematic.
Swift's closure support and its high-traffic combinations with async and systems API's make it pretty common in Swift to have code in nests that are not only deep, but non-sequential. So things like block-relative interpretation or (throw-like) jumps to outer contexts from expressions pile complexity on complexity.
i.e., a bias against the return
keyword in Swift or for the last-expression in Python comes not really the economy or readability of syntax but what the programmer has to understand (and has understood) in the overall language context.
From my perspective, expressions are relatively safe; they're almost by definition simple and local. That's worth preserving.
In medical education they distinguish between system-1 and system-2 thinking. System 1 is quick, high-confidence associations to simply memorize and apply efficiently. System 2 involves working through complex issues from first principles. Yes, all doctors do both, but doctors differ generally by expertise in one or the other. In schooling or practice it's unwise to simply assume a volume or depth profile, and impractical to ask for depth at volume or volume at depth. It makes things easier when the workflow has boundaries between the different systems so switching has clear signals.
Given that distinction, one design heuristic could be to keep expressions in system-1 distinct from closures requiring system-2.
If there really are cases where the multi-statement expression is simpler to think about than the alternatives, the clearest rule would be to only support a result in the last statement, and to require some syntactic indicia for multiple statements
For that indicia, the obligatory bikeshed:
- not
return
, for reasons above
- not
then
, because of if
, and lack of precedent
- not
yield
if Swift is ever to have generators
- not
:
label, for ambiguity and obscurity
Some assignment-reminiscent prefix operators:
:=
- (more definitional),
=>
- mirrors the function result indicator ->
- (but both typically are used as infix operators)
To birth this difficult decision, it could help have an open repository with a robust suite of canonical examples written in Swift today, with people contributing branches or folders for the different approaches. That could be also be a starting-point for compiler test suite.