[swift-evolution] continuations - "extensions on steroids" idea

Adam Kemp adam_kemp at apple.com
Fri Nov 3 16:36:46 CDT 2017


> On Nov 3, 2017, at 11:45 AM, Mike Kluev <mike.kluev at gmail.com> wrote:
> 
> On 3 November 2017 at 18:08, Adam Kemp <adam_kemp at apple.com <mailto:adam_kemp at apple.com>> wrote:
> 
> 1. You end up with a whole section of type aliases at the top of the file,
> 
> i'm putting those in a separate Platform.swift file
>  
> and as you read the file it’s hard to understand what those types actually represent.
> 
> in the example above "View" - a very similar concept between macOS and iOS/tvOS/watchOS.
> in case of doubts - command click is always at the finger tips.
>  
> Which methods are you actually allowed to use? What should code completion show you? 
> 
> autocomplete shows the relevant methods on each platform correctly.
> 
> 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.
> 
> if the differences are minute i'm creating my own extension methods to make the difference non existent.
> 
> example: 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:
> 
> extension UIView {
>     var viewLayer: CALayer? {
>         return layer
>     }
> }
> 
> and a similar thing on OSX, and afterwards i have single API on both platforms with no differences.
> 
> 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. 
>  
>  
> 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.
>  
> Out of the strategies I’ve seen used for cross-platform code this one was the most frustrating to work with in my experience.
> 
> quite the contrary to me - the best possible experience with such an approach (during many years of experience ftm)

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.

>  
>> My argument is that there should be no ledger in the first place. IMO you haven’t made the case for that requirement.
> 
> the real-world example would be:
> 
> 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. 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)

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.

If you work with people who can’t follow conventions and would try to extend partial classes from random places then I’m sorry. :)

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.

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”.

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.

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.

>> i mean this:
>> 
>> class MyView: UIView {
>>     optional part Drawing
>> }
>> 
>> part Drawing of MyView { // **** forgot to include this into target
>>     override func drawRect(...) {
>>         .....
>>     }
>> }
>> 
>> the app compiles but doesn't work correctly.
> 
> That example doesn’t make any sense.
> 
> 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.

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.

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171103/ea0c3771/attachment.html>


More information about the swift-evolution mailing list