Poll: what do you strongly dislike about Swift?

Yeah, that's a huge one. The super frustrating thing is that if they would add in support for community plugins, with the proper APIs and internal hooks etc., then the community would provide an amazing vim plugin within no time, like exists for vscode. That's why the lack of community plugins (beyond the extremely limited surface area they allow) is such a big deal.

I understand that there are major security implementations in a product like Xcode that does code-signing, etc. But if they would take the engineering time they put into things like the lackluster vim support, and instead had those super smart people work on creating a safe, sandboxed set of APIs that they could expose to third-party community plugin authors, the results would be so much better, the community would build tons of stuff and make Xcode a truly delightful editor. Xcode right now is like Vscode without extensions -- a pretty good editor, but not customizable enough to adapt to me.

1 Like
  • if and switch being statements rather than expressions.
  • I love enums, but the case syntax is so ugly to me having come from OCaml, though I know there are people that hate the OCaml syntax so I suppose this is neither here nor there.
  • I know it's easy enough to work around, but every time I type .isEmpty and then have to go back to add the ! in front of the variable name I utter a mild curse.
  • Already called out, but tuples of Hashables not being Hashable.
  • error: closure tuple parameter does not support destructuring (sigh…)
  • Trying to use Swift on a notmac environment
3 Likes

As somebody whose instinct always goes there, and has pushed for that kind of extensibility and generality in review threads, I should note that I’ve already received thoughtful responses about why these things do belong in the compiler.

That’s not to say the “bolt-in” criticism is always wrong. In hindsight, differentiable programming probably never should have made it into the language. Distributed actors…it remains to be seen. I’m skeptical, but eager to be proven wrong!

Just saying that sometimes the “bolt-on” criticism is misplaced. People complained about property wrappers and function builders being too SwiftUI-specific, for example, but they’ve turned out to be wonderful and widely useful. That criticism was misplaced in that instance.

For a person like me who carries around a bit of that Ruby-ish instinct of “don’t make the language do it, make the language make it possible to do it,” sometimes the type safety, optimization, or system integration advantages of stuffing something into the language itself are surprisingly compelling once I actually understand the problem properly.

5 Likes

I dislike like phrase “hate about Swift,” which fosters unhelpful conversation, and focuses attention too easily on familiarity bias.

I do have a long-running list of Swift Wishes that stands as my answer to your question:

…and it’s been pleasing to see several of them addressed over the years! Number 1, in fact, is under the spotlight right now. Hooray!

10 Likes

We shouldn't assume that everyone has the same keyboard layout. A character that's difficult to find for one person could be right on another person's keyboard, and vice versa.

I agree. Everything we have in Swift is the result of thousands of people's tireless work, with the intention of providing the users with a better language. Even though people have differing views on what "better" is, it's not nice to hate something that's provided without being asked for anything in return. We shouldn't disrespect other Swift contributors and their work by hating it.

Don't be silly. Real programmers use magnetized needle and a steady hand.

It's perhaps not fair to treat Xcode's flaws as Swift's.

2 Likes

I am not saying those features are not good or useful. I have voted for many of them and I like and use them as appropriate. I have also read the justifications for why many of these features need direct compiler support.

I think such direct compiler support should be possible as a special part of the Swift library that implements the feature. Library code that runs as part of the compiler. LLVM is very pluggable and we have already added support for compiler passes written in Swift, but it is still far from where it needs to be. A big part of it is tied to C++ interop. All of the code that compiler is synthesizing now should be possible to write in Swift itself.

1 Like

Forgot to state my main concern:

These nice to have features are taking up all of the bandwidth of the developer team that would be better spent improving the foundation of the language that could benefit all developers.

The time each of these features take to implement is far less than the time it would take to implement those foundational features first and then building that feature on top of the new foundation. But these features add up and add to the codebase complexity and the maintenance burden.

After implementing most of the features that Apple needs, we reach a point where spending money on better foundations is no longer justifiable for Apple. Then the other features that really need those foundation will not economically be justifiable as well.

2 Likes

i would hesitate to make assumptions about how the technical debt of the codebase is structured just based on observing the feature set. a tool can have a very elegant feature model from the outside and be really terribly implemented on the inside, and vice versa.

my issue with unicode operators isn’t that i think they are intrinsically bad, i just think people are far too focused on “can i use √ as an operator?” and forgetting about “is there an ASCII alternative that provides the same expressive power but is more accessible for everyone to type?

for example, godot-swift could have used × as its matrix/outer product operator, but instead i ended up going with >< which can be typed with two ascii characters. it also led naturally to using >|< to represent cross products, which kind of evokes a set of 3D axes :slight_smile:

1 Like

I hate when I need to use NSError.

enum Foo: Equatable {
    static func == (lhs: Foo, rhs: Foo) -> Bool {
        switch (lhs, rhs) {
        case (.error(let e1), .error(let e2)):
            return e1 as NSError == e2 as NSError
        }
    }

    case error(Error)
}

enum Bar: Equatable {
    case error(NSError)
}

Is XCodeKit not sufficient?

Not my cup of tea either. Mine would be:

a.inner(b)
a.outer(b)
a.cross(b)

and a * b as a shortcut for one of the above.

2 Likes

Not sure there's anything I hate otherwise I'd not be using Swift. The biggest thing I miss from other languages is pre and post increment and decrement operators: i++ etc.. Yes, the main reason for using them in C-style for loops is irrelevant for Swift, but there are many other places you can use them, and when used they can make code more concise and expressive (I've read SE-0004 so know why they were removed but still miss them).

1 Like
I have a "fix" 😉
prefix func ++ <T: Numeric> (x: inout T) -> T {
    x += 1
    return x
}

prefix func -- <T: Numeric> (x: inout T) -> T {
    x -= 1
    return x
}

@discardableResult postfix func ++ <T: Numeric> (x: inout T) -> T {
    let y = x
    _ = ++x
    return y
}

@discardableResult postfix func -- <T: Numeric> (x: inout T) -> T {
    let y = x
    _ = --x
    return y
}

4 Likes

What kind of code prefix/postfix --/++ operators make them better than without? Can you show examples? I feel with --/++ code is more terse but may not necessary clearer. Perhaps I just don't get it.

1 Like

In code I use them similar to how I used them in C++ (release example below), but the real power and need if you make these ops atomic (either via atomic operations like OSAtomicAdd or via a mutex), the classical example would be:

func myretain() {
	++retainCount
}

func myrelease() {
	if --retainCount == 0 {
		delete()
	}
}

Having said that, it is of course possible to have it in a form of a function (which has the benefit of specifying an arbitrary increment value):

func myrelease() {
	if preIncrement(&retainCount, -1) == 0 {
		delete()
	}
}

The difficulty of testing fatalError/precondition/assert and other Never returning functions.

Your options are:

  • Never check for preconditions or use assertions
  • Check for preconditions, but leave these edge cases untested
  • Use a platform specific-workaround like CwlPreconditionTesting. For example, it doesn’t work on tvOS, and until recently, didn’t work on M1 macs at all.
  • … or resign to using the error mechanism for preconditions/assertions, causing all your functions to be throws, and thus precipitating an explosion of try.
    • Until recently, this property getters couldn’t be marked throws, and if I'm not mistaken, subscripts still can’t be.
10 Likes
  • subscript and operator labels
  • no optional first trailing closure label
  • open access modifier not applying to protocols
  • keypath requiring the hashability of the path (it's good but sometimes a real pain point)
  • well access modifiers below internal, there is just not enough flexibility, therefore I only use public and implicit internal and never anything else except open when necessary
  • callAsFunction naming scheme, as it could have been a nice and clean anonymous function instead
  • subscript not being treated as a keyword like func and requiring a space after it
  • the whole weirdness about associated type inference in combination with where clauses (What kind of magic behavior is this?)

I'll extend the list if anything else comes to my mind.

3 Likes

What do you mean? Can you show example code?

This is just a stylistic choice:

- subscript(…) -> Foo
+ subscript (…) -> Foo

You could argue that I would then treating init in the similar way, well yes and no.

If we had not callAsFunction but anonymous functions, then my mental model for init could be substituted with static func (…) -> Self. So what such init does, it removes the declaration boilerplate on both the lhs and rhs, so it's okay to treat it stylistically different.