<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">I agree that being explicit is nice and I also like to use `guard`.</div><div class=""><br class=""></div><div class="">But according to my observation, usually it is easier to make mistakes if we choose to use `guard`.</div><div class=""><br class=""></div><div class="">Let me give you a fake real world example.</div><div class=""><br class=""></div><div class="">With `guard`, you need to be really careful when you want to add new expression (people usually will add to the end of the function).</div><div class=""><br class=""></div><div class="">```</div><div class="">func updateCell(cell: Cell, data: CellData) {</div><div class=""> cell.label.text = data.title</div><div class=""> guard let imageName = data.imageName else { return }</div><div class=""> cell.sublabel.text = cell.humanize(imageName)</div><div class=""> guard let image = UIImage(named: imageName) else { return }</div><div class=""> cell.addBackgroundImage(image)</div><div class=""> // Let's say we changed the design and added a new heading that depends on image name</div><div class=""> cell.heading = String(imageName.characters.first) // This won't be called if image is nil!</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">With `if let`, it is really hard to read. This will become more complicated if we add more attributes to cell.</div><div class=""><br class=""></div><div class="">```</div><div class="">func updateCell(cell: Cell, data: CellData) {</div><div class=""> cell.label.text = data.title</div><div class=""> if let imageName = data.imageName {</div><div class=""> cell.sublabel.text = cell.humanize(imageName)</div><div class=""> if let image = UIImage(name: imageName) {</div><div class=""> cell.addBackgroundImage(image)</div><div class=""> }</div><div class=""> cell.heading = String(imageName.characters.first)</div><div class=""> }</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">With the proposed syntax:</div><div class=""><br class=""></div><div class="">```</div><div class="">func updateCell(cell: Cell, data: CellData) {</div><div class=""> cell.label.text = data.title</div><div class=""> let imageName = data.imageName // imageName is optional</div><div class=""> cell.sublabel.text = cell.humanize(imageName?)</div><div class=""> let image = UIImage(named: imageName?) // image is optional</div><div class=""> cell.addBackgroundImage(image?)</div><div class=""> cell.heading = String(imageName.characters.first?)</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class=""><div class="">This is really easy to read. And everything works correctly.</div><div class=""><br class=""></div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Aug 16, 2016, at 12:43 AM, David Rönnqvist <<a href="mailto:david.ronnqvist@gmail.com" class="">david.ronnqvist@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><br class="Apple-interchange-newline">On 15 Aug 2016, at 15:29, Justin Jia via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">IMO `if x? { }` is not a lot shorter than `if let x = x`.</div><div class=""><br class=""></div><div class="">The problem with `if let` is, you need to explicit specify { } and call the function inside it. It is good for being explicit, but sometimes you ended up with something like this:</div><div class=""><br class=""></div><div class="">```</div><div class="">/* code 1 */</div><div class="">if let x = x, let y = y {</div><div class=""> / * code 2 */</div><div class=""> let z = foo(x, y)</div><div class=""> if let z = z {</div><div class=""> bar(z)</div><div class=""> }</div><div class=""> / * code 3 */</div><div class="">}</div><div class="">/* code 4 */</div><div class="">```</div><div class=""><br class=""></div><div class="">I would like to use guard if possible, but guard will force you to leave the entire function.</div><div class=""><br class=""></div><div class="">```</div><div class="">/ * code 1 */</div><div class="">guard let x = x, y = y else { return }</div><div class="">/* code 2 */</div><div class="">/ * some code */</div><div class="">guard let z = foo(x, y) else { return }</div><div class="">bar(z)</div><div class="">/ * code 3 */ // note: code 3 and code 4 won’t execute if x, y, or z is nil!</div><div class="">/ * code 4 */ </div><div class="">```</div><div class=""><br class=""></div><div class="">What I really want is some like this:</div><div class=""><br class=""></div><div class="">```</div><div class="">/ * code 1 */</div><div class="">let z = foo(x?, y?)</div><div class="">/ * code 2 */</div><div class="">bar(z?)</div><div class="">/ * code 3 */ // note: code 3 and code 4 will still execute even if z is nil!</div><div class="">/ * code 4 */</div><div class="">```</div><div class=""><br class=""></div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">The fact that this variant and the guard variant doesn’t do the same thing stands out to me. The if-let and guard variants while being more verbose is also very explicit about the control flow. While reading that I can fully understand under what circumstances code 3 and 4 will be executed. This sugar would be more equivalent to this (below), which I’m not sure if everyone would expect it to be. I can see people being surprised that code 3 and 4 was executed, especially if calling `bar` had some side effects that either code 3 or 4 was relying on.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">/ * code 1 */<br class="">let z = x.flatMap { </div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> x in y.flatMap { </div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> y in foo(x, y)</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""> }</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">}<br class="">/ * code 2 */<br class="">let _ = z.flatMap { z in bar(z) }<br class="">/ * code 3 */ // note: code 3 and code 4 will still execute even if z is nil!<br class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">/ * code 4 */</div><div class=""><br class=""></div></div></div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">IMO, this is much easier to read.</div><div class=""><br class=""></div><div class="">Sincerely,</div><div class="">Justin</div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Aug 15, 2016, at 7:05 PM, Haravikk <<a href="mailto:swift-evolution@haravikk.me" class="">swift-evolution@haravikk.me</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 15 Aug 2016, at 08:02, Justin Jia via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="">Hi!<br class=""><br class="">I don’t know if this has came up before. I tried to search though the mailing list but didn’t find any related threads.<br class=""><br class="">This is purely a syntactic thing (which I know it’s the lowest priority for Swift 4), but I think it’s an important one.<br class=""><br class="">Let’s say we have a struct with a function:<br class=""><br class="">```<br class="">struct Foo {<br class=""> func bar(x: Int)<br class="">}<br class="">```<br class=""><br class="">We can use optionals:<br class=""><br class="">```<br class="">let foo: Foo? = nil<br class="">let x = 1<br class="">foo!.bar(x: x) // Able to compile, but will cause runtime error<br class="">foo?.bar(x: x) // Able to compile, and won't cause runtime error<br class="">```<br class=""><br class="">However:<br class=""><br class="">```<br class="">let foo = Foo()<br class="">let x: Int? = nil<br class="">foo.bar(x: x!) // Able to compile, but will cause runtime error<br class="">foo.bar(x: x?) // Won't compile<br class="">```<br class=""><br class="">I propose that we should allow `foo.bar(x: x?)`, which should be equivalent to:<br class=""><br class="">```<br class="">if let x = x {<br class=""> foo.bar(x: x)<br class="">}<br class="">```<br class=""><br class="">What do you think?</div></div></blockquote><br class=""></div><div class="">I like the intent behind this, but personally I think it's not clear enough. For me, putting the statement in a conditional as you've shown is the better solution, as it's a lot clearer exactly what's going on. Putting a question mark on a variable makes it look like something specific to that variable, rather than preventing the entire statement from executing.</div><div class=""><br class=""></div><div class="">There may be some alternatives though, for example, what about a shorthand for the conditional like so:</div><div class=""><br class=""></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>if let x? { foo.bar(x: x) }</font></div><div class=""><font face="Monaco" class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>if x? { foo.bar(x: x) } // even shorter?</font></div><div class=""><br class=""></div><div class="">But in general, I think it's best to be explicit about the entire statement being optional, which the conditional does but a postfix on a variable doesn't to the same degree.</div></div></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div></blockquote></div><br class=""></div></div></body></html>