4 ms·
I like a lot about Swift: strong typing, good support for closures, reasonable abstractions. But there's a lot that I dislike too. A lot. In general, I find the
by geophile 7y ago
I like a lot about Swift: strong typing, good support for closures, reasonable abstractions. But there's a lot that I dislike too. A lot. In general, I find the language to be far too trendy and fussy. I get the impression the design was guided by the goal of streamlining snippets of code meant to highlight cool features, gaining undesirable complexity as a result. One example: Do we really need $n function parameters? In just about every other language, a function has parameters, period. Those names are used inside the function. Depending on the language they may be used outside the function too. Swift separates those inside and outside views, permitting different names for both. And then allows for no names at all! I don't care. $n parameters seem to come from primitive languages like sh, and should have stayed there.
get/set/didSet introduces ridiculous complications just so we can pretend that a large number of function invocations look like assignment statements. This was a cool idea in C++, briefly, and then we discovered that having arbitrary code hide behind what looks like an ordinary assignment statement was a bad idea.
Extensions also remind me of C++ excesses. It is difficult to look at a piece of code involving a variable some type and be sure that I understand how that type works. The problem is that the code implementing the type is not in one place. There is the type definition, but then there are extensions. Possibly many of them. Defined all over the place.
I really dislike the irregularity surrounding let. In one context in unwraps an Optional. In another context it does not. Why?
I got off the Swift train at the release in which associated types were introduced. I'm sure it solves some actual problem, but it sure wasn't clear at the time. (The project ended -- it's not that I decided to go back to Objective C.)
Reference counting is far too intrusive, and it is easy to get it wrong in subtle ways. I find Java's (!) memory model relatively simple, and that's saying something. I understand why reference counting was chosen over GC. I don't have a good answer, but reference counting is just ugly. I actually think I prefer the C/C++ model of explicitly freeing memory.
- setpatchaddress 7y agoI certainly don't disagree that there's too much C++ in Swift (the Swift architects write C++ for a living, not ObjC, so it's hardly surprising) but it's not due to trendiness. Most of the features you mention derive from direct experience with Objective-C. Function arguments, property accessors (get/set/didSet), extensions (categories), etc. Every one of these things solves a real problem in the field. I don't understand your comment about reference counting being intrusive. Apple's implementation, ARC, used in Swift and modern ObjC, is essentially invisible to you if you're using native objects.
- geophile 7y agoI don't agree that get/set/didSet solve actual problems. Languages without property accessors do just fine, but then they don't overload the getting and setting of variables. I would much rather right thing.setField(123), and have setField do whatever actions need to accompany the assignment; than write thing.field = 123, and then have the actions be hidden. What is so f'ing special about x = thing.field and thing.field = x syntax? Why is it so important to stuff additional semantics into that syntax? As for reference counting: I'm referring to capture lists, and the "unowned self" hack needed with closures. E.g. https://www.raywenderlich.com/966538-arc-and-memory-management-in-swift#toc-anchor-011 https://www.raywenderlich.com/966538-arc-and-memory-manageme.... And it gets more complicated with @escaping. I sure don't view all these subtle interactions of closures and ARC to be invisible. This stuff is subtle. Get it wrong and you have leaks.
- fauigerzigerk 7y agoI agree. Here's an article that has really opened my eyes on how subtle reference cycles can be: http://marksands.github.io/2018/05/15/an-exhaustive-look-at-memory-management-in-swift.html http://marksands.github.io/2018/05/15/an-exhaustive-look-at-... I have pasted the most egregious example here: https://news.ycombinator.com/item?id=21919728 https://news.ycombinator.com/item?id=21919728
- fauigerzigerk 7y ago>I don't understand your comment about reference counting being intrusive. It's intrusive because you can never really stop thinking about it if you want to write correct code. Here's an example from a very interesting article by Mark Sands [1]: How quickly can you tell whether or not this piece of code has a reference cycle? class ServiceLayer { // ... private var task: URLSessionDataTask? func foo(url: URL) { task = URLSession.shared.dataTask(with: url) { data, response, error in let result = // process data DispatchQueue.main.async { [weak self] in self?.handleResult(result) } } task?.resume() } deinit { task?.cancel() } } In my view, reference counting does not combine very well with heavy use of closures. [1] This is an interesting read: http://marksands.github.io/2018/05/15/an-exhaustive-look-at-memory-management-in-swift.html http://marksands.github.io/2018/05/15/an-exhaustive-look-at-...
- skohan 7y ago> Swift separates those inside and outside views, permitting different names for both. The named parameter handling is one of my favorite features of Swift. It makes Swift code self-documenting in a way most languages aren't.
- geophile 7y agoI actually don't mind that feature too much. I do appreciate that it clarifies code with even a few arguments of the same type. Although there are other ways to clarify such situations in other languages. The Swift approach does lead to exceptionally verbose code, but that's obviously subjective. It's the $n syntax that I think is overkill. Do we really need three different ways to name parameters?
- skohan 7y agoYeah to each her own I guess, but I don't mind the $n syntax either. It's only relevant in closures, and in my experience it's mostly used in simple, short closures where the identity of the parameter is obvious. So for example if you are doing a simple map: let incremented = myArray.map { $0 + 1 } the $n syntax just lets you save a little bit of typing. In my opinion it often makes the intent clearer when reading a line of code, since having to explicitly name the variable here adds noise which isn't really meaningful, especially in the case where you have a chain of map/reduce/filter operations. I would put it in the same category as Rust's `?` operator, which saves you from typing a bunch of unwraps or match statements everywhere.
- tonyedgecombe 7y agoI assumed it was there for compatibility with Objective-C, I can't imagine any other justification.
- skohan 7y agoWhat would it have to do with Objective-C?
- lokedhs 7y agoWhy was refcounting chosen? It seems to me it was only done because the designers were so used to C++ that they don't understand the drawbacks of not having it.
- pjmlp 7y agoEasy, interoperability with Objective-C runtime and Cocoa refcounting patterns.
- lokedhs 7y agoBut didn't some version of Objective-C use a GC? My understanding was that the reason it didn't work well was because of issues with the language and not the libraries. So they could still have used a GC for Swift?
- pjmlp 7y agoThe reason it did not work was indeed the language, given the underlying C semantics of Objective-C. However Objective-C ARC is basically the compiler taking care of Cocoa retain/release patterns. Swift needed to provide a seemless path forward to integrate with Objective-C libraries so reference counting was the easist way forward. Microsoft has chosen another way to interoperate with COM from .NET, which requires an additional layer. https://docs.microsoft.com/en-us/dotnet/standard/native-interop/runtime-callable-wrapper https://docs.microsoft.com/en-us/dotnet/standard/native-inte... https://docs.microsoft.com/en-us/dotnet/standard/native-interop/com-callable-wrapper https://docs.microsoft.com/en-us/dotnet/standard/native-inte... Although is is quite alright to use, it adds an additional complexity that most likely Apple wasn't willing to make use of.
- lokedhs 7y agoSo if I understand it correctly, Apple decided to move that complexity to the language itself? I was reading up on the rules for references in Swift, and it looks like a lot of complexity and lots of opportunities for introducing errors leading to leaks.