Poll: what do you strongly dislike about Swift?

Having to manually write type erase, can't the compiler just do it?! Or the need to type erase at all. Seem so very stupid to me.

.foregroundStyle(flag ? AnyShapeStyle(.tint) : AnyShapeStyle(.orange))

What? why do I have to do this? Both are ShapeStyle!

3 Likes

Indeed, those areas of SwiftUI do not feel polished. Note, this is work in progress, I remember before I had to use things like "AnyView" much more often than now.

A few things from me:

  • "Protocol 'X' can only be used as a generic constraint because it has Self or associated type requirements"
    (I didn't follow recent discussions, hope this is somewhat relaxed in the upcoming versions of Swift).
  • hard, error prone and generally unsafe to use swift in realtime code.
  • stack overflow crash in deinit (e.g. simply assigning a linked list top to nil causes that, where list holds some 50K - 100K nodes).
  • can't declare variables in extensions (same module use case).
  • JSONEncoder/Decoder/Codable inflexibility (irt nil, default values, date formats, etc).
  • Extension outside of file declaring struct 'X' prevents automatic synthesis of '==' / 'hash(into:)' / 'encode(to:)' for protocol 'Equatable' / 'Hashable' / 'Encodable' (even when X is some very simple struct... if I can do that boilerplate manually why can't compiler?)
  • declaring initializer in a struct body disables default synthesized initializer and there is no way to opt-in it back unless i move my initialiser into an extension.
  • no way to have a synthesized initializer in classes.
  • T? not being exactly the same as Optional<T>.
  • cumbersome enum case checking.
  • the foot-gun of "Data" subscript being typed "Data" (not data slice).
  • CGFloat mere existence and associated issues.
  • Swift mostly lexical access control rules.
  • I would drop here two other things:
    • ability to use arbitrary unicode symbols in identifiers (like emoticons):
      let 🐶🐮 = "dogcow"
      let →→→ = 123
      var 𓂸 = "wtf"
      var foo = 1; var fоо = 2 // the second foo is not!
      (the last one is called homograph attack)

    • ability to create custom operator symbols (even ascii!). Talking about defining a new operator symbol (like operator |%&^>>, not about a custom implementation for some existing operator symbol like "func +"):
      infix operator |%&^>>
      infix operator ≸
      prefix operator ?!
      (I don't use those two features myself and hate when I see them in other people code I have to deal with, though I admit this is subjective. I believe removing these features would make Swift simpler and overall better, not worse.)

7 Likes

String handling. Not so much hate as dread.

12 Likes
let tupleKeyed:[(Int, Int): String] = [:]
enum DateError:Error
{
    case invalid(month:Int)
    case invalid(day:Int)
}  
struct Outer 
{
    struct Index 
    {
    }
    struct Thing 
    {
    }
}
extension Outer.Thing 
{
    subscript(index:Index) -> Int 
    {
    }
}
var literal:[UInt8] 
{
    // '::SYNTHESIZED::'
    [
        0x3a, 0x3a, 
        0x53, 0x59, 0x4e, 0x54, 0x48, 0x45, 0x53, 0x49, 0x5a, 0x45, 0x44, 
        0x3a, 0x3a
    ]
}
zip(left, right).map 
{
    (item:(Left.Element, Right.Element)) in
    ...
}
for (left, (middle, right)):(_, (_, _)) in zip(left, zip(middle, right))
{
}
2 Likes

I think one thing which makes Swift great, and a much greater language than many other languages of its generation, is that its creators didn't assume that they knew exactly how the language would be used or what its feature set should be.

I basically never write custom operators, but one of my first Swift programs was a hashing algorithm. Hashing often involves bit-twiddling, and Swift offers both binary NOT/AND/OR operators (~, &, |) and bit shift operators (<< and >>). What it doesn’t offer is a rotation operator, even though rotation is a common operation in CPUs. Thanks to Swift’s open-endedness, I could, as a novice, create a rotation operator >>> and write a more succinct algorithm than otherwise.

And I wouldn’t have been able to do that in other languages.

10 Likes

i like the custom operators in principle. non-ASCII unicode operators were a terrible idea.

4 Likes

Tools.
Swift debugger fails to print the value of a variable a lot of the time, and even when it succeeds it might print a different value than the one in a real program

Installing swift on linux is an awful experience The current state of Swift for Server and Linux - #18 by cukr

sourcekit-lsp is incomplete, lacking stuff like formatting and global rename

I dislike Xcode in general, for example spm integration is done poorly.

15 Likes

How are they different?

For me, it is the bolt-on feature creep of recent years. There are too many features added for the pragmatic reason of urgently addressing some specific needs of Apple framework API developers without putting enough time and effort into keeping the logical foundation of the language simple, sound, consistent and orthogonal.

We should have used this time and effort to design some foundational enabling features that would make most of these (now bolt-on) features into library-defined extensions of the language written in Swift itself instead of being baked into the compiler and written in C++.

There are also some regrets about some of the original design choices. (If you haven't seen it already, check out @jrose 's insightful Swift Regrets series.)

My biggest regret is the choice of Int as the Collection.Index type of Array. The semantics of Collection should require Index to be opaque and it should not be possible to construct or manipulate it without using the Collection API.

What we needed instead (that now we can't have), was an Int subscript on RandomAccessCollection as the offset into the collection elements. This would let us address Array (and its slice) elements with always zero-based Int offsets (as opposed to indices). This would make a consistent and well-defined Int offset available on all random-access collections.

We could also define special meaning for negative offsets to indicate reverse offset (offset from beyond end or endIndex) which would make a[-1] the always valid way to refer to the last element of any non-empty array. That would make addressing and slicing relative to the end of an array very easy.

15 Likes

i believe she/he is referring to What is a 'variable initialization expression'?

1 Like

Not as terrible as ASCII-only operators. I quite like being able to use ° for degrees, for instance.

12 Likes

Actually, they are one of my favorites and I (ab)use them often.

It depends on the domain. They are very useful for domain-specific libraries that manipulate domain-specific currency types.

3 Likes

how do people using your library type them? for that matter, how do they google them?

These are not typical libraries meant for general consumption. Professionals (engineers/scientists) know what those currency types represent and what those custom operators do. It helps them translate something close to their normal engineering/scientific notations for those concepts into Swift programs.

9 Likes

An example of this is SE-0293 xtend Property Wrappers to Function and Closure Parameters: something wrong at the call site, the compile error show up at the function definition.

Or property wrapper composition: it only work in some cases.

2 Likes

enum case comparison (with associated values) - almost always the associated value needs to be ignored

4 Likes
  • The compilation speed.
  • Doing anything with generics regularly makes me wish I was writing C++. Swift's compiler errors with generics are usually entirely worthless beyond reporting that there's a type error of some sort. The lack of a spec and incomplete implementation means that I'm often not sure if I'm doing something invalid or if it's something conceptually valid that just isn't implemented yet (or sometimes it turned out I did something invalid which accidentally worked).
  • Everything related to Codable.
  • All the brittle compiler magic that makes 80% of scenarios nice and the other 20% awful because the compiler magic is there instead of an important feature.
  • Result builders.
7 Likes

Generic function parameters cannot have default values:

This doesn't compile:

struct Foo<S1: ShapeStyle, S2: ShapeStyle> {
    init(s1: S1 = .tint, s2: S2 = .primary) { }
}

so you wonder why doesn't it work?

Pretty this is fixed in Swift 5.7.

1 Like

Huh?

let optional1: Int? = nil
let optional2: Optional<Int> = nil

let same = type(of: optional1) == type(of: optional2) //true
1 Like