Which (breaking) changes would you be willing to accept in a major language release? [+ Feature wishes]

I'd like to see compilation conditions back on the drawing board. I really like that they're part of the compilation rather than just string processing, but they're too simple and feel like a forgotten cousin.

Given this thread I'd love to see the related subject of Swift meta language rethought. To that end I'd like to be able to replace gyb (see string processing comment above) with result builder executed at run time to create any Swift eg types.

1 Like

I'd like to see that the enum type has the same features as struct. Currently, enum is incomplete compared with struct.

2 Likes

Adding one more to my list:

  • Removal of callAsFunction in favor of anonymous functions: func (...)

If we then added named subscripts this would align very well:


struct S {
  func name(...) {}
  func (...) {} // instead of `func callAsFunction(...)`
  subscript (...) {}
  subscript name(...) {} // new
}

let s = S()
s.name(...) // calling a named method
s(...) // calling an anonymous method
s[...] // calling a subscript
s.name[...] // calling a named subscript 

And it would signal on why we really need to fix subscript label rules.

10 Likes

I’d be in favor of func _() similar to how we can write func hey(_: Int) {}; hey(_: 0). But all in all, I don’t see why folks are so against callAsFunction. Yes, it’s not the most natural syntax for Swift but it isn’t worth a breaking change in my opinion. Subscript arguments are a blatant exception to Swift’s argument syntax for functions, which are much more commonly declared.

4 Likes

I spoke too soon. Never mind. [Retracted my comment on _().]

Sorry if my post came off as aggressive or overly opinionated. I was honestly asking about the arguments for superseding callAsFunction because I haven’t really followed related discussions.

The thing is it's not syntax at all, it's a special-cased stringly-typed function name that magically gets turned into an anonymous method. It goes against all compile-safe philosophies of Swift, and, although it's a very minor feature, is hands-down one of the most sub-standard evolution acceptances.

1 Like

you are talking about @dynamicCallable, which is different from callAsFunction.

anonymous member functions cannot be passed as an object.

elements.map(self.callAsFunction(_:))

this is one of the pain points of subscripts, which need closure literals to be used functionally, and i for one am glad we did not go down this route for functors.

4 Likes

I'd like to see some improvements to:

  • Type Metadata. .Type, and .Protocol changes voice already, but improvements to Mirror, or a newer API would be appreciated.
  • Tuple, Variadic, and Function parameter list, and fixed size array changes. Personally, I'd be up for a nice mental model for these types and how they compose, even if it introduces a little bit more syntax noise.
  • A string datatype which enables python like usage. In my experience I've found solving Project Euler problems much less convenient than Swift, and yet the indexing patterns are pretty much the same.
1 Like

I quite like this, it's very natural, symmetric and it can be almost introduced as a non breaking change (if to deprecate callAsFunction instead of outright removal), but indeed subscript labels rules deserve to be straightened even if that's a breaking change on its own.

I do like the general direction. It doesn't sit well in my mind that callAsFunction (and to a lesser extent subscript) looks like an everyday function but is actually tied into syntactic magic. With Python's dunder sugar (__foo__) there's at least a hint that something special is going on (especially if it's a new corner of the language I've never used or seen before).

2 Likes

people want named subscripts because until very recently, it was not possible to vend mutable views on types with storage. now that we have _move(_:) on mutable self, i can’t think of many situations where i would want to use a named subscript instead of a full-featured nested type. it helps keep the base type from becoming cluttered with views.

1 Like

Don't worry, I was commenting on the _ part when I later realized that my comment partly didn't made any sense so I removed it. ;)

1 Like

If we REALLY wanted, we could have allowed a leading dot to refer to an anonymous function self.(_:). There is no big difference between that and callAsFunction except that it's possibly easier to parse as a human. ;)

My guess is that we can still make self.[_:] possible to refer to a subscript.

While you're not wrong, there is always have been a solution for absence of things like toggle(), yet sometimes the convenient part still wins. Requiring the user to do a 'move' dance and coming up with view types to solve this problem smells a lot like unnecessary boilerplate enforcement to me.

However I personally don't want the discussion to derail any further into those specifics. :ok_hand:

3 Likes

Perhaps not many. Consider this one for example.

Maybe just me, but subscripts are nicer / more obvious / cleaner.

I'd add generic parameters to that list — actually, I'd put that on the first position...

1 Like

If we're making breaking changes, I'd love to go back to the (now abandoned) plan of moving unapplied method references from curried functions (Self) -> (Args) -> Result to regular functions (Self, Args) -> Result. Keypath support for methods is nice, but I'd still like usable unapplied mutating methods.

2 Likes

Another one is that Set is not the same same as Set<_> inside extensions with additional constraints on elements:

extension Set where Element == Int {
  func dummyFunc() -> Set<String> {
    Set(map(\.description))
    // ❌ Cannot convert Set<Int> to return type Set<String>
  }
} 

It always catches me off guard. I’d rather have to use Self or fully specify the generic parameters.

2 Likes

Removing inheritance from the language (I'm only half kidding)

9 Likes

Some interesting things brought up and I agree with a lot, disagree with a few :laughing:

  • My biggest wish to fix if we are talking about breaking changes is Default Protocol Implementation Inheritance Behaviour - The current situation and what/if anything should be done about it Its tripped a lot of people up and addressing it would smooth out a rough and very unexpected area of swift.

  • I might be one of the few people who actually like the basic Codable, but as soon as you move outside of a 'standard' workflow it fails quickly. It would be great to address some areas around this to make it much more flexible and hopefully gain some speed. Some lessons could be learnt from Rust's Serde.

  • I also really miss having named arguments in tuples. I understand the arguments as to why they were removed, but it just feels like removing useful information from the language.

4 Likes