I am trying to understand why the below syntax is valid. It seems contradictory, but the code compiles, and it appears to behave as if nonisolated is not present.
nonisolated actor Counter {
var counter = 0
func increment() {
counter += 1
}
}
I tested the above and await is still required to call increment and I don’t see any race conditions when I ran multiple iterations.
hi, and welcome to the swift forums! i believe this is pretty clearly a bug – this used to be rejected in the Swift 6.0 compiler, but began being accepted in 6.1 (see this example). i would recommend filing a bug report.
as an aside, it seems like there are numerous related issues with various attributes being erroneously accepted on actors when they presumably should not be (exhibit A, exhibit B).
Since an actor is just a ClassDecl under the hood, the compiler will accept any attribute that is allowed on a class, even though some might not be meaningful with an actor. Someone needs to go through and ensure anything meaningless (like open, final, and nonisolated) is properly rejected in this case.
Since an actor is just a ClassDecl under the hood, the compiler will accept any attribute that is allowed on a class , even though some might not be meaningful with an actor.
yes, i assume many of the issues here stem from the fact that actors piggy-back off of 'normal' classes for some (most?) of their implementation. that, plus the fact that in some of the initial design pitches/proposals/prototypes it seems like actor was being considered as potentially something of a kind of 'class modifier' rather than becoming more of its own 'category of thing' (IIUC, actor class or some such used to be valid syntax in an implementation prototype at some point).
it's unfortunate that these inconsistent/meaningless declarations weren't more aggressively rejected since apparently failure to do so may lead to runtime issues in some cases (see 'exhibit A' from above), and it also makes it more painful to fix due to source breaks. but i guess that's how it goes sometimes.
Yeah, the way the compiler is architected, anything not explicitly rejected, is accepted. It would be better if it was the other way around but I don’t know if that’s possible to do in a systemic way.
the attribute was added in this PR, and there is some discussion about it in the comments (well, some related-sounding things at any rate; though i can't say i follow it all). there's also some discussion about it in this pitch thread for custom executors (Chris & John discussion starting here).
the final attribute is marked as ABIBreakingToAdd | ABIBreakingToRemove in this source file, which suggests it can't necessarily be freely adopted/dropped. additionally the output of this godbolt example suggests its presence may impact type metadata and descriptors.
final is not meaningless on actor, unfortunately. When actors were first introduced, the door was left open to potentially amend the language to allow them to be subclassed. That has not happened and probably never will, but the ABI for method calls on actors go through dynamic dispatch in case there's actually a subclass present at runtime. That means that marking an actor method final, or marking the whole actor final, changes the ABI of calling methods on the actor since calls will no longer go through dynamic dispatch. There probably are other attributes that we can start rejecting on actor declarations, but I don't think final is one of them.
thank you for the clarifications and additional context Allan! i need to read up on the difference b/w public and public final to better understand what the implications of this are... but it seems unfortunate if developers need to explicitly write final on these types to opt out of dynamic dispatch, when that attribute is at least implied to be inapplicable/implicit in various ways (e.g. like when you try to make one actor inherit from another and it fails). i was thinking perhaps this could be phased out with a warning now + error later, but if there are ABI implications, that's presumably a less straightforwardly plausible option. perhaps there's still something that could be done though...
fluff: this is how i read this :)
When actors were first introduced, the door was left open to potentially amend the language to allow them to be subclassed.
Actors as commonly imagined across programming languages have identity, almost by definition. If Swift had something called an "actor" that was a value type, it would probably cause too much confusion, even if it made sense as a feature in itself.