Leo Dion (host): Thank you for joining me for another episode of Empower Apps. I'm your host, Leo Dion. I'm joined once again by Matt Masicotte. Matt, thank you so much for coming on. Matt Massicotte (guest): Thank you very much for having me again. Leo Dion (host): This is number three appearance. People probably know you, but I'll let you go ahead and introduce yourself. Matt Massicotte (guest): sure.
Well, my name is Matt and I'm a long time Apple developer, and lately I've been putting a lot of effort apparently into concurrency. It's like my main thing. Leo Dion (host): So you were on last time to talk about concurrency. You're back on to talk about concurrency and the future of Swift. Yeah. Where, let's just jump right into it. Where do you think concurrency is at when it comes to Swift 6 and how things went with Swift 6 and actors and a weight and all that stuff?
Matt Massicotte (guest): Well. I think that most people are gonna have trouble adopting Swift 6, And I think a lot of people kind of naturally are trying to do it because it's this new thing and it's been released. And so because it's released, it feels like it should be the thing that we use. But I think that for the vast majority of projects, Swift five mode is the right thing to choose and then to just incrementally work your way towards going in this direction.
Leo Dion (host): What if you're starting a brand new product? Matt Massicotte (guest): I think that if you're starting something brand new, especially like with No, if you're starting with nothing carried over, then sure go for Swift 6. It's usually a lot easier to do it with a new project than it is to migrate existing stuff. That's really the big problem I think.
Leo Dion (host): Okay. Do you think where do you see the issues as far as, for the most part, for people's mental model of how they think it works versus how it actually works? Matt Massicotte (guest): you know, the big thing that happened, and this happened to me, and I think it happened to a lot of people, and I still see it happening now, is they're using async weight, as a syntactic convenience, over completion handlers, I. it feels that way in a lot of ways.
And so you might like have an existing project. All the warnings are off by default, and you just start saying like, oh, instead of having completion handlers everywhere, I'm just gonna use async weight, then it's all gonna be the same. And that is not true in the general case. And there are very trivial examples where that will change not just how the code looks, but it will change the semantics of how it works as well.
so when people get themselves, like when you were asking about a new project, you can kind of catch yourself from the beginning because Swift 6 mode will present errors as soon as you make a. Swift five mode, especially with no warnings for the most part, won't show you anything. So it's very easy to make these changes that are mostly correct and mostly fine, and you start having this big project that is adopting more and more of this stuff.
And when you finally do flip on the warnings or try to use Swift 6 mode, you'll inevitably discover some stuff that isn't right, and that's when it can be hard to fix. Leo Dion (host): So I have a few thoughts about that. It's interesting you said syntactic sugar. 'cause that's exactly what I had thought before. Async away had come. I had thought that's essentially what it was gonna be, was kind of like promises underneath, but like basically it's still not changing a lot.
So my first question is the problems that Swift 6 addresses when it comes to concurrency were those issues that had already existed, but we didn't notice under GCD? Matt Massicotte (guest): Well, well, like one example is you have some API, right? And it's got some callback and it says. And you need to know, well, does that callback happen on the main thread or do I need to dispatch over to the main thread to, to handle that callback?
And so that's a really common pattern where many people will just not look at documentation, not read how things work. They'll just always put a dispatch to man, and That's safe because then you never have to worry about whether you're being called in a background threat or not. It is also inefficient, but it kind of shows you, it highlights the general problem of.
if you miss that in even one single spot where you happen to not realize some API is calling you back on the main thread and you don't put that that call back in. Then inevitably you'll run into problem. and this is like a really common problem. I'm sure you've had this problem happen to you as well. a super common problem. So that's one of the things that concurrency.
Swift concurrency fixes is because that the, this information of like, should this be main thread or not, is built into the signature of the function. You cannot get it wrong. You don't even need to think about it. You just like run your code and it'll automatically do the right thing.
So from that perspective, I love that because that's a really common problem Leo Dion (host): we talked about previously in the last episode with Donnie about the whole having to mark things as main thread and the plan to like change that going forward for like, if you call something from main thread, you call it async function, from the main thread, there's look, they're looking at like proposals about that. Do you know what I'm talking Matt Massicotte (guest): Yeah.
Leo Dion (host): You wanna just kind of explain what that is and what it's supposed to address. Matt Massicotte (guest): Well, there's a lot going on there a lot but like one of the things is you had said, and I thought too, that async weight was just syntactic sugar for callback. And that is true provided that the isolation of the types involved don't change.
Leo Dion (host): right, Matt Massicotte (guest): And so, and, but what's interesting is there was this proposal that was introduced, I don't know, like Swift 5.7 or 5.8. I can't remember exactly what it was called, but it changed the semantics and it very clearly specified that if you have a non-isolated asynchronous function, it's always gonna run on the background.
But What that did was it fixed a couple of performance issues, but it made it so it was no longer true that these things are just syntactic, sugar for completion handlers for most uses. And so that one little change ended up having widespread implications to make it really hard for people to do the right thing unless they deeply understood this implication. But that is gonna get changed. And just that one change, Leo Dion (host): That is actually gonna get a change.
Matt Massicotte (guest): well it's being, it's in, it's being worked on, but it, hasn't actually been, it hasn't actually been formally pitched or formally proposed yet, but I think it's going to be. But I bring that up because talking about. How all this works, there's a lot of lack of intuition. So the, how you might expect the code to work and maybe how you have code written that works today. It will like start working right when this has changed.
It has a bunch of other positive impacts as well. I mean, I think this is, this was a very I'm not sure why this change was made originally, but I am looking, forward to it being undone. Leo Dion (host): Okay. Okay. So what are some other misnomers that you've seen people pick up when it comes to concurrency lately? Matt Massicotte (guest): Well, so one is like not understanding the implications of asynchronous. functions. This is what we're talking about.
Leo Dion (host): and I think that the whole like isolation stuff like. When it was first introduced, actors were just like, yeah, I'm not dealing with that. I don't want to have to deal with it. And then like the more and more I deep dived into Async away, I was like, okay, yeah, I need to know how this stuff works. Because like you said, it isn't syntactic sugar. There's a lot going on there, especially concerning isolation and like, I mean, essentially what we're getting at is like, not.
Dealing with race conditions, right? And stuff like that where you don't want two people doing the same thing and messing stuff up. Or two people, two actors I should say. And I think that safety, that thread safety was something that I think we didn't realize needed to be done that wasn't being taken care of in Swift. And it's like augmenting.
Part of what makes Swift so great is that safety, and so for me that was a big revelation in a lot of the work that you've done has been a big revelation as far as like what Swift 6, what async away and what actors are trying to do. Matt Massicotte (guest): Yeah. I mean, it's, that's the only reason it exists is to do safety. It's also nice. I mean, I like that. You no longer need to check the documentation to figure out is this. thing being called on the main thread?
Do I have to use this thing only on the main thread? It's cool that You don't have to look at documentation anymore, but the big focus was was, safe, was around safety. You're absolutely right. Leo Dion (host): So actors, I mean, is it come down to like actors being the big challenge when it comes to async away and isolation more so than the, like, not concurrency, but Like, is that where it really comes down to?
Matt Massicotte (guest): I think the challenges people run into is taking their existing code that uses, that doesn't use concurrency primitives, or, and this is worse, uses concurrency in incorrectly. And then when they wanna move that to a warning free or error free state. But if you're starting with something that, like you have. Absolutely no asy weight in your code base and you just want to start like seeing where the warnings show up.
It's not usually that bad to start expressing the reality of your code. to the compiler, for example, adding things like this is unchecked sendable. this is non-isolated, unsafe, like there are all these called opt-outs, these tools that you can use to tell the compiler, I am doing the right thing. You don't need to check this stuff. Now, the advantage of that is That gets you really far. And the disadvantage of it is it turns off all the checking. So like, I'm not sure.
if you were saying what I wanna do is use Swift 6 with no errors and have all these popped out, turned on. I just, I don't know what the advantage of it is really. Leo Dion (host): right. Matt Massicotte (guest): unless there then, unless you wanna start now in the future, moving towards not doing that anymore. I. Leo Dion (host): Right. Right. So let's talk about that. Where is using unchecked send? Well, let's try it with unchecked sendable and then we'll move to pre concurrency.
Where do you think it's useful to use unchecked sendable, Matt Massicotte (guest): Well, Leo Dion (host): yeah, that's okay. Matt Massicotte (guest): imagine you had some class that you made that is like a dictionary plus a queue, and it's just this thread safe version of a dictionary or a cache or something like this. Just some thread safe type that you're using for whatever reason, but it protects all its state. Internally, I. that thing is unchecked, sendable.
You make it unchecked, sendable, and you're done. Leo Dion (host): Okay. How about, is there ever an instance where you just don't care? Matt Massicotte (guest): you don't care whether it's safe or not? Leo Dion (host): Yeah. Yes. Matt Massicotte (guest): Probably that's true. And I think really I think there are many people that have come to Swift concurrency saying, well, I just think my code is fine. I don't understand why do I have to deal with this stuff at all? And I think the end.
Today the answer to that would be then turn off the warnings. Use Swift five mode, and then you're mostly, okay. There are a few bugs that are currently exist in the Swift 6 compiler that make it so that even if you do turn off everything, you still see some warnings in certain circumstances. But I think it's relatively rare but that's not usually what people are seeing.
What people usually are seeing when they get frustrated is they're using concurrency, they're using it incorrectly, but they're getting frustrated because they just want The warnings to go away. And the solution to that there is no solution to that 'cause you can't use the concurrency system, but then have it not tell you that you're using it wrong. Leo Dion (host): Right, right. That's a whole point.
I mean, so are the gains by using it correctly, like performance or what do you get from switching over to Swift 6 doing and doing it right, as opposed to Swift five? Matt Massicotte (guest): Well, I guess so I'm interpreting your question to mean you're migrating from using something like GCD to using the concurrency primitive, And in that case there are some potential performance gains. So this huge emphasis was put when Swift concurrency was first introduced on like reducing context switches.
And the idea there was, instead of having your code bouncing around between different threads, you have these, this small set of thread, pool thread. pool Threads And then this work can be divvied up without actually necessarily needing to hop around and or spawn different threads. So G, c, D and concurrency, one of the things concurrency was trying to do was address this problem. And you can see there's A-W-W-D-C talk that goes into like depth about the idea behind this.
Leo Dion (host): Okay. Matt Massicotte (guest): Now I'm kind of trying to focus on the idea because in practice I've done zero really investigation into. this. So I don't know for a fact that you will see performance gains or losses by making these changes, but that's one of the ideas. Leo Dion (host): You're gonna say another one Matt Massicotte (guest): Yeah.
Well, the main, but the main focus of it was not so much performance as it was being able to use concurrency without having to even really think about whether or not you're introducing data races. That was really the big Leo Dion (host): Right, right. So, I mean, to me, like the emphasis on concurrency was always the fact that, I mean, we could get into it, but when I did my talk at 360 Ida a few years ago about the future of like asy, this would've been 10, almost 10 years ago.
Geez. But the idea was, is like a, we don't, we wanna do async away for the syntactic sugar, but also the fact that like, I don't wanna say we've hit like the edge of Moore's law. I don't know where you're at on that, but the fact is we moved away from like, you know, getting faster and faster processors to just having more and more cores. And the fact that you can divvy up jobs to multiple cores makes it more advantageous to want to do.
Things on more cores as opposed to like, just like, because you can't, your processors aren't gonna get faster per se, as much as you get more cores and can do more things at the same time. And that's where the advantage is. Am I mistaken in what I said or like, like is that the benefit of concurrency or doing things concurrently or is it like with context switching? Is it just creating more work than it's worth?
Matt Massicotte (guest): Well, so one thing I'll say is single-threaded performance has been getting significantly better year over year and continues to. I don't know that will continue forever, but it certainly has been the case. Leo Dion (host): Okay. Matt Massicotte (guest): So it is true that like, generally speaking, there's been more cores per processor over time. That's true.
But also, even if you don't use any concurrency at all and just have a single threaded program, they're also getting Leo Dion (host): Okay. Okay. Matt Massicotte (guest): Now, you know, I think that one of the things that I've seen people do with concurrency is like this, it's almost like this fear of the main thread that they wanna get everything Leo Dion (host): I like that. the fear of the main thread. Matt Massicotte (guest): Well, it makes sense because it makes your app unresponsive.
So the idea is you want to get all that work off the main thread so that you can have it be available to service user input or other kinds of events. But the thing is that it is, there's overhead, So moving something off of the main thread, even to one of these, to any to anywhere, It has a little bit of a cough. It's usually Leo Dion (host): And this is, you're talking about the context switching. Matt Massicotte (guest): Yeah, exactly.
It costs it, it takes some amount of work for the computer to be able to no longer run this stuff on the main thread and do it somewhere else. And so as long as the work you're doing outweighs the cost, then it's a win. But if it turns out that the work that you're switching off of, the main thread is minuscule, is teeny, like a very small amount of work, you're doing it off of the main thread, so you're transferring the work off.
and now you have to deal with, and now my user interface can still accept input, right? So I have to maybe like turn off a button or put a spinner and then you finish and now you have to move that work back onto the main thread. So there's overhead and extra complexity. And as long as it's worth it, it's good.
But I, I've encountered certainly a number of applications where they're shifting these minuscule amounts of work off of the main thread To do basically nothing and then move it back onto the main thread, which causes significantly more complexity for, it's actually a negative performance benefit. It's faster to just stay on the main thread and do it all there. Leo Dion (host): That's really interesting.
I don't think a lot of people know that, Matt, like, I think a lot of people think, like you said, oh, we should just have it all. On the background and then only have the stuff that involves UI updates on the main thread. So I agree. I don't like it Makes sense. It makes sense what you said and I think a lot of people don't know that. Matt Massicotte (guest): Well, I think they, I think that their intuition is so close.
I think people are really, have the right idea, which is your fear should be of long running synchronous work. If you have anything, like take the super classic example is you're gonna download some J from the internet, you're gonna decode it and turn it into some model or something That J is probably normally small, maybe it's even tiny. And it's true. If you do the decoding and parsing on the main thread, it might actually be faster. but only for that particular input.
In the general case, you could get these massive blobs adjacent, take a long time to decode. So those kinds of things, they make sense to offload to a background task and then to pop back Leo Dion (host): Okay. Is there anything else we're looking at as far as the future of Swift in concurrency going forward with six one or six two Matt Massicotte (guest): I mean, I'm, Leo Dion (host): the other thing.
Matt Massicotte (guest): well, six one, I'm very excited about six, 6.1 because there's a whole bunch of bugs and I guess I'll call them limitations in the existing six point whatever, three compiler that 6.03. That I just I'm looking forward to seeing. them Leo Dion (host): All right. Matt Massicotte (guest): There was a lot there was a lot of new features added with Swift 6 and some of them don't, aren't quite as robust as I think they should be.
And I think that 6.1 is gonna do a lot to fix that. Leo Dion (host): Are they concurrency related? Matt Massicotte (guest): Yeah. Yeah. I'm only talking Leo Dion (host): Yeah. Yeah. Yeah. What are they? Do You wanna talk about 'em? Matt Massicotte (guest): Well, for example, there's this new keyword called sending. And sending is like, you can think about it as this lower bar than sendable. The whole type needs to be thread safe. And sending is more like just this one spot.
In this one case, I'm gonna make it be that can the compiler prove this is it? So sending is really wonderful and it really is this great tool except I have found many. limitations where the compiler is Oh, Too aggressive too. Too conservative in avoiding using it. And so it lets, it doesn't let me do the thing, even though I'm pretty sure that it should. And there's a lot of bugs that have been filed about this and many of them are fixed, but just not yet really.
Leo Dion (host): Okay. Yeah, we just talked about that in the last episode with Donnie. That, so I wanna talk about that little is this whole world of like perimeter. Perimeter argument, prefix it words, keywords that I'm like totally not familiar with. So like, so like with the non copyable stuff that I talked about at ww dc right? They introduced a few, and then we have sending, and then we have isolation.
Like kinda, Especially the isolation one, I still don't understand how that is supposed to be used in a method. Signature. Matt Massicotte (guest): I think that's good. You shouldn't need to understand it. And as soon as the, as soon as the non-isolated async change happens, which I hope it does, you won't even need to Leo Dion (host): Okay? Okay. Matt Massicotte (guest): Un unfortunately, we're not in that place today. Today.
It's a critical tool for certain kinds of problems where you really Leo Dion (host): You wanna explain what those problems are? Matt Massicotte (guest): Well, I mean, what it really comes down to is if you wanna add a asynchronous function to a non sendible type. You can't really pull that off without understanding how, I mean, I think you're talking about isolated Leo Dion (host): exactly. 100%. Matt Massicotte (guest): yeah. Yeah. You can't really pull that off without isolated parameters.
And so like a common thing I have seen people do is they'll take some type that they don't control. It's from some library somewhere, and they wanna wrap up something that the library provides with an asynchronous function. If that type that you're wrapping up though is not sendable, you can't really do that.
Leo Dion (host): Okay. I know exactly what you're talking about because when I bug you on Slack one of the things lately that I've been bugging you about is the virtual machine stuff and like there was something specifically related to that. I think it was like either starting, well it's weird 'cause virtual machine, or virtualization, I should say framework has a bunch of async weight methods. But then they're classes and they're not really sendable and it's like kind of a mess.
Matt Massicotte (guest): Okay. Well actually wait, so is that, but that framework is an objective Leo Dion (host): Yeah. Yes. We've talked about this offline. Matt Massicotte (guest): Okay. So, So, that's important because the comp, well, I don't know the history of this or why this happened, but the compiler does this automatic translation to in both directions from async to completion handler, and then Leo Dion (host): Because it's same tactic, sugar mat, so that makes total sense.
We just talk. Matt Massicotte (guest): Well, I think, okay, so this is speculation. My speculation is what happened is that was added before the change to non-isolated asynchronous methods was made, and that was added to the compiler and then they changed this, which caused that translation to not work properly and they left the translation in. I'm not sure why that was done. Leo Dion (host): documented too. So it's like it's not an accident.
It's like they actually document it in the, like if you go to the Apple documentation, they ha, Matt Massicotte (guest): I know. Yeah, I've seen it. It's just, it's not a safe thing to use. You can't really use the compiler bridging from, Async to completion handlers. Leo Dion (host): oh my gosh. This is what drives people crazy. Matt Massicotte (guest): Yeah. I mean, that should, that's a tough one.
I don't Leo Dion (host): And I get, the translation right, because we've done, we've gone through this crap before with like, like you could do syntactic sugar and objective C for generics and you could do stuff for like throwing. So yeah, that makes total sense. And then what you're telling me is like they are treating it like syntactic sugar and this translation stuff, but in fact they're not taking into account the ramifications of what that really means.
Matt Massicotte (guest): Well, I okay, so the most charitable point of view on this is, it's not that it's wrong, it will work, but only in very narrow circumstances. I. So it could be that the reason that it was left in was because it still can potentially work sometimes. It just depends on your usage and if you use it wrong, it will be caught with warnings and errors.
So it could be, and again, I'm not sure this is the case that it was left enabled because that you can use it correctly provided you follow the warnings and use Leo Dion (host): I mean. I've never gotten a single warning about running any of those methods, so like, Matt Massicotte (guest): If they're non sendable types, then you should receive a warning if you call it from an isolated contact. Leo Dion (host): I don't think I. Matt Massicotte (guest): but it's possible you aren't.
So if you aren't doing that. then that's an example of where it could work. Leo Dion (host): fair enough. Matt Massicotte (guest): So, so like I'm not saying, I'm not saying that, they. I'm not saying that the objective c async translation stuff never works. I'm saying that it is, you have to really understand what's going on. If the types are Leo Dion (host): ever look in objective C if they added any documentation for like, how it should be translated?
Like can you put any macros or like things in it? Matt Massicotte (guest): you can, There's tons. so there's tons of of clang annotations you can use to put things to put annotate Swift only annotations in your objective C code. That Those all Leo Dion (host): Okay. So is there something to deal with the situation? Like let's say you're, you have some old objective C code and it's out there and you wanna make sure that no, don't create a async away version of this completion handler.
Is there a way to, Matt Massicotte (guest): Yes, you can suppress, the comp, the the async version. You can also do things like, you can add at sendable annotations to closures, which is a very important thing to do. You can do that from objective C. You can mark types as sendable as main actor, and you can do pretty much everything in terms of annotations with. From Objective C Code that you can do from Leo Dion (host): Okay.
So we, talked about this, like in my case, would it be useful to use pre concurrency on the virtualization framework? I. Since it's Matt Massicotte (guest): I would have to look more closely at it to say with confidence, but it's possible so. Leo Dion (host): So yeah, go ahead. What would be a good case for where you want to use pre concurrency?
Matt Massicotte (guest): Well, okay, so let's just pretend that, we won't talk about virtualization 'cause I'm not sure, but you have some library and it has let's say it's in objective T, It hasn't had any updates whatsoever. So today in your Swift five, no warnings World, you have to use it correctly, right? if the things have to be called on the main thread, you have to, run the main thread. If you have to supply your own queue, you have to use it correctly. So if you import precon.
What you're telling the compiler is, I am using this. Right? Stop complaining about the types that you can't tell. So when you import a frame, that framework with pre concurrency, you're basically telling the compiler what I'm doing is fine. But that's not necessarily the case. But as long as it is, as long as your code is right today, then import pre concurrency. Makes sense. Unfortunately, one of the disadvantages of it is that it applies to the entire file.
So some what's happened to me sometimes is I'll have like one, I'll have a big complicated class and it's got one little use of a framework in one spot, and that type there is not sendible, but I know I'm using it safely. Now, if I import the thing pre concurrency. I could later accidentally make a mistake and the compiler won't warn me Leo Dion (host): Because it does it to the whole framework. Matt Massicotte (guest): Yeah, it does the whole, it does the whole framework in that file.
Yeah. So what you, can do is separate out just that one usage. You can even do this with extensions. You can like split a class into multiple files. So it's kind of gross to do that, but that is maybe a thing you want to Leo Dion (host): So basically put that little one use in a separate file in an extension. Okay. Matt Massicotte (guest): Yeah. If you're really worried about it, then that. makes sense.
I mean, I've also seen the opposite case where there are people that are using code wrong today. They turn on the warnings, they discover the compiler is unhappy all over the place. They throw a pre concurrency on there and all the warnings go away, but the code's still wrong. Yeah, Leo Dion (host): You had a really great blog post about why you don't need to make everything sendable. Maybe you wanna like quickly summarize that and where people fall fail in that aspect.
Matt Massicotte (guest): Well. A thing that happens is that you turn on warnings and immediately you're gonna get a lot of warnings. That reference sendible, this type is, I sendible you can't do this 'cause it's not sendible. And so your reaction, you're very strongly pushed towards this direction of just make the stuff sendible. Everything works so nicely when things are sendible.
So it's a very normal, I think, to have that kind of feeling, especially if you don't really you're just getting started and you're getting started with an existing code. base. Usually, I think what you want to do is like, think harder about do I want this thing to be sendible? Why does it have to be sendable? Does maybe I'm I shouldn't be bouncing this stuff around between lots of different act, lots of different threads. Like maybe it should all stay on one.
And so, I my, my go-to is always can we like not need this thing to be sendible in the first place. That's a better Leo Dion (host): for me, like, this is where you're gonna tell me I'm wrong. cause that's what this whole episode's gonna be about. So for me, like Sendible is basically like if it's a struct to where it's just data. Like it's okay to just make all those sendible because they're simple enough and who cares. Whereas classes, I would never make a class.
I would like try really hard, never to make a class sendible. Matt Massicotte (guest): No. you're, I think you're right. that's totally the right way to think about it. Leo Dion (host): Classes should never be sendable because they're reference types and that's a mess Waiting to. Matt Massicotte (guest): I mean, I Leo Dion (host): Not never, but like it's a lot of work to make a class sendible. Like if you're.
Matt Massicotte (guest): Okay. So, but that's the key, what you just said there is the key is that if you have to do work to make something sendible, that's a strong signal. You probably don't Leo Dion (host): If it has to be used, what basically would I've come, what I wrote in my blog post was basically if it's a struct and it's fairly like just data types, then yeah, go ahead.
You can make that sound, you should make it sound kinda like you to make it quotable or you make it credible or something simple like that. Whereas if it's a class and you really need it to be sendable at that point, you may as well just make it an actor. Because then that way, like you are, you're taking care of the fact that like you'll never have an instance where you can't write and read essentially at the same time. And actors kind of handle that.
Matt Massicotte (guest): Okay, So first in terms of like, struct and simple data types that are just packaging up a bunch of data and moving them around, Like I make so many, it's almost like a default when I make types like that. I put sendible and hatchable, like I add those two things to almost everything. Yeah. Yeah. So, and I think that, I think a pretty good rule of thumb is if it's easy to make something sendable, you should go for it.
Now classes are not easy to make sendable, but it could be like we talked about before, that this is a thread safe type. It just happens to be a class then unchecked sendable makes a lot of sense. Now you brought up another thing, which is I really want this type to be sendable, but that's hard and you're right, I'm gonna make it an actor.
Now, actors are super cool because the good thing is they're, they are Sendible and they also protect all their internal states, and you can have all kinds of garbage in there that is not safe at all, but the actor will keep it safe. Leo Dion (host): But Leo, go ahead. Matt Massicotte (guest): well there, but they come with trade-offs. And the trade-offs are significant. right? So the first one is now to the outside world, everything has to be asynchronous.
Their interface is now always asynchronous. And Yeah. And that can be like a very profound and terrible Leo Dion (host): To a code base. But how about like, how about to the app itself, like in performance, because we talked about context switching earlier. Like Matt Massicotte (guest): I wouldn't, I mean, yeah. Hey, That's true. I wouldn't really give that a lot of thought unless you're very I really don't wanna emphasize context switching as being a problem. I don't think it is.
For Leo Dion (host): Oh, okay. Okay, Matt Massicotte (guest): What I, meant more was it's not so much the performance that's the problem. The problem is you're paying this complexity cost for performance you don't need. That's really the more important thing is bouncing around to the background, to actors to basically manage like very small amounts of states. It's so much, first of all, simpler, but also could be more performant to just leave that stuff on the main Leo Dion (host): Right, right.
Okay. So you're basically saying. If you need to make a class sendable, you should really consider, instead of making an actor, make it on main actor. Matt Massicotte (guest): that's, I think that's often exactly what people need to do. Now, another thing, a second part to that is, this is getting a little more complicated. Leo Dion (host): It's perfect for a podcast in the car. This will be great having the kids in the car that can Matt Massicotte (guest): Okay, good.
Leo Dion (host): Yeah, no, go ahead. Matt Massicotte (guest): well, I mean, Main actors your first try, right? As soon as you have a thing, especially if you find, while what I really want to do, this happens all the time, is I have this one spot where I wanna read or write this data synchronously, but I need to do that from the main thread. That's main actor stuff. There's nothing you can do about it.
The compiler is telling you want this to be on the background, but that has a big cost and your design doesn't support that cost. So if you run into that kind of situation, it's, you really have to think hard. Am I willing to totally redesign how my app works to make this an actor, or can I just make this main actor and it's gonna be fine? And as long as there's no long running synchronous work, you are gonna be fine to put that on the main actor. Leo Dion (host): I'm trying to rephrase this.
So what's the benefit of using main actor instead of putting it as a class? As an actor, if you don't care that everything is gonna be async away. Matt Massicotte (guest): If you don't care that things are gonna be Asynchronous So there's one other problem with actors compared to, for example, main actor and everything. And that problem is not only is its interface asynchronous, but all the inputs and outputs have to be Leo Dion (host): Right.
Okay. Matt Massicotte (guest): Because everything has Leo Dion (host): Right, right, Matt Massicotte (guest): it is, presumably main actor, to this actor and then back again. So what ends up happening is you have this problem. You started with, oh, I just need this class to be sendible. I'm gonna make it an actor. But now you fix that problem and in exchange, now all the inputs and outputs to this type now have to be sendible.
And so usually what happens is you get down and this, it says like never ending. You're just chasing over and over again. That type has to be sendible. This has to be an actor. Now, this has to be an actor. This has to. be an actor, and. What you're doing is you're adding more and more concurrency, which means you're more and more sendible types. And that might be what you want to do, but I usually just don't do Leo Dion (host): a lot of cone maintenance work.
Matt Massicotte (guest): It's a lot of work. It's a lot of change. Espec. I mean, if you're doing something Leo Dion (host): that's what I'm saying is like doing something new, which of course is only 20% of the work out there, but you know what I mean Yeah. Matt Massicotte (guest): Yeah, I mean I still actor is a rare thing. I have to really be able to justify to myself.
I actually tell a lot of people when they're first getting started, you wanna make something, an actor, I want you to write like a little code comment on the top of the type and say, this is an actor because, and if the because is I needed to be sendible, that is not a good enough reason. Leo Dion (host): Because if it's synchronous, you'll never run into the situation of, yeah. Matt Massicotte (guest): Now?
Yeah, I mean, unfor, unfortunately today, if you wanted to make a class, which is very reasonable to be used from a bunch of different places, and you want it to have asynchronous methods or even like participate in concurrency in any way today to do that is possible and requires a very deep understanding of how isolation works. but that's really unfortunate.
That's just the Leo Dion (host): I mean, when you say, is that something that we could, is this something that can fix it in the language or is it just that's the problem of dealing with threat safety Matt Massicotte (guest): Nope, they're gonna fix it in the language because the, this problem all really comes down to how non-isolated, and this is a plain class, no isolation and asynchronous methods work. and they're gonna change this.
Or at least it's being Leo Dion (host): and how are they gonna fix that? Matt Massicotte (guest): Well, what they're gonna do is for a non-isolated type, non-isolated asynchronous method today, it automatically goes to the Leo Dion (host): so that's what we had talked about earlier is that way it will go, if you have a class and you're running it in main actor, it'll stay in main actor, and then if you run it in something outside of main actor, it'll stay outside of main actor.
Matt Massicotte (guest): So the reason why that's so important is that it means that you can just use these things normally, like you would normally, any other thing. It makes it much more like syntactic sugar for a completion handler, And it's it's just such an, it's such an easier model for people to understand and use for regular code. Leo Dion (host): so Matt, I really like, I'm not being sincere here. I'm just gonna be an advocate, devil's advocate for this.
I really hate that they're changing that. How can I make sure that my method goes into. I guess you could just mark the method as non-isolated, right? I guess. Or how would you be able to go back to the way it is now, I guess? Matt Massicotte (guest): Yeah. Very valid question. So that's part of this proposal that is, remember, it's not finalized yet.
But part of the proposal today, what it looks like is if you wanna make a method that runs on a background thread, specifically, you have to annotate it with something like, at concurrent, Leo Dion (host): Or Matt Massicotte (guest): is what's currently proposed. Leo Dion (host): up with. Matt Massicotte (guest): Something. Somehow you have to indicate this is a method that's gonna run not Leo Dion (host): Is this for 6 1, 6 2? Will this be June? Will this be like, Matt Massicotte (guest): is.
it is not even in proposal form yet. so I don't Leo Dion (host): Fair enough. Matt Massicotte (guest): But it would be cool, I mean, I would love to see this for June, but it, I don't think it'll be any sooner than Leo Dion (host): so one que one thing, I don't know if you tackled this in a blog post or somebody did, is main actor always the main thread.
Matt Massicotte (guest): Yes, I have, sometimes said to people before, so the confusion, there's a little tiny bit of subtlety because if you make a type main actor. A lot of people remember, they're scared of the main thread. So they see main actor and they think, no, I don't want this to be on the main actor. But the reason they're saying that is because there's one spot in one method that can run some long running synchronous code. and so, but the main actor always runs on the main thread.
But what you can, which, what you can do is take a main actor type and then just carve out this one little method that runs on the background. Leo Dion (host): Okay. Matt Massicotte (guest): So if that makes Leo Dion (host): Put that Matt Massicotte (guest): What I'm saying is yes, it can say in the same class, you can just have, you can have everything be a main actor type and one method of that type. Not be main actor isolated. today non-isolated async.
Leo Dion (host): So I feel like we covered a lot. So is there anything else we need to cover with actors in isolation that we haven't already? Matt Massicotte (guest): I mean, it's a big topic. We could talk about it all day, but it seems pretty good what we've Leo Dion (host): So besides concurrency, what else do you have to look forward to in Swift in 2025? Matt Massicotte (guest): Oh, that's a very good question. I've been so focused on that, to be honest, that I'm not even sure.
Um. What else to look forward to? Leo Dion (host): so we talked about this offline, but parameter packs, fixing those. Matt Massicotte (guest): yeah, I have used them a little bit. And I think they're very far along, they're very usable and they added a bunch of things in Swift 6 to make parameter packs even more usable. because I think before there were some pretty rough edges.
But there are some spots definitely if you start getting deep into parameter packs, there are some spots where it doesn't quite work the way Leo Dion (host): Yeah, we talked about this with, I was trying to set up a parameter pack and. Posted it to the GitHub issue for Swift. But yeah, there, I forgot what it was exactly, but yeah, that, we talked about this on NASA probably too.
But yeah, that was the one thing that like, kind of stopped me from using parameter packs further 'cause it didn't do that one thing that I wanted. Matt Massicotte (guest): I was able to, for what I was trying. I've used them one time for one exact, exactly one project and I was able to pull off what I wanted. But I remember struggling a little bit here and there, you know, parameter pack, kind of the same thing as Sendible.
I. excuse me, sending, and it kind of reminds me of like the earlier generic days of Swift two where you look at the language and you write something and you think this should work. It totally makes sense given my understanding of how this all works. But the compiler just isn't quite there yet. Leo Dion (host): Yeah. Anything else you're looking forward to in 2025 when it, comes to Swift?
Matt Massicotte (guest): I mean, I've been ignoring so much of the I've been ignoring so much of the proposals and everything else going on because I'm so focused on concurrency. But personally, what I would like to see, I mean, there were some major improvements in Xcode in with Xcode Two things that I loved was the support for editor config, which is this like way of configuring how your editor behaved. Leo Dion (host): so can you do Matt Massicotte (guest): It's supported by.
Leo Dion (host): and then X code will read it. Is that what it is? Oh, awesome. Matt Massicotte (guest): that's exactly it. That's exactly it. And it's cool because that format is supported by basically every other editor in the world except Xcode, but now it's, which is really wonderful.
But the other thing that Xcode has done, which I think is really cool, is they've made it so that instead of having, its like its own internal project structure with groups, you can just reference folders directly, kind of like how SPM works and they'll just automatically compile what's ever in that folder. And that is life changing. I mean, it's such an amazing feature.
I can't believe it took so long to arrive, but it's really great and I just want to see more Leo Dion (host): the file creation is a big update in Xcode that I use a ton now. So you can create a new empty file. You can create a new file from the clipboard. You can you can select a piece of code and say, extract this into a new type or new file. Like that stuff has been amazing and I've loved that. That to me has been a big advancement in my workflow.
Matt Massicotte (guest): Yeah, I've like, I've liked that a lot as well, but what I really want to see them do is address some of the usability problems. Not like with not with your experience using the the editor, but with what the editor is capable or what the ID is capable of doing. Like, SPM has some pretty big limitations and just a lot of Problem. For example, you can't, like, you can't build your project if you don't have an internet connection unless you've pre-cash your SPM. packages.
That's terrible. These kinds of things need to be improved and I think that SPM is so wonderful. 'cause it went so far towards being like more easier to use open source software, contribute to open source software, but it just isn't quite there yet. Where it feels like a, Leo Dion (host): a package and you don't have it, and you don't have an internet connection, Matt Massicotte (guest): well, I Leo Dion (host): right? So you would just say you're talking about like the machine SPN cache.
Like why not just use that? But if you don't have it in that cache, so, but. But the problem you're saying is like, if you have it cashed globally, why is it still trying to go out on the internet and, Matt Massicotte (guest): yeah, I mean, I think maybe a warning is fine. Telling me I want pressure data and I don't have it. That's okay. But to fail to build when you, just because you don't have internet connection makes absolutely no Leo Dion (host): I don't, Huh. That is a Weird thing.
Or at least have a flag like. Matt Massicotte (guest): don't know that will, I don't know that it'll happen in all cases, but that's been a tough one that I've experienced. And I've also found, I found a lot of other SPM related problems where it's just, it can just be hard to use for more complex projects and I would love to see it just bug fixes Leo Dion (host): What are some of the problems you've run into with bigger projects?
Matt Massicotte (guest): I have this like, long standing issue with an SPM package that itself builds a c target. And if you do that, that works fine. unless it's part of a static library in an ex there's a combination of, there's a, there's like a combination of setup that will result in a just not working properly without a crazy workaround required. Leo Dion (host): XE frameworks and like.
I'll say thank God for like ai, because like I could not figure out how the, well even AI got it wrong, but like how to get to build multiple frameworks and then package 'em and like get that all in a GitHub workflow and all that stuff. That's been a huge godsend for me. But it's like there's some weird stuff with XY frameworks that didn't work the way I thought it would and yeah.
But. Matt Massicotte (guest): I'm not a huge, I mean, XI understand why XD frameworks, were created, but I find it really annoying Leo Dion (host): It's for a React native project, so you know, you pick your poison, Matt Massicotte (guest): no. Yes, I know. But what I mean is XD frameworks are like solving a problem that It's packaging up a whole bunch of different binaries for different architectures in one single thing, but like the Mac OSS executable format can do that. Leo Dion (host): mean.
Matt Massicotte (guest): It just turns out that like there is XD frameworks can do a little bit more than the Mako format can do, but like they could have made the MACO format more capable, and then XD frameworks would be Leo Dion (host): Yeah. Yeah, Matt Massicotte (guest): And I'm just disappointed. I under probably that was a very big technical problem to deal with, but I'm disappointed that Leo Dion (host): else you wanna talk about before we close out? No, I think this has been fantastic.
I. So there's, we all, there's gonna be a lot of kids in the back of the SUV who are gonna now understand on their Christmas road trip how to do Swift 6 thank you Matt. Where can people find you online? Matt Massicotte (guest): You can find me while my website is maico.org. And all the links to my, Leo Dion (host): Awesome. People can find me on all the social medias at Leo Dion ma on it's at Leo Dion at c Im.
If you're listening to this on your podcast player, please take some time to post a review, and if you're watching this on YouTube. Please like and subscribe. Thank you so much and I look forward to talking to you again. Bye everybody.