<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Nov 3, 2017, at 11:45 AM, Mike Kluev &lt;<a href="mailto:mike.kluev@gmail.com" class="">mike.kluev@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">On 3 November 2017 at 18:08, Adam Kemp <span dir="ltr" class="">&lt;<a href="mailto:adam_kemp@apple.com" target="_blank" class="">adam_kemp@apple.com</a>&gt;</span> wrote:<br class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><br class=""><div class=""><div class="">1. You end up with a whole section of type aliases at the top of the file,</div></div></div></blockquote><div class=""><br class=""></div><div class="">i'm putting those in a separate Platform.swift file</div><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class="">and as you read the file it’s hard to understand what those types actually represent.</div></div></div></blockquote><div class=""><br class=""></div><div class="">in the example above "View" - a very similar concept between macOS and iOS/tvOS/watchOS.</div><div class="">in case of doubts - command click is always at the finger tips.</div><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class="">Which methods are you actually allowed to use? What should code completion show you?&nbsp;</div></div></div></blockquote><div class=""><br class=""></div><div class="">autocomplete shows the relevant methods on each platform correctly.</div><div class=""><br class=""></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class="">2. The type alias is only useful when the naming of the methods/properties is identical and the sequence of calls you have to make is identical, which very often isn’t the case. You end up needing conditional compilation anyway for cases where you only need to make a call on one platform, or where the method you have to call is named slightly different or takes different arguments.</div></div></div></blockquote><div class=""><br class=""></div><div class="">if the differences are minute i'm creating my own extension methods to make the difference non existent.</div><div class=""><br class=""></div><div class="">example:&nbsp;layer is optional on OSX and non optional on iOS. the difference is minute and i can make this difference non existent, e.g. by:</div><div class=""><br class=""></div><div class=""><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo; color: rgb(52, 149, 175);" class=""><span style="color:rgb(4,51,255)" class="">extension</span><span style="" class=""> </span>UIView<span style="" class=""> {</span></div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo;" class="">&nbsp; &nbsp; <span style="color:rgb(4,51,255)" class="">var</span> viewLayer: <span style="color:rgb(52,149,175)" class="">CALayer?</span> {</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo;" class="">&nbsp; &nbsp; &nbsp; &nbsp; <span style="color:rgb(4,51,255)" class="">return</span> <span style="color:rgb(52,149,175)" class="">layer</span></div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo;" class="">&nbsp; &nbsp; }</div><div style="margin: 0px; font-stretch: normal; font-size: 11px; line-height: normal; font-family: Menlo;" class="">}</div></div><div class=""><br class=""></div><div class="">and a similar thing on OSX, and afterwards i have single API on both platforms with no differences.</div><div class=""><br class=""></div><div class=""><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class="">You end up needing conditional compilation anyway for cases where you only need to make a call on one platform, or where the method you have to call is named slightly different or takes different arguments.&nbsp;</div></blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class="">&nbsp;</div></blockquote><div class="">&nbsp;</div></div><div class="">i rarely have to use conditional compilation and even when have to do so i normally hide it inside the relevant "utility" extensions, from then on i don't see anything "conditional" within the normal app sources.</div><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class="">Out of the strategies I’ve seen used for cross-platform code this one was the most frustrating to work with in my experience.</div></div></div></blockquote><div class=""><br class=""></div><div class="">quite the contrary to me - the best possible experience with such an approach (during many years of experience ftm)</div></div></div></div></div></blockquote><div><br class=""></div><div>All I can say is, again, I’ve worked with code that plays these tricks, and I found it much harder to deal with than the code that used partial classes. You’re using all the tricks you can to make it work, but in my experience those tricks add up to a code base that is harder to work with and harder to understand and more brittle than the alternative approach I described. The tricks are part of what makes it confusing. At the risk of sounding presumptuous, I think if you could actually try the other approach (i.e., if we actually had partial classes that work like in C#) you would likely agree. Unfortunately it’s hard to do that comparison when you haven’t tried both approaches in real world situations.</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">&nbsp;</div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><span class="gmail-"><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><div class="">My argument is that there should be no ledger in the first place. IMO you haven’t made the case for that requirement.</div></div></div></blockquote></div></div></div></blockquote></span></div></div></blockquote><div class=""><div class="">the real-world example would be:</div><div class=""><br class=""></div><div class="">case 1. you have a single page of paper on hands saying: "partial contract A. continued elsewhere. Blah, blah". you look around and within a multitude of papers on the table you managed to find another sheet of paper with "partial contract A. continued elsewhere.&nbsp;Blah, blah". in order to find the whole thing you will have to look in all papers on your table, then in the shelve and then in the whole building (module boundaries)</div></div></div></div></div></div></blockquote><div><br class=""></div><div>This is not how it works in practice. In practice the files are right next to each other with similar names. It would be more like having “to be continued” at the end of a book sitting right next to another book with the same name plus “Volume 2”. I think you would know where to look.</div><div><br class=""></div><div>If you work with people who can’t follow conventions and would try to extend partial classes from random places then I’m sorry. :)</div><div><br class=""></div><div>You may notice that this has echoes to our earlier conversation where I was on the other side of a very similar disagreement about extensions. I argued that extensions would lead to confusion because they can be thrown anywhere, and someone pointed out that there are file naming conventions for that. I think this is different because extensions are very often included in random files where they are most convenient. They have a different meaning and a different use case that I think encourages their use in files that are not named after the class they’re extending.</div><div><br class=""></div><div>Partial classes aren’t intended to be used that way so it really never makes sense to have a partial class implementation in a file that is not dedicated specifically to that partial class implementation. That would raise red flags during code reviews. It’s a very simple rule to follow: if you see “partial class Foo” then the file name better start with “Foo”.</div><div><br class=""></div><div>If I thought it made sense to have the compiler somehow enforce the file naming scheme for partial classes I would propose doing that, but it really doesn’t make sense. I don’t think the compiler works that way, and that’s probably for the best.</div><div><br class=""></div><div>As for cross-module usages, absolutely under no circumstances do I want this to be supported across modules. I don’t think either of our approaches would work that way so that’s probably not something we need to debate.</div><div><br class=""></div><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space" class=""><div class=""><span class="gmail-"><blockquote type="cite" class=""><div dir="ltr" class=""><div class="gmail_extra"><div class="gmail_quote"><div class="">i mean this:</div><div class=""><br class=""></div><div class="">class MyView: UIView {</div><div class="">&nbsp; &nbsp; optional part Drawing</div><div class="">}</div><div class=""><br class=""></div><div class="">part Drawing of MyView { // **** forgot to include this into target</div><div class="">&nbsp; &nbsp; override func drawRect(...) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; .....</div><div class="">&nbsp; &nbsp; }</div><div class="">}</div><div class=""><br class=""></div><div class="">the app compiles but doesn't work correctly.</div></div></div></div></blockquote><div class=""><br class=""></div></span><div class="">That example doesn’t make any sense.</div></div></div></blockquote><div class=""><br class=""></div><div class="">i don't see why (and I am not talking about cross platform code at this point). i have instances like these implemented via extensions in a day to day code. the split of the class into files was done merely for organising purposes, to keep file size manageable.</div></div></div></div></blockquote><div><br class=""></div><div>I meant that if you’re doing cross-platform coding using partial classes as I’ve described then the scenario you described is an example of doing things the wrong way. What I’m saying is there is a way of doing things with partial classes in C# where if you follow the pattern then you can’t run into those problems because you will get build errors. If you don’t follow the pattern then bad things could happen, just like with so many other things in programming. There are practices that lead to brittle code and practices that lead to robust code. Using partial classes in C# has best practices that avoid those problems, while at the same time allowing for people to work very efficiently.</div><div><br class=""></div><div>Your ledger idea might theoretically prevent some of those bad things from happening, but at the expense of making the whole thing unusable for this use case. That’s not a good trade off.</div></div></body></html>