-
Notifications
You must be signed in to change notification settings - Fork 0
Swift subset
I mentioned online recently that I don't feel that I "know Swift". It's just too big and complex. I write in a not-well-defined subset of Swift. Beyond the compiler bugs mentioned above, here's some parts that I avoid, because I know I'm not smart enough to be able to use them effectively:
-
PATs. I've read the docs and watched this video several times, and I can kind of understand the intent of the feature, and given some code I can probably tell you why it won't compile, but I'm really far from being able to use PATs myself.
- I've tried to use PATs in a few different cases. Every time, I end up wasting a couple days chasing down the craziest type-checker error messages I've ever seen. Or it'll work fine for a while, and then I'll discover 3 layers later that my original design won't possibly work in another case. So I always give up and just throw an
Any
in my protocol, document what it's supposed to be, and cast the sucker when I need to take it out. This takes about 2 minutes to do, and I've never once run into a type error from it.
- I've tried to use PATs in a few different cases. Every time, I end up wasting a couple days chasing down the craziest type-checker error messages I've ever seen. Or it'll work fine for a while, and then I'll discover 3 layers later that my original design won't possibly work in another case. So I always give up and just throw an
-
The C API. It's the most confusing C API I've ever seen. Worse, it changed completely every year for a while (though it seems to have stabilized a bit since Swift 5). You might not be able to avoid it (either for third-party C libraries you need, or even some of Apple's own libraries which only have a C interface), but you should absolutely minimize the surface area. Encapsulate the C API parts in a tiny Swift wrapper, so when you need to update it, it's one isolated place. Or you can replace it with a native Swift library, in the future, if they ever write one.
- In hindsight, I wouldn't have touched the Swift C API at all. What I should have done is write that part in Objective-C. Objective-C is a strict superset of C, and Swift is built to be a great Objective-C wrapper.
-
Callable types. I guess this is mostly for interop with dynamic languages that support this feature. You don't need it.
-
Any numeric types apart from
Int
andDouble
. For some reason, Swift made it painful to use other types, especially unsigned integers. Swift follows this guideline itself: even in cases where a negative number makes no sense (like counts or lengths), the stdlib uses signed ints.- The only case I've ever used other numeric sizes is when a C interface requires it, and even that's rare.
- Are you worried that you can't use the type system to enforce bounds? You can't do that for 99% of bounds checks, anyway. Your code is full of cases where you want to say "This is an integer from 1 to 100", and the type system doesn't support that. Use
Int
/Double
everywhere, andprecondition
for bounds checks.
-
All the crazy new string interpolation, including multiline string literals. I get why it exists, but just, ick. Too much.
- Plus, Xcode 12 still can't seem to offer any autocomplete inside string literals -- which is the one place I need it!
-
@escaping
/@noescape
. I do some pretty crazy async stuff, and I've only needed these twice -- when conforming to AppKit/WebKit protocols that require it. I've read descriptions of them a dozen times, and I still have no intuition for why they exist. Does it have something to do with Swift's use of refcounting? I've used a dozen other languages with closures and none of them needed this. -
@autoclosure
. I'm all for making code as short as possible (I won't typereturn
unless it's necessary), but this one just looks like a recipe for confusion. Spend an extra 2 characters and write it normally. -
propertyWrappers. These seem like a decent idea, and I've used similar functionality in other languages. It's just that the documentation looks awfully brief for how much functionality and how many rules there must be. All of Apple's official docs are mostly "here's a tiny demo, isn't it neat?".
- Plus, the compiler's error messages are bad enough. I don't trust them to say anything intelligent about how I'm inevitably going to misuse a wrapped property.
-
operators, precedencgroups, etc. Maybe this is useful if you're writing numeric code (though I'm not sure why you'd pick Swift for that!). Swift already has the most complex syntax of any language I've ever learned. I can't remember the precedence rules for the built-in operators. Please don't go adding new ones.
-
in-out parameters. These I actually understand just fine. I've just almost never had a use for them. I think I've used this maybe 3 times in my life, and even that was probably too much.
-
Key path literals.
-
some
-
Codable, except in trivial cases. I guess you need a good serialization system, but I'm no fan of Codable. It makes one trivial case easy, and doesn't seem to help at all for the 99% of other cases I care about. Or if it does, it's too complex for me to figure out.
-
Mirror. I would probably like this
-
Multiple trailing closures. OMG make it stop.
-
for
-where
. It's true I often need to loop on a subset of an iterator, but thefor
line is usually already pretty long, and we've already got perfectly good ways to do this that don't need new syntax.- The examples I see are always either
for o in objects where o.isActive
andfor i in range where i%2==1
, and none of my loop filters ever look anything like those.
- The examples I see are always either