<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">The “inout” modifier is probably one of the main culprits here. While it is certainly very convenient to use (and I personally use it a lot), its very existence seems to have some downsides that restrict Swift design decisions.<div class=""><br class=""></div><div class="">Maybe there is a solution though: make “inout” distribute over elements of a tuple, something that actually already happens. The following code compiles and works in Xcode 9 beta:</div><div class=""><br class=""></div><div class="">———</div><div class=""><br class=""></div><div class="">protocol Incrementable {<br class=""> mutating func addOne()<br class="">}<br class=""><br class="">func incrementFirstAndPrintSecond1<A: Incrementable,B>(tuple: inout (A, B)) {<br class=""> tuple.0.addOne()<br class=""> print(tuple.1)<br class="">}<br class=""><br class="">extension Int: Incrementable {<br class=""> mutating func addOne() {<br class=""> self += 1<br class=""> }<br class="">}<br class=""><br class="">var m1 = (42,"this will be printed")<br class="">incrementFirstAndPrintSecond1(tuple: &m1) /// prints "this will be printed"<br class="">print(m1.0) /// prints "43"<br class=""><br class="">func incrementFirstAndPrintSecond2<A: Incrementable,B>(first: inout A, second: inout B) {<br class=""> first.addOne()<br class=""> print(second)<br class="">}<br class=""><br class="">var m21 = 42<br class="">var m22 = "this will be printed"<br class="">incrementFirstAndPrintSecond2(first: &m21, second: &m22) /// prints "this will be printed"<br class="">print(m21) /// prints "43"<br class=""><br class="">func applying1<A>(value: A, f: (inout A) -> ()) -> A {<br class=""> var m = value<br class=""> f(&m)<br class=""> return m<br class="">}<br class=""><br class="">let x1 = applying1(value: 42) { (a: inout Int) in<br class=""> a.addOne()<br class="">}<br class="">print(x1) /// prints "43"<br class=""><br class="">func applying2<A,B>(value: (A,B), f: (inout (A,B)) -> ()) -> (A,B) {<br class=""> var m = value<br class=""> f(&m)<br class=""> return m<br class="">}<br class=""><br class="">let x2 = applying2(value: (42,"OK")) { (tuple: inout (Int,String)) in<br class=""> tuple.0.addOne()<br class="">}<br class="">print(x2) /// prints "(43, OK)"<br class=""><br class="">func applying3<A,B>(first: A, second: B, f: (inout A, inout B) -> ()) -> (A,B) {<br class=""> var m1 = first<br class=""> var m2 = second<br class=""> f(&m1,&m2)<br class=""> return (m1,m2)<br class="">}<br class=""><br class="">let x3 = applying3(first: 42, second: "OK") { (a: inout Int, b: inout String) in<br class=""> a.addOne()<br class="">}<br class="">print(x3) /// prints "(43, OK)"<br class=""><br class="">———</div><div class=""><br class=""></div><div class="">As you can see, a function with a single inout tuple corresponds to a function with two inout arguments. This means that in a hypothetic model with isomorphic tuples and arguments, a tuple could be used in place of a subset of the arguments only if:</div><div class=""><br class=""></div><div class="">- none of the arguments in the subset is inout;</div><div class="">- all the arguments in the subset are inout, thus the tuple is to be considered wholly inout;</div><div class=""><br class=""></div><div class="">Obviously the subset could include all arguments. This way we could take 100% advantage of tuple isomorphism for functions with no inout arguments (thus, most of them), and still gain something where inout is there.</div><div class=""><br class=""></div><div class="">———</div><div class=""><br class=""></div><div class=""> About your second point, I’m definitely not an expert in type checkers, but if every composition of tuples was always reduced to simplest flattened form, maybe the type checker could have an even easier time. What I mean is that, because something like ((A,B),(C,(D,E))) could be considered equivalent to (A,B,C,D,E), the compiler could reduce the first tuple to the second, and then check the latter against a potential consumer. It seems to me that structuring-destructuring exists as a problem only when we need to differentiate isomorphic tuples just by their structure: without this need, the problems goes away. </div><div class=""><br class="">Still, I don't have a deep enough understanding of how the compiler works to analyze this second problem in full. And as I said in my first post, if the distinctions are truly important at the compiler level, and there are impossible challenges to overcome in finite space and time to acquire a feature like tuple isomorphism, then there's not much to do about it. My suggestion is simply that, if we need to define some workarounds, we should take into account the fact that at the usage point tuples with same content are equivalent, and a potential new model for the SE-110 aftermath should at least consider this idea.</div><div class=""><br class=""></div><div class="">Thanks</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Elviro<br class=""><br class=""><div class=""><div class=""><div><br class=""><blockquote type="cite" class=""><div class="">Il giorno 25 giu 2017, alle ore 06:28, David Hart <<a href="mailto:david@hartbit.com" class="">david@hartbit.com</a>> ha scritto:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="content-type" content="text/html; charset=utf-8" class=""><div dir="auto" class=""><div class="">I think the Core Team initially (pre-Swift 1) wanted to make tuples and arguments isomorphic. But that model has many downsides which forced us to backtrack from that model:</div><div class=""><br class=""></div><div class="">• Modifiers on arguments (like inout) would force us to introduce them as part of the type-system on tuples, which makes for a messy model,</div><div class="">• Tuple structuring and de-structuring greatly complicates the work of the type-checker.</div><div class=""><br class=""></div><div class="">The decision was made early in the Swift-evolution timeframe to strip what was left of the old model. It's much too late to backtrack now. Even if one wanted to, you'd have to address the original concerns that drove us to the current model.</div><div class=""><br class=""></div><div class="">David.</div><div class=""><br class="">On 24 Jun 2017, at 21:12, Djura Retired Hunter via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div class=""><div class=""><blockquote type="cite" class=""><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 Jun 23, 2017, at 7:46 AM, Elviro Rocca 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="">It's probably late to just casually add a couple of cents to a discussion that has been going for so long, but it seems to me that from a user standpoint, that uses types to structure their programs and define logic and relationships, isomorphic types should be considered the same by the compiler. The added burden of distinguishing between, to say, a function that takes 2 arguments and one that takes a single tuple of two arguments doesn't seem useful at all, at least from the standpoint of the types involves. All the rest, like named parameters or tuple labels, are just really about style and convenience, but isomorphic types, while not strictly equal (the very concept of "equal" is in fact a huge deal in abstract mathematics) are for all means "equivalent" for the world-modeler.<br class=""></div></div></blockquote></div><br class=""><div class="">Doesn’t seem useful?…</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Monaco" class="">let myFunc: (MyTypeAlias) -> Int = /* … */</font></div></blockquote><div class=""><br class=""></div><div class="">Does the function pointer have a single parameter? Or does it trigger Super-Secret Tuple-Destructing mode and actually indicate two parameters? My secret unknown single type should always be a single type, no matter what kind of type it is.</div></div></div></blockquote></div></div></div></div></div></blockquote><br class=""></div><blockquote class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; margin: 0px 0px 0px 40px; border: none; padding: 0px;"><font face="Monaco" class="">(A, B, C) ((A, B), C) (A, (B, C))</font></blockquote><div class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">You’re saying partitions aren’t important. I’m saying that they are. Even though the second two tuples above are implemented like the first, I wouldn’t want them to be indistinguishable from an user’s standpoint. I wouldn’t want my two-argument functions magically become a three-argument one due to implementation details.</div></blockquote><div class=""><br class=""></div><div class="">Why are partitions, just partitions, of tuples important? And why should anybody even consider writing a function that takes a tuple as "single argument" instead of just taking two arguments?</div><div class=""><br class=""></div><div class="">The difference between the following two functions is completely meaningless from a user standpoint:</div><div class=""><br class=""></div><div class="">func x<A,B> (tuple: (first: A, second: B))</div><div class="">func y<A,B> (first: A, second: B)</div><br class=""><blockquote type="cite" class=""><div class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div><div class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;">My previous example will stay an one-argument function for any non-tuple type behind the alias. But if it’s a tuple type, my assumption breaks because your rules would ban tuples from being first-class types.</div><div class="" style="font-family: Helvetica; font-size: 13px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><br class=""></div></blockquote></div><div class=""><br class=""></div>What? Why my rules say that tuples are not first class types? I'm just saying that equivalent tuples should be allowed as arguments for functions that take equivalent tuples as arguments.<div class=""><br class=""></div><div class="">You examples shows a function that takes a "MyTypeAlias" as input:</div><div class=""><br class=""></div><div class="">- if MyTypeAlias is an alias for, say, a "Person", that function can be called with an instance of "Person"</div><div class="">- if MyTypeAlias is an alias for (Int,Int), that function can be called with a couple of Int</div><div class=""><br class=""></div><div class="">What's the matter?</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">Elviro</div><div class=""><div class=""><br class=""></div></div></div></blockquote><blockquote type="cite" class=""><div class=""><span class="">_______________________________________________</span><br class=""><span class="">swift-evolution mailing list</span><br class=""><span class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a></span><br class=""><span class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br class=""></div></blockquote></div></div></blockquote></div><br class=""></div></div></div></body></html>