Alexis Gallagher - Protocols with Associated Types

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
I think the rest of my body is used to the very small time change from San Francisco but some reason my throat isn't so just bear with me hello everybody I'm really excited to be talking about this this is this is a subject that I've been looking into further and further and as I was saying to someone just outside it feels a little bit like where there's a little piece of string and you pull on it and you're like I'm gonna get to the end of this thing in a minute then I'll have my talk all together and I'll understand it it'll be clear and then you're like okay okay there's more string here okay like oh my god where does this end so I'm really excited I've had the chance to think about this and I hope this makes it a bit clearer so I'm talking today about protocols with associated pipes and how they got that way maybe because we can't be exactly sure now protocols with associated types like why is this an interesting one to get into I think first reason is that they seem to cause a lot of pain if you look at what you see on the internet you see a lot of reactions a bit like this like yes I'm using value types I'm using Swift this is awesome oh I can't subclass no problem using protocols and swift protocols all right I need to implement equatable because you know equality it comes up a lot and then I am right away you get this error a protocol whatever you're working with it only be used as a generic constraint because itself or associated type requirements you hit this and this is what you hit as soon as you're working with a protocol with associated types and it first you see this in your like what like what is this why is this happening is there okay is there a quick fix is there a way I can go in and fix it quickly and there's not this is this is a subsequent something that comes it comes up and often requires you to radically restructure your code and that you're not going to be using protocols in the way you thought you were using them you can own what it's saying is you can only use it as a generic constraint which basically means you can't use them for variables right that's confusing because normal protocols work something like this this is kind of what we were all taught in OB school right you got your protocol then you have your type here it's a struct but it could be you know it could be a class whatever and then you can define a variable proto var which has the type of the protocol right because now and I'm creating an instance of my struct or my class whatever foo because it conforms to because it adopts that protocol I can assign it into the protocol that's great and then in downstream code I know that I'm working with something that's a my proto I can forget what it originally was maybe someone handed it to me and all I know is that it's my proto so I know what its interface is I can call methods on it no problem right but in protocols with associated types or with associated pain that's not what happens as soon as you have a protocol that associated type which you're going to have as soon as you add a type alias declaration inside the protocol definition things are going to work differently the type alias declaration is declaring a requirement every adoption of this protocol needs to say what that type alias means so here's an adoption of the protocol for my struct foo I'm saying foo is adopting the protocol in my proto and for its adoption of my proto the my associated type type let's say it's integers meeting requirement and now when I try to write that code at the bottom which is probably the kind of code that I used to write protocols every day of my life you get there now oftentimes people aren't going to encounter this first when they are adding a associate of type explicitly as I mentioned usually the first place people run into this place the first place I did is when you're doing anything that has equality but what's the connection there I'm not 100% sure of this but my understanding from staring at this for a long time is that basically anytime you use self with a capital S self is kind of like a built-in Associated type it's sort of a special associated type that's predefined to be spelled self and whenever you're adopting a protocol that uses itself it's predefined that the adopting type is equal to the self alias or the self type name so you know if we were defining equatable for our self it would be a bit something like this you'd have something myself and the adopting type would have to be the one set equal to myself and that's exactly the situation that we have before that's why I think that error covers those two cases you're using self or you're using an Associated type the reason those things go together is because every time itself is actually just a special case of dissociated types that's built in because it's a commonly needed one and again as soon as you say something's equatable you can't put it in a variable Oh can't be done you get an error um so that says a bit of surprise the first time you encounter it you know what does that mean I first of all it means that particles with associated types are different enough that I suggest we stop calling them protocols with associated types also my tongue is just going to wear out if I have to say that 100 times during this talk so that's why I call them Pat's makes them seem much more friendly approachable protocol associated type Pat's and Pat's are a bit weird or at least they seem that way when you first run into them so why why are they like this and what's the best way to make use of them is that saying that you know when you understand uh you forgive right so I wanna I wanted to understand where protocols with associated types were coming from in order to forgive them for being a bit frustrating this is a journey to try to understand Pat's I've got four questions that I want to address in this talk and I will I'll feel good if I feel like I've given partial answers at least to all of these and made this bit clearer so first question to think about is just how our paths weird like let's really name exactly the ways in which they are surprising or frustrated then the second question is a deeper one why our password why were they made this way like what what's the trade-off that motivated producing these effects in order to produce some other kind of benefits what's what's the point of this like why they like this all the guys working on the Swift team very capable guys and gals I don't have any you know I'm not saying they're making a mistake they are they're they know more about this than I do so I just try to understand where they're coming from the third question is this the plan like the things that are a bit frustrating about protocols and associated types is this how it's supposed to be this house indefinitely or is this kind of work in progress stuff I think that's a good one that's good what understand and then the last the last point is how to love them right how to forgive them and understand them and make the best use them let's dive in first just to quickly review how Pats are weird I'm going to name three aspects of the weirdness that I think are the key one so the first one like I mentioned is this one that they're only usable as generic constraints now when you think about it why is this weird this if you this rule excludes Pats from literally every single use of protocols as defined in Objective C literally and you know the proof of that is is quite simple Objective C lacked constraints right so in Objective C all of the protocols you used in Objective C none of those were being used as generic constraints hats can only be used as generic constraints there's literally no overlap QED right though yeah that's a little bit author called protocols but literally every single protocol you ever wrote before you could not write it with a pad second weirdness everywhere and so how's that expressed the effectiveness is that everywhere that you wanted to have a plain old protocol before you wanted to have something like this delegate is the fine with this protocol now in order to use a pad you need to have a generic constraint so now my bar delegate declaration let's suppose it's inside a class well now that class needs to be a generic class it needs to be generic with a type parameter T with a constraint protocol and then the delegate declaration gets the type parameter T so everywhere that I would have had a simple kind of protocol property I now need to have a generic context for it and so the effect of this is that now my whole class has become a generic class which maybe is not what I wanted maybe he's not what I was used to maybe it seems like a big change just in order to be using a path and the other aspect of this is that once you've done this okay now I'm using a pat instead of a plain old protocol but that little change did not get me exactly to where I was before because now I've lost dynamic dispatch and dynamic dispatch might have been the reason I was using a protocol to begin with so refresh here if that were a plain old protocol and I had an array of them right and that array of protocol objects if it was just plain old familiar protocols it could have had underneath a heterogeneous array of different kinds of types that were conforming to the same protocol object and then I just go through them and every one of them okay it's a protocol I don't know what's underneath it but I know it has this method foo and I call foo and then dynamic dispatch going to do food thing a if it's type a it's going to do food thing B if it's type B that's dynamic dispatch that's the subtype polymorphism that's do but once you make this change so that you're using a pat and then you're forced to do it in here at context the array that you get is not an array of proto objects it's actually an array of whatever the type is that adopts the protocol so you're forced into a uniform array but you no longer have dynamic dispatch you can no longer have a collection of delegates where all you know about them is that they all conform to Pat you've got a collection of delegates where they're all some single type that is obliged to perform that so you've lost a significant language feature by making the switch Pat's and that may have been the very feature you are depending on when you decided you wanted to use a protocol to begin with so this is this only usable as a generic constraint feature is genuinely restrictive and I think it's fair to be surprised especially because when you look at the docs and communication from Apple there's a lot of language that describes protocols as real types and Swift here in the Swift programming language book it says any protocol you create will become a fully fledged type for use in your code you can use a protocol in many places where other types are allowed parameter type return type type of a constant variable property type of items an array is dictionaries that actually a list of all the places that you cannot use a protocol position literally those are all the places you cannot use what which is I guess why they have the word many in there just to make it a bit ambiguous in the protocol oriented programming talk any type you name is a first class any type you can name as a first class citizen we talking about protocols so if you find this behavior of Pat's confusing if it surprises you a bit relax you your brain is functioning properly you should you should be confused by it I think now the third thing that's a bit weird about Pat's is the way the type alias keyword works so let me say a little bit about that and that's actually I think the natural entry for diving deeper into the topic and getting a sense of where they come from and how to understand them and appreciate them enjoy them so type alias there's two very distinct functions in the language right now the first function is anytime you're using a new time you use the identify or type alias outside of a pat it's really just a syntactic convenience it's just a way it's like type death it just gives you a opportunity to create a shorter and more meaningful name for what could be a kind of long and awkward type date I think it would be correct to say that it's not doing anything semantically it's just a syntactic convenience if you had a really great short-term memory you could go through and take all the type destined the type aliases and just air them out and replace them with the fully specified name it's not concealing anything or requiring anything or doing anything it's just saving saving your brain from having to keep track of a longer and a or opaque name but inside a protocol with associate type as I mentioned earlier IP Elise has done something to do something very different type alias is actually establishing a semantic requirement for adopting the protocols it's establishing the requirement that any type that adopts this protocol needs to implicitly or explicitly specify which type is associated with this type alias and that is interesting to think on type alias is in that case effectively defining a placeholder or an unknown type right so here's a protocol animal and every animal eat some kind of food and once they foods also a type but you know until I know which animal adopts I don't know what kind of food it is so I can say well there's some type called food but I don't know up food but I don't know yet and whatever type wants to be an animal it needs to have a function eat and that function and eat means you need to eat this this food type that it's your preferred food and this is a requirements defining role of the type aliases intriguing because it sounds a bit familiar doesn't it you look at this and you think well type alias the identifier that I name with the type alias it feels a lot like a generic type parameter or that's another case where we have syntax that specifies that we're introducing an identifier that will be a placeholder for a type that's not known yet and can be used throughout our definition so if I were defining a struct animal this is a generic over the parameter type parameter I could use food as the name of that parameter and then I could say okay yeah if I possess a specialization of animal on a particular type of food and that specialization eats that type of food but that leads to the question well all these things that are a lot about pat's is that because add so really under the surface or conceptually best understood as generic protocols in the same way that tie parameters are used for generic types so they're really just generic protocols with a little bit of a wacky syntax does that explain everything this was the road I started going down first no yeah the answer is no they're a bit they're a bit like that but I don't think that's the most productive way to think about them and it would be different if they actually were like that but they are a bit like that so as no and and yes sort of but and asking why explains a lot and exposes I think probably the thinking that drove this feature I'm speculating a bit let's let's go to question number two having now laid out how Pats are weird you know why are they like this so what is the problem that associated types solved it could be used for a number of things but I think a good way to get at it is to say that what associated types do is they solve problems where you can't represent type relationships through the tools that you have with normal object-oriented programming based subtyping but this is a classic example let's say I have a protocol food and then grass is a kind of food so it's adopting that protocol I also have a protocol animal and every animal eats some kind of food but sir I'm not here I'm not using to associate a type of this thing animals eat food now let's say I want to specify that a cow which is a kind of animal it's a particular kind of food a grass you can try to do this you get nearer and this isn't really specifically a problem with protocols you'd see the same thing here if I define food as a class and grass as a subclass an animal as a class and cow is a subclass in that case I have an override there this is not an issue with protocols this is an issue with having only the hierarchical structure that inheritance and subclasses give you and then the error is because if you tried to do that whether having an override for a subclass or just having an adopt or a protocol you've violated the substitutability requirement for a subclass right everything that's an animal needs to be able to eat type food if I create a kind of animal that doesn't eat food in general that only eats grass then I can't take an instance of that I can't take a cow and just give it to you to use as an animal it would say had a function that took an array of animals that went through all of them and it just gave them all food food objects right maybe the food is um I don't know meat right well then what if you know one of those animals actually a cow and only eats grass and then that would fail so it's be cut so because of this you can't actually represent this kind of type relationship with normal object-oriented subtyping I think the technical languages for this is talking about the covariance requirements on the arguments of the methods I don't know if that clarifies it this just compressive language but with a associated type you can be more precise you can say every animal eats some kind of food and when you declare that you want to be an animal you can just specify what kind of food it is and now it's okay this is a toy example but it sort of gets at what protocols with socio types are trying to do they're trying to provide a way for expressing Richard that they do provide a way for expressing type relationships that you can't fit into an object-oriented hierarchy okay that's been a context but it doesn't really explain this question of why they work quite the way they do typically does explain well why aren't they correctly thought of just as generic protocols why aren't they defined using the syntax that you'd expect from generic protocols as you could imagine it's some imaginary version of Swift this is how it would work right you protocol for animal and it's parameterised on the type parameter which we call foods we know the hour meaning for that is food and then if I wanted to say that cow was adopting this I'd do it by saying how is adopting animal what kind of animal okay animals that eat grass and that's how it's how it could work so why doesn't it work this way and this this parts a bit subtle but I think the answer it has to do with the way that the type alias style definition of an associated type as opposed the generic parameter style definition of associated type exposes that type from the outside of the protocol let's say let's say we did have generic rota calls in this way and you are consuming it the only way you could sort of see the associated type in order to declare constraints on it or do other things with it is by parameterizing over it right I don't wanted to feed an animal I have to say feed animal a it's kind of animal oh but I also need to have the F in there and the F appears on the female feed animal signature and then inside the implementation of feed animal you'd be able to see F because it's one of the type parameters that you are privatizing over for the definition of a generic function but with a sort of swift style pad because the type alias acts more like a member of the type you have direct named access to it so I still need to parameterize over animal just because you always need to parameterize over a protocol dissociative type you can't just pass it in as a reference that's something you can't get around but once you're inside feed animal you can directly figure out what that Associated type is just by accessing it with normal dot based access notation now if you look at that notation it sort of gives you a hint of what's going on here the in fact that's being used means that the Associated type is a lot more like a property of a type than it is like the generic parameter that was used to define a type you're accessing it with a dot and just like when I define a protocol and so you have to limit this function you have to implement this variable now we're also saying you also have to specify this type and then that type is accessible it's like one of the axes of customization that you're providing anytime you subclass something or anytime you implement a protocol so that's a difference but you might be looking at that and saying well that that version of the top doesn't look so bad like okay my my type parameter appears on the signature of things that are consuming the protocol is that so bad maybe it's not so bad for simple cases like this but it turns out that this problem gets a lot worse when you're doing something heavier weight with it so if you have many associated types not just this kind of food but also I need to live in this kind of dwelling and then I need to get this kind of drink and then I need to be near this other kind of animal table home hope if you have a whole bunch of associate types of the protocol it gets more complicated if the Associated types themselves have associated types and also if you're using a lot of protocols simultaneously so when you add all of those things together then the then the type constraint specification that you would need to put on consumers of these generic protocols it's very complicated because all these factors are being exposed to the consumer of the protocol they're not sort of embedded in the definition of the protocol now I'd like to have a really tiny example here where I show you how it gets bad with the imaginary animal example in Swift I started working on that but I confess it gets complicated right away and I think it's a bit more useful to just look at other examples for other languages this so here's an example of breadth-first search of a generic library for doing graphs or doing research on a graph in java version 1.3 java version 1.3 actually has had a problem like this i don't know if they fix it up in java having to keep track but um if you specify the man to start the breadth-first search on a generic graph library in genre that is the high specification you see on the signature what you're seeing there is a result of the fact that the pipe constraints involved in the associated types are don't get embedded in the product in the path type structure instead they're pushed out you have to interact with them from the outside and specify them and maintain these invariants from the outside whereas in contrast if you do a similar implementation of a generic graph rest first search in C++ which has ends up having better support for this kind of thing the actual signature is much simpler here you can see there's only three type parameters instead of one two three four five six seven set of a type parameters right and you can see what's going on there in that traits declaration there's a type named graph traits be vertex s what that's saying is okay I'm generic over the class G which is the type that defines the kind of graph I have with it the and from that type I can get the Associated type vertex that tells me the type of the vertex so if I have a graph where every node is an integer and I just tell you that this is the type that finds the graph you can access the fact that that type requires that the types of the individual nodes is integers you don't need to separately specify that this is a functional programming conference so I feel like we have to put Haskell on the board as well but this is also old Haskell's compiled on hogs 2002 but this is showing similarly that you get this simpler syntax when you have this ability to embed information about the associate types now why am i showing you example from 2000 to 2003 the reason is I didn't come up with these examples myself these were things that I encountered in the course of trying to understand the motivations behind the swift design and I think the magic key for understanding this more deeply is the document I found which is a paper published finally in the journal functional programming in 2007 extensive comparative study of language support for generics and this reviews in detail the generic support in Haskell standard ml Java 1.3 at time c-sharp c++ language called cecil eiffel and it implements a significant generic graph library in all of these languages and then it looks at one of the problems like oh it was really easy to do in this language it was hard to do in this language it was okay in this language and then based on that work just by a few people working over a few years this very systematic discussion of well okay these are the here's a generalized statement of the language features and this language has these features this language of these features these ones are important for this reason it's is quite dense but but it's a great document one of the outputs of it is this awesome table where they have on the left a column that shows generic oriented language features and then languages they're saying how they stack up a multi type concepts that is protocols associated types so concept in C++ is a lot like for the called associative type multi type means that you can have multiple associated by multiple constraints lots of constraints on the types at the moment so if lets you apply conformance constraints to the Associated types maybe there's more coming associated type access this is the thing I was getting out about how easily you can figure out what the Associated is constraints on associate effects retroactive modeling that means being able to apply an extension to a type that someone else defined or after it's been defined type aliases sounds familiar this was published finally in 2007 but if you go through and look at swift swift ticks all the boxes that's a great job of it Bravo 16 Bravo and I don't think it's entirely a coincidence I would be astonished if they had not read this in fact I think has a lot of circumstantial evidence that they have for instance a lot of the terms that this paper invented to describe these features it invented in order to describe them in a general way who's covering different languages so some of these languages don't call them type aliases some of these languages don't call them associated types Swift does it says it seems a little bit like when they were thinking about how to define these language features in Swift they sort of took this article said like great is that we do it what we just called type aliases because seems like we want to have this I'm speculating but there's something to this I think and also if you look at a the redoubtable they've abrams talk protocol oriented programming look at the language he uses there are times when the terminology used shifts a little bit the language which is not in the Swift programming language book but is in this paper so he talks about modeling a concept which is something that's in this paper although that's also the language that comes from the C++ Perl all the Swift guys are deep into C++ so maybe that's it I think is a lot of evidence that this paper certainly insightful first whiff that may have had an influence on the thinking of the team that was working on the features another interesting table here is just describing how these different how some of these different operations and procedures are named in different languages so you can sort of see how thing happening to map up right so you know what they call a concept what will be it's a princess of type class in Haskell most analogous to a protocol associate type and Swift the refinement operation is protocol inheriting from another with the SPL book calls it modeling that's what we call adopting a protocol constraints are called constraints the Swift fits in quite nicely and more also when you look at some of this you some of the examples I showed if you're coming from a more purely functional background you might say like well Haskell actually has features that are like even better for this and in fact if you looked at this you saw there were kind of asterisks here because even even even excellent Haskell support wasn't you know quite perfect and developing this library exposed places where it was a bit awkward and the reason that you might be thinking Haskell is great for some of these things is because actually this paper had a huge influence on Haskell this could this this article of by simon jones and Chakravarthy and Keller explicitly references the 2003 version of this paper and the difficult is that it exposed in handling certain kinds of scenarios with the Haskell type system and proposed amendments that I think are not now part of Haskell for handling these things so you know it's all it's all one there's a small world and people are people are paying attention to each other another relevant body of literature is the stuff around Scala scale is actually probably a closer analogy than any of these other languages mentioned the Scala is this hybrid thing where functional aspects of it have been done in a very deliberate and functional friendly way but it also needs to integrate with a pre-existing hierarchy oo P based type system the one you get from the JVM if Scalla were a column here I think you'd see the what are called abstract type members and asked in Scala are the closest analog to associated types and paths in Swift so that's a bit of a context on where it's coming from question number three is this the plan like really is like this how it's going to be going forward we have to make everything generic in order to use protocols with associated types at all well I have to turn all my code generic just in order to deal with things that support quality I think for the moment yes it does seem that way although you know who knows what the future holds I know that certainly around August of this year before WTC there were blog posts where people were saying oh I imagine they're going to fix this soon this can't be the way it's going to be but when the protocol oriented programming taught came out it really suggests that this is kind of the plan so this is this is I think the the key slide from dr. Abrams talk on protocol oriented programming and theory kind of lays out the two worlds and where he's calling one the without self requirement the will self apartment it's not just with self requirement its with any associate type and you can see right here the contrast right there's the contrast between dynamic dispatch which is func sort and out a of array of orders and static dispatch which is funk and then parametrizing over ordered things because ordered is a pat and then you have a array there or there at the bottom dynamic dispatch static dispatch now if you are skeptic you might say that some of the things on the right side we're not great only usable as a generic and straight poses a lot of requirements on how you use it all I want to do is equate able but now I'm stuck with generics and static dispatch is this these two worlds just like the world of frustration I think it needs to be that way but I can understand why people are frustrated when they bump into this issue and don't understand the motivation behind it one thing I think that this slide doesn't represent is that the other world where you don't have Pat's it's not limited to those things maybe this is the world of choices like yeah you have the actual option of dynamic dispatch if you're not using a pat if you're using a plane protocol but you know you can still do static dispatch as well if you're not using a pro so it's all you're locked into dynamic dispatch on one side and you're locked in the static dispatch on the other side actually this one side what you can do either there's one side where you're stuck with static dispatch you could use types of generic constraints if you wanted to on the non pat side of the protocol world but based on this talk you'd have the impression that this is the this is the intended the language and these restrictions around Pat's or things we should learn to live with and embrace it appreciate I did put a little asterisk fun on that yes and the asterisks represent existential x' now I haven't reviewed this material very deeply in fact Colin told me about it about 30 minutes ago to be honest which really embarrassed me because made me realize I should have got into it more but existential x' is the name that you'll see in Haskell or the world of statically polymorphic parametrically polymorphic languages that describe the kinds of the dynamic dispatch that you'd get an object-oriented language so basically if you want to have a pat and then have a reference to it rather than have to use it as their constraint what you would need for that is for Swift to support existential x' and are they coming I don't know we don't have anyone here from the Swift team to tell us the truth but but if you go and look inside this is the standard library you do see some evidence that they regard this as a bug that don't exist yet for instance they haven't fixed me you know so these features in santur library right now that are described as well workaround for the inability to create existential x' and there's a radar for it so maybe existential czar coming down the road and in that case it will be you know a better world in the meantime there are workarounds that you can define and indeed you can see examples of them in the standard library I play any generate any generator or any sequence are pipe racing wrappers that you can define in order to work around the fact that the language doesn't define existential you can also define your own if you want it's a it's a somewhat irritating exercise but it can be done but for instance I found myself building one for any interval is a vertical associate type of path that defines the interval type but that interval type has an Associated type which is the type of the scalar value that defines the intervals now let's say you wanted to have an array of intervals where some of them were closed open intervals and other were open open intervals that were close close intervals array of interval objects that represent they all the possible values between 0 and 1 if you want to sort of go through that array and check you know if something is contained by any of them well you can't do that with a pat because because it's a pat you can only do these homogeneous arrays so you need to create this type of racing wrapper just have an array of interval object so it can be done I could show that later people are curious but it's a bit of a nuisance maybe it'll become automatic if the language gave support for exercises again I'd say you know to understand is is to forgive an understanding why Pat's work the way they do gives us some perspective but let me just review the four questions hopefully to pull all this into some kind of shape how are Pat's weird I think the essence of it is if they lock you into generics and static dispatch which maybe was not you wanted not what you wanted maybe all you wanted was to be able to find equality I Elias as a keyword specifically is a bit misleading because it does two very different things one is nd convenient syntax thing other is established as a requirement a protocol thing and when you think about what an associate type is I think it's as much like a required property as it is like a type parameter does a good guide to have in the back of your mind again why are Pat's weird Oh what's the motivation behind this that the fundamental motivation behind Pat's is to enable rich multi type abstractions that don't fit into the pure hierarchy like structure that you get with object-oriented programming and then why are they like properties of a type instead of generic parameters it seems like this is a very deliberate choice to work around well-known and discussed issues in the literature where generic protocols don't scale well and they don't really encapsulate the type and variants that they want to maintain in a nice way that's where they're coming from that's why they work the way they work now are they functioning as planned I think they seem to be in that they're informed by a lot of research and a lot of comparison with other languages and similar language features and if you look at all those languages all those languages um or not as not as much oriented around dynamic dispatch as a swift is I mean C++ has virtual functions but for the most part the thinking that seems to have inform this feature is thinking that was focused on languages that were more static I think that's where the static this is coming from I think the impact on a traditional object-oriented programming there's difficult a call is lateral damage but maybe this isn't the end of story maybe so it's going to get existential x' and then and then we can be able to use Pat's in the way that we're familiar with using plain plain old protocols last question right was there before like how how to love them how do how do how to embrace Pat's rather than calling them weird perhaps our uh I think first step call them Pat's make makes them seem so much more friendly and familiar they're just Pat's right they're not they're not bad guys they're just Pat's also I think giving them a new name acknowledges that it's a new thing right Pat's aren't the swift version of protocols from Objective C they're actually a new thing that has new capabilities you can do certain kinds of modeling of multi type abstractions in a way that you simply couldn't have done before it's not a broken version of an old thing it's actually a new thing deserves a new name and that's a good way to think about why it also has new trade-offs to call them Pat and if you're going to use them then you need to embrace generics at least at the moment because they can only be used as your constraints so get comfy with that idea if you still need dynamic dispatcher if you need something like dynamic dispatch because of the purpose that you had in mind when you decided you wanted to use a protocol I guess I only have three bits advice the sort of end of the talks can't go into it in detail but one option is instead of relying on dynamic dispatch use enums and push the runtime variation into the value level so instead of having a type but than five different subtypes and dynamic dispatch is picking the one you want actually create an enum that has five different cases and then inside it you could have an embedded switch and that which is between the different values that you want maybe that's a better way to model your situation to begin with the example is working on with intervals for myself I have like one solution to the type Racing rapper another with enums is this doesn't work arounds the other workaround again is the hyper racing rapper to high dynamic dispatch inside to type and this is what the standard library does when it would like to have a plain old protocol or an existential or whatever you want to call also if you still need an amicus - maybe wait a year and 23-point whatever will come out and then will have existential x' and then we can all just you know go back to our old ways so that's my that's my thinking on protocol to associate types and how they got that way and when I started doing this he was thinking about it Apple was still a sort of black hole or opaque wall it was very hard to figure out what they were thinking because you could sort of get hints of it on Twitter but now since the open source release since the the new sort of glasnost era like open discussion about where switch is going maybe we could just ask them and then we'll find out it makes a lot of this detective work and criminology a bit unnecessary so you know we can call them up later uh I hope that planes this to some degree Anna be delighted to answer any questions hi that was a very interesting talk explained a lot of concepts for me umm can you elaborate a little bit on what makes these constraints I'm not really familiar with that term being used in the context of type being associated with the protocol like is it just the fact that they introduce something that needs to be implemented or what they're under if they could only be use America France like I guess could you define constraint in this context a few senses of generic constraint is eat all this but let me just focus on the most basic one at the very top I think that's that's what's puzzling about the error message the first time you see it if you look here the error message you get when you try to create a variable that contains a protocol that uses self or protocol that uses some other Associated type like I'm doing here at this bottom line of this slide the error that you get is this one and the exact language is protocol whatever it is that you're trying to but can only be used as a generic constraint right so let's like really break that down what does it mean um the problem is that here we're not using that protocol as a generic constraint the protocol here called my equatable is being used as the type of a variable with the variable proto bar but what would it mean to use it as a generic constraint it would mean this case here right here let's say I have my product my hat or a called an associate type or with a self requirement it's called proto and in this line here where I say - the only place the protocol appears is right next to the T so when you see class 2c defining a class because my hair cut my type parameters this class is generic over T meaning every different T I could put in there would produce a different kind of C right but it was a constraint part just put any tea I want in there I can't just put in an integer or a string or whatever it has to be a tea that is a protocol that can adopt that does adopt the proto protocol so that's what it means to say that the Patt protocol can only be used as a generic constraint I can't use it as the type of a variable or of a function argument or of a return value I can only use it in this little bit of language where I'm saying okay here's a type parameter but it's constrained and the constraint is whatever type I fill in here needs to be a type that adopts this protocol so that's the sort of wouldn't does that answer the question I feel like this is the essence of it it is very puzzling if you haven't done a lot of generic stuff before it's actually more a follow-up comment but when I first tried to understand it was very helpful for me to understand that when you have the type alias and you try to use a protocol that you actually working with an unfinished type you're still like holes in the type definition that can be fooled by the class or struct it implements a protocol and by using a generic constraint you basically define who's going to implement it and who's going to fill the holes and then fulfill I had a final type of specification essentially regarding protocol path right because you can't have a array of different specializations of the same generic type like I couldn't have an array that had the first element being itself a I don't know right event and the second element being a array of string array of int an array of swinger different types you can't have an array that contains different types but when I first started think about this I thought like oh maybe the problem the reason I can't have an array of ATS is because they could all be different under the hood but that's not actually the essence of it right because if that were the only problem if that were the only issue that a patent that a pat is kind of a generic and so they're actually diverse types if I were the only issue that would explain why you couldn't have an array of hats that were differently specialized but that wouldn't explain why you can't have a uniform array of Pat's and it wouldn't explain why you can't have a single variable that's a pat right because you could is that then there's no ambiguity then like you have a specifically defined Pat it's adopting with a specific knowable Associated type so ah I think it's a it's very useful to think about in the sense that type alias defines a requirement that needs to be met and it's an unfinished type and tell that to met but that's not the fundamental reason why you can't use it as variables I don't always you can't using those variables there right now they've only built the machinery for static dispatch it seems like they want to build the machinery for dynamic dispatch as a thing on top of it X essentials whatever rather than the way people have done for overview learning I hope that's helpful yeah yeah but that is that insight is what led me to think about oh maybe it's just as there are protocols but I don't think that's all there is good so I found myself in the same situation as you mentioned I ended up with a solution of using enums however at the end you don't wanted something to be a little bit easier to use so I created a bind and when I did the bind because the bond is declared generically I found myself I'm back to square one and I couldn't use it again arm without making binds the specific again um how do you deal with that how do you deal with you just have to do that switch statement again and again again yeah so both of these workarounds of pushing the dynamic dispatch like behavior and enums or pushing them into a hyper racing wrapper involve a lot of boilerplate because like let's say I have a plain old protocol or even a superclass that has 100 functions right and then I create different subclasses of them and then you get dynamic dispatch on all of those functions whereas if you're using enums or if you're using type racing wrappers I think you end up needing to create like 100 switch statements I'm not sure about that but that's been my experience so far there might be some clever pattern in there but I haven't found it to pay in the button uh thanks a lot for your talk that was really great I definitely learned a lot of stuff about Pat's um a lot of the programmers that I admire and follow on Twitter reference academic papers like the one that you brought up during your talk so my question is where did you find that paper how did you discover it and also is there like a cool website or resource that I could use to find papers that touch on my interests sorry if that's a tangential question well I was writing a book a chapter of a book the functional programming chapter and the generics after of a book on introductory programming in Swift and when I agreed to write that is because I didn't really understand the Derrick's I thought well if I write a chapter on it that'll force me to understand it really well so I just was googling a lot on generics and trying to understand them in comparison with other languages and I was also studying Haskell the times I'd like run into these issues and I think just googling on generics I eventually stumbled into a reference to this paper but then I found an old preprint version of it and one of things I've just as a kind of practical matter when you find academic papers they're usually locked up behind some a wall but then if you look at the names of the authors and go to that authors website then they usually distribute the PDF for free or an early version then if you decide it's worth it you can flunk out the $50 by the official version so I just sort of googled around and then a bit of detective work to chase it down but I thought this paper was really good I mean we have a community where we talk about technology issues and there's going to blogs and talks and the academic community is more separate from that than it should be but this paper is fantastic this is like four or five people working on this over years with NSF funding systematically developing different Graf libraries it's like a lot more work well work and thought light into this than putting together a blog post and really I'm just trying to communicate a little fraction of it so I think I think it's really worth digging into these papers whenever you bump bump into them thanks a lot it's the one more question your site um may be 100 and good place to find papers this lambda D ultimate this website that's a good one lambda the ultimate like lambda and I'm the function as a website this is just a quick comment six days ago there was a proposal on swift revolution that was merged into Swift three that will hopefully alleviate some of the ambiguity around the type alias keyword it's going to now use associated inside protocols and it's with two point two they'll deprecated use of the type alias keyword inside protocol definition so so the reason I bring it up is part of the excitement around Swift being open sources that we can now witness and participate in well precisely that evolution but thank you for your there's one at the back getting my exercise point yeah awesome talk I learned a lot could you guys the definition of tie pretty sure I'm not really familiar with it and kind of maybe go into the any generator or any sequence example like how that's an example separation I think I do a better job showing the example I work through than trying to provide a definition in the abstract but let me let me go through the example maybe not right now because as other questions but later and then that can sort of show it I think I have a hard time putting it in language well but basically you have a type that is concealing the fact that there were parametrize types underneath internally so sort of the outside but for instance like let's say I have any sequence right so as an example of a type of racing rapper that's in standard library if I had some type which was a sequence type and it would be a sequence type of some particular element type right so let's say I have a sequence as they have a type which is a sequence type of integers now that type has two types associated with it right well integers obviously we know it's a sequence of integers but we don't just know that it's a sequence type of integers it's a particular type right it could be a array of integers or it could be some kind of linked list of integers so there's two types that you're managing in that situation you're managing the element type what it's the sequence of and then you're actually managing the type the type of sequence type is in an array or is it a linked list you might have situations where what you wanted was just to have something and know that it a type just represented a sequence like any type at all that represents a sequence of integers and you don't actually care if it's an array or if it's a linked list or whatever so you can create a type and that's the hyper racing wrapper type which kind of disguises if it's an array underneath or if it's a linked list underneath and it only exposes that it's giving you an interface a sequence like interface to integers so that that's an example of a type of racing wrapper that's in the standard library so I'm not sure how to define that abstractly but that's what it is and if you wanted to get something like dynamic dispatch you'd need that because you want dynamic dispatch you don't care about some pipe fact underneath you just want to be able to know that you can call a method and so that means is if you get a type raising wrapper then you don't need to use the type of generic straight because you know do you have in any sequence does that be helpful I can walk through an example later but then that's the gist of it and it's a final question and then luncheon ARC's yeah um you showed the slide from Dave Abraham's talk but a call oriented programming that's like I feel like that's a very helpful distinction between the two types um and uh I guess there's more comment on the motivation um it seems like in this case um and if you look at what Swift is like it's very much like a bridge between you know two ecosystems one of which we don't really know what the other end is like whatever Coco and Swift looks like like the you app kit and UI kit are very much designed around like dynamic dispatch and objective-c you so like do you think this is more of a scaffolding on the left side the ones without the self requirement that's more of a scaffolding that's not for the sake of static type information but really just like until they have a nicer method to do dynamic dispatch one question is let's say you've got existential x' then you wouldn't have this static dispatch on the right-hand side that's the only way to do it would that give you functionally all the same things that you get from left hand side I don't know I don't I don't think it would give you everything but I think yeah yeah oh yeah I don't know that's the interesting question when I when I first started looking through this especially looking at the thinking that seemed to inform this I put up this would be true year and a half from now yeah just that stuff um existential and the big mark is a pig will be better Oh Oh Elsa and calexis again so there will be lunch maybe it's not there yet it will be there within minutes and a conference is not only about listening
Info
Channel: Functional Swift
Views: 29,740
Rating: undefined out of 5
Keywords:
Id: XWoNjiSPqI8
Channel Id: undefined
Length: 56min 6sec (3366 seconds)
Published: Tue Dec 15 2015
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.