let icon: IconImage = do {
let image = NSImage(
systemSymbolName: "something",
accessibilityDescription: nil)!
let preferredColor = NSColor(named: "AccentColor")!
IconImage(
image,
isSymbol: true,
isBackgroundSupressed: true,
preferredColor: preferredColor.cgColor)
}
I think is a good addition to the language, and adds very handy way for small portions of code and assign it directly to a constant or variable. I'm totally in favor of this one
The optionality of the return for regular functions, I'm not in favor of this. I think it just add a new complexity layer about how to read and write Swift functions, return has always been there (at least for multiline functions), it might not be perfect, but has been a rule that has given a consistent way about where a function exits, adding the optionality to this, it will just create a lot new and existing codebases with mixing usages, which will break a "simple" rule that everyone had to follow. Maybe in the early years of Swift this idea might have sound quiet right, when the language was younger and an addition like this would be more easier to digest and adopt by everyone, but after 10 years, with the amount of Swift users, documentation, blogs, etc... this could cause more disruption to existing and new Swift users. Swift is an already mature languages, maybe some existing functionality might not be perfect but it works, adding more rules on top of them just adds more complexity to an already beautiful but complex language. Sometimes maybe it's ok to just pay the price of not having something rather than add it later.
I think this proposal can bring some improvements to the language ergonomy. When I used something like this in languages like Ruby or Elixir, and then came back to Swift, having to type returns in some scenarios felt unnecessary.
Considering many many devs working in teams where these kind of bugs would be carnage (good luck with an MR/PR review without running and stepping through the code… and even then…) on top of footguns even for the smaller indie devs… I really honestly do not get how such a minor character typing win justifies worse readability and potential for more bugs to seep through.
I cannot understand, my fault not yours, how you are in support of this despite admitting to this issue…
IMHO the entire bit of expression statements (as opposed to {…}() closures that offered the same behaviour without this growing list of concerns / proposals to keep refining / improving support… I asked a few times without any satisfying answer over personal distaste of braces and parentheses, but I am still curious of what adding this feature brought that was impossible to do with {…}() expressions) was a bit of a mistake to bring into the language to begin with.
Over the last few years I think we have seen a lot of powerful but more and more complex syntax (as the language tries to be everything to everyone, from embedded systems, to phone and desktop apps, to shell scripts, to server apps and distributed systems, overlapping with the kind of data race and memory safety approaches as rust, direct compatibility with Java and C++, etc…) with syntactic sugar to make it easier to use but subtly adding more and more edge cases and/or complexity if you found yourself to need to know what the syntactic sugar code actually did and what it implied.
Overall, unpopular opinion here, we should have never allowed to omit return anywhere nor to remove self. I have not seen real evidence the pros overweighted the cons (nor opportunity cost evaluation of all the work that it took the community to get here and the work still needed).
We created our own can of worms of consistency / opened Pandora’s box of consistency the moment we valued writing code over reading code IMHO :(…
We have such an easy time with semicolonlessness today, so maybe this is already a solved problem, but an odd case of new ground might be:
Your final expression is a static member of a type the compiler has already determined. You write it with a bare leading dot operator. But it's parsed as a method call or property access as part of the prior line. You add the return keyword to clarify, but 1. now you have to add the return keyword to all the other final lines in your other switch cases, or 2. you just incorrectly returned from within a do expression that was only supposed to initialize a local variable.
Some folks are saying the readability loss is not worth the small benefits. I would still find this readable, but I need to not be wrong about what the compiler will think I mean, or it will have a writability problem too.
It about not introducing closures to compensate lack of expressiveness. E.g. “return” in a closure does not return from the original context. And it feels cumbersome.
My short comment was just about not to refuse a convenient notation just because there is a little learning or “getting used to” involved.
Fair enough, but is it really even convenient if it just adds more footguns / edge cases to the language and/or even more sharp edges we will need more work and more proposals to smooth out? All this work by the community is not free / could be spent on other things…
I have no objections to allowing the last value to be the return/expression value, but I’m vehemently against forcing that on those of us that prefer more explicit control flow for these new multi-statement expressions. There are very clearly quite a few of us that strongly prefer that style, please add some new keyword so that the new if/switch/do expressions can be palatable without having to add comments like:
That‘s exactly the question (without the “just”). I think there are very valid arguments for both sides, you choose what hurts less For me, convenience wins in the long run (if it does not hurt too much otherwise). Reduce the syntactical burden for complex but “conventional” code, avoid difficult edge cases.
While I’m a fan of do expressions as a replacement for these immediately executed closures, overall I’m -1 on this precisely for the readability problems stated in this thread.
I really like using implicit returns in short closures or functions, but I don’t see the appeal of using this in longer pieces of code. I occasionally come across an if/else or switch expression where I want to change one branch to have multiple statements and am disappointed that there’s no good way to do that right now, but this proposal is just way too much for my taste with all the ambiguities and edge cases it introduces (result builders, loops, longer functions, …).
I must admit that I don’t have experience with using implicit returns in other languages, but I see that other people in this thread who do like this feature. So maybe I’m missing something here, but I don’t get what the benefit is of making the return keyword optional at the cost of making the code harder to read. If it’s just to make a piece of code shorter or do less typing, then that makes sense to me if that piece of code really is short, like a one-line expression (which Swift supports). If it’s long, like a 10+ line function, then not typing those few characters won’t buy you much, but you lose readability. I think fixing the middle ground between those is desirable, but this pitch overshoots, IMHO.
Note that I’m not saying that I’m in favor of introducing then for these cases or that implicit return for multi-statement blocks should only work in if/else and switch expressions and not in functions and closures. Just that this is too much for my taste and I fear for the readability of Swift code if this is accepted.
I have now mixed feelings about this proposal. I especially don't like returning values from functions without the explicit return.
The good thing is that the proposal does not outlaw old way of doing things. However, I am just curious how much extra burden this proposed feature would put on the compiler.
Now, we have two kinds of if, two kinds of switch, and two kinds of do: plain old compound-statement kind, and value yielding compound-statement kind.
For example:
Plain old if statement:
if ... {
...
}
else {
...
}
Value yielding if statement:
let u = if ... {
...
2
}
else {
...
3
}
Could a compiler engineer shed some light on this to educate?
Having some experience with large Kotlin project, I also really dislike this feature. While it may looks nice on single line block, it become very confusing on larger blocks.
It even sometime causes compiler error when a closure that must return void (Unit) ends by a function call that has a return value and the compiler infer that the closure return type is the same type than this last statement.
The worst is that IntelliJ (and so Android Studio) is encouraging use of implicit return everywhere it can.
That to me seems like one of the biggest specific readability issues. If the last statement is a function, then you may just have to know that it returns a value and therefore that value is being implicitly returned. This is technically true with current implicit return syntax for a one-line function, but then you have the return type right in front of you. In a longer function that context can get lost.
I'm still deciding what to think of a Void function where the last statement is, say, a @discardableResult function. I guess the compiler should just assume the result should be discarded, but it also seems weird that I can change the return type of the outer function to match and suddenly I already have a return value. But I guess that's already true in a one-line function.
If your function body doesn't fit on a single screen so much that function signature is not immediately visible, wouldn't that be a strong signal that such function needs to be refactored and broken down into multiple functions in the first place for readability?
In other words, you already need to keep some context in your head when reading function's body: whether a given variable is a local declaration shadowing an argument, a property on self or is an actual argument, whether a function is throwing or non-throwing, async or sync etc. If not having that context in front of you is a concern, it would be a concern for any of those aspects of the function, not just implicit returns. But it seems to me this is not a philosophy Swift has taken so far, given that it endorses scoped shadowing and implicit self.
I don’t think this is a practical metric. Screen heights vary, and some code is complex enough when read linearly that it would absolutely not benefit the reader to spread it around.
Sure, but if you don't keep that context in mind, don't you already have to go to the top of the screen to check if a given variable is a local declaration, a function argument, or a property on self?
For code with implicit returns following API design and naming guidelines, it's quite obvious that something other than empty tuple is going to be returned.
And if you got it wrong you'd get a compiler error anyway. Fortunately we don't have to deal with a dynamically typed language that will just swallow the error, not even emit a warning, and fail on user's side in the end.