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