DEV Community

Swift Classes — The Four Ways Variables and Constants Can Combine 🎭

Gamya on July 23, 2026

A constant class can have its properties changed. A constant struct can't. This sounds inconsistent until you remember the signpost — and then it m...
Collapse
 
publiflow profile image
PubliFlow

Solid mobile development content. Cross-platform is compelling but the native integration layer often determines success — have you found that custom platform channels or native module integration becomes a bottleneck?

Collapse
 
gamya_m profile image
Gamya

Thanks for reading! This series is focused on native Swift/iOS development for now, so cross-platform integration is a bit outside the current scope.

Collapse
 
publiflow profile image
PubliFlow

Focusing purely on the native ecosystem makes perfect sense, especially when diving into the specific memory management and lifecycle quirks of Swift classes. Mastering these core language features first is definitely the right approach before worrying about cross-platform abstractions. Do you plan to cover how these native variable patterns influence overall architecture decisions in larger iOS codebases later in the series?

Thread Thread
 
gamya_m profile image
Gamya

Yes, definitely planning to get there! The series is building toward real app architecture gradually, so once the language fundamentals are solid the plan is to connect them to how you'd actually structure a larger SwiftUI codebase, where class vs struct choices, access control, and memory management all start to matter in ways that aren't obvious from small examples. Still a few topics away but it's very much on the roadmap. 😊

Thread Thread
 
publiflow profile image
PubliFlow

That progression from core fundamentals to real-world SwiftUI architecture is exactly what developers need to see. Watching how memory management and class versus struct decisions actually impact a larger codebase is where the real learning happens. I am curious to see how you plan to tackle state management and dependency injection when you bridge that gap.

Thread Thread
 
gamya_m profile image
Gamya

Those are exactly the topics I'm looking forward to getting to, state management especially since it's where the class vs struct decision stops being theoretical and starts having real consequences for how data flows through the app. Dependency injection is a bit further down the road but it's on the list. The plan is to build toward those naturally through the series rather than jumping to them early, so by the time they come up the foundations should make the architectural choices feel obvious rather than arbitrary.

Collapse
 
merbayerp profile image
Mustafa ERBAY

I like the “signpost” analogy—it makes the let behavior much easier to visualize.

One thing I’d add is that this distinction becomes much more important when designing APIs than when just learning the language. A let reference to a class often looks immutable, but it doesn’t guarantee immutability unless the object itself is designed that way.

That’s one reason value types (struct) are often preferred for models in Swift. Their immutability is much easier to reason about, especially when passing data across threads or between different parts of an application.

So the interesting distinction isn’t just reference vs value—it’s reference identity vs state mutability. Once those become separate concepts, the behavior feels completely consistent.

Collapse
 
gamya_m profile image
Gamya

"Reference identity vs state mutability" is the precise distinction that makes the whole thing click — because the confusion usually comes from treating them as the same thing, which works fine for structs but falls apart for classes. A let reference guarantees identity stability (this variable always points at the same object) but says nothing about state stability (what that object contains can still change freely). Once those are properly separated in your mental model, the behavior stops feeling inconsistent and starts feeling like a deliberate design choice about which guarantee you actually need.

The API design point is the one I hadn't emphasized enough — because in a learning context the examples are self-contained enough that the practical consequences of "looks immutable but isn't" don't really surface. In a real API, a caller receiving a let reference to a class instance has no way of knowing whether the object's state is safe to cache, share across threads, or rely on not changing between two function calls. That's exactly the gap that makes structs the default preference for models — the immutability guarantee is structural rather than just conventional, which is a much stronger thing to hand to a caller. Really appreciate you adding this layer.

Collapse
 
merbayerp profile image
Mustafa ERBAY

Exactly. And that’s where API contracts become more interesting than language syntax.

Identity stability tells me what object I’m talking to, but state stability tells me whether I can safely reason about it over time.

That’s also why Swift’s modern concurrency model leans so heavily toward value semantics and Sendable. An immutable value can cross isolation boundaries with far fewer assumptions than a shared mutable reference.

So I’d say the question isn’t “class or struct?” but rather “do I need identity, or do I need predictable state?”

Thread Thread
 
gamya_m profile image
Gamya

"Do I need identity, or do I need predictable state?" is such a better question to ask at the design stage than "class or struct?", because it forces you to think about what the data actually needs to guarantee rather than reaching for a type and then working backwards. Identity tells you who you're talking to across time, state stability tells you whether what they tell you is safe to rely on. Most of the time in a data model you need the second thing and don't actually need the first, which is exactly why structs end up being the right default for most models.

The Sendable connection is the one I'm looking forward to covering properly when the series gets to concurrency, because it makes the value semantics preference structural rather than conventional. An immutable value can cross isolation boundaries because the compiler can verify there's nothing to race on. A shared mutable reference requires explicit coordination that the programmer has to get right every time. Same principle as the API design point, just enforced at a different level. Really appreciate this whole thread, it's covered territory the article itself didn't reach.

Thread Thread
 
merbayerp profile image
Mustafa ERBAY

I think that’s also why Swift’s evolution has consistently pushed developers toward making semantics explicit instead of implicit.

Value semantics, Sendable, actor isolation, ownership… they’re all solving different problems, but they’re built around the same idea: make the guarantees visible to both the compiler and the programmer.

Once you start thinking in terms of what guarantees your type provides, many language features stop feeling like separate rules and start looking like pieces of the same design philosophy.

Really enjoyed this discussion. Looking forward to the concurrency part of the series. 🙂

Thread Thread
 
tenporo profile image
Tenporo • Edited

You're absolutely right: Swift's evolution is a story of the transition from implicit conventions to explicit architectural guarantees. When the compiler takes on the role of a strict enforcer, developers no longer need to keep hundreds of implicit nuances about thread safety in mind. A lengthy payout process often spoils the overall experience, even during the most successful and profitable sessions. Innovative Fast Payout Casinos lgl.io/ solve this problem, ensuring that players retain only positive feelings from their wins. Quick access to their winnings allows players to feel in control and motivates them to return to the platform again and again.