|
I'm not sure that Swift was ever super beginner friendly. I'm thinking of protocols and how they mix with generics and associated types, as well as "class vs struct" ref/value semantics, in particular. But, anyway, I do agree that Swift is a mess now. Personally, I think the last salvageable version of Swift was 3. That's not to say that everything added since 3 is bad, but rather that they've done much more harm than good to the language since then. Examples: * Swift used to not have a Result type. Rather, you were supposed to mark fallible functions with the `throws` keyword, and the compiler would force callers to handle the possible failure. However, that didn't work with so-called "escaping" callback functions that are passed as arguments and then held to be called at a later time, because there may be nobody around to handle the failure when it's called. (This is as opposed to some functions that are marked as `rethrows`, which guarantees that they execute any callbacks immediately, and therefore can be passed `throws` functions/closures. So, then they added the Result type. The reason this sucks is because now there are two ways to define a fallible function: either mark it `throws` or make it return `Result`. What's even more infuriatingly inconsistent is that a function that is marked `throws` does not specify the type of the `Error` that it throws; however, the `Result` type is actually `Result<T, E>` and does specify the `Error` type. So, which is it? Are we supposed to care about the specific error types or not? Of course people will come up with some rule of thumb or convention around when to use which, but I think it's clear from how the language evolved that this was more-or-less a design back-track. * Swift has an unapologetically imperative syntax. Almost nothing is an expression, and even handling null/nil involves imperative constructs like `switch`, `if let` and `guard let` blocks. That's fine. It's not my favorite syntax style, but whatever. Until Apple decided that super-imperative code isn't that elegant for writing UI logic. So, they tacked on this God-awful "result builder" syntax/API/feature with annotations and arcane syntax/semantics that is completely out of place in the rest of the language. I feel the same way about property wrappers and dynamic member lookup. They are totally out of place with how the core of the language works. |
In C these operators, paired with pointer arithmetic, allow you to write either incredibly terse yet correct implementations (e.g. strcpy as one liner) or more often in practice, conceal horrible defects where your code is hard enough to read that nobody spots the mistake. If it is the 1970s where you are, your CPU might have an increment instruction, and your compiler might not be smart enough to spot that x += 1; is also an increment. So when C was invented this isn't crazy at all.
C++ inherited them from C, for whatever that excuse is worth in the 1980s.
But in a modern language you should either abolish them entirely or, if you can't bear to do that, neuter them enough that most of your programmers won't manage to blow their whole foot off when they try to use them. Swift chose to abolish them. Go keeps an increment operator but you can't use it in expression context, so that way it doesn't have pre/post-increment.
So, to me that's pretty obviously an improvement in Swift, even if it's incompatible.