Hacker News new | comments | show | ask | jobs | submit login

So, I'm deeply involved in Swift, in the sense that: I write the odd compiler feature.

From my vantage point it seems to be the opposite of your analysis. While it is true that ObjC's dynamism has all kinds of problems we want to avoid, we're also running into lots of cases where the obvious solution is dynamism, and the other solutions aren't obvious.

One concrete example I can offer you is NSCoding, which is being reimplemented right now in corelibs-Foundation. That API pretty much needs a way to look up classes at runtime, (there's really no other sane way to provide the feature). You could argue that we don't need NSCoding (in fact that was argued), but ultimately, we decided we needed NSCoding more than not. So Swift 3 adds a `_typeByName` API which does dynamic lookups of classes by string. It landed, it exists, the ship has sailed.

Another concrete example that may be interesting is XCTest. The way XCTest works is your unit tests are written as functions on a class, and we "discover" the tests by enumerating the functions at runtime. But oops, Swift has no way to enumerate functions at runtime, so we can't find any of your tests. The solution to this problem is actually pretty interesting: the latest proposal is to do sourcecode analysis from the compiler to enumerate your test functions, dump that somewhere, and then generate a second program that uses the dump to call the enumerated functions.

Now that is very interesting, and certainly less dynamic than ObjC (e.g. no method_exchangeImplementations and other nonsense), and I would argue quite a lot saner for the scope of the XCTest problem. But it follows easily that as soon as we do that we could emit a program that uses that same function enumeration to emit a giant switch statement that does dispatch-by-string. Of course it would be opt-in, so only callers that wanted it would use it, but there's nobody to stop you.

All of that to say, I think what is actually happening inside Swift is we're coming up with more structured kinds of dynamism, rather than a knee-jerk reaction against the ObjC philosophy. ObjC's model certainly has its issues, and we have gotten surprisingly far without really much dynamism at all. On the other hand, Swift constantly hits cases that are "solved" by ObjC's dynamism, those are definitely real (doesn't get more real than the core libraries), and dismissing them out of hand would be stupid. Meanwhile it takes time to come up with solid "structured" approaches to all the various cases people use dynamism in the wild, so it will be a long process of enabling more and more kinds of dynamism over time.

As for the ObjC runtime, we will not actually have it for years. Maybe on Apple platforms. But the decision has been made not to ship it for Linux, and Linux is of course the next big frontier for Swift. All code that wants to run on Linux (or run on both platforms) better not use the ObjC runtime for anything ever. So this places increasing pressure on designers to figure out what our answer to all the dynamic usecases will be, because there is no seatbelt to save you on one of our platforms.

Basically, I would very much not be dismissing these critiques out of hand. They are not (other than a few) arguing for a return to ObjC. But they are raising issues not seriously solved by Swift at present, and we need to be uncovering those and putting in the design effort to generate solutions for them.

There's definitely some nuance to this situation – I didn't mean to imply dynamic features aren't needed, or have no place. While writing my comment, there was a nagging voice in my head saying "What about Swift Foundation?"

What I meant to communicate was that there's a histrionical air to most of the commentary that is unfounded. We don't need to be able to reimplement Rails, or KVO, or Core Data – we need to come up with new ways to solve those problems with an approach like you're seeing working in practice, a more structured dynamism. And for what it's worth, all of those problems deserve another try at an answer. They're some of the most tricky parts of the platform.

Other than "we want to rewrite Foundation/XCTest in Swift", why do we need XCTest or NSCoding implemented in Swift? Neither is particularly Swifty - many things in Foundation that ought to be structs are classes, for example, and there's the nonsensical duplication of String/NSString/NSMutableString and the other containers.

If you want a Swifty testing framework, just pass a bunch of test functions to a function, or define a test case protocol. Similarly, a coding-style protocol can be represented as an encoded associatedtype and encode/decode functions. Plus, you can throw in the decode instead of having to return nil with no explanation.

> why do we need XCTest or NSCoding implemented in Swift?

Linux compatibility. As long as Foundation is written in Obj-C it can't be ported.

I get that it's necessary for running them on Linux, I just question the need to do that in the first place, instead of creating new, Swiftier APIs. NSURLSession's delegates have optional requirements, for example, which aren't supported in pure Swift code.

Regarding XCTest, could you extend Mirror to provide methods as well as fields? That seems to me like it would be a more natural solution.

For what it's worth, that's my preferred solution in the long-term too.

Speaking narrowly about the XCTest case:

* It doesn't actually require runtime dynamism (since you have a finite number of tests that can be statically enumerated). Following the principle of least power, don't do it if you don't have to.

* A runtime-dynamism-based solution would require `dynamic` sprinkled on function definitions which would be a departure from source compatibility with Darwin XCTest which relies on the superclass and @objc inference on methods.

* Mirror offers reads but not writes, and there is some sense that offering the ability to mutate through Mirror is uncharted design territory.

Then there is debate about whether other "dynamic" cases can also be solved with static analysis. I am in the "probably not all of them" camp, but that still leaves some of them, and it would be good to study that boundary condition in more detail.

With sufficiently robust static analysis you "can" implement your mirror trick for example (by code-generating a bigass extension to Mirror that just returns statically-analyzed data). Somebody will do that, and so I think upstream will be following how well it works out for them and letting the larger community build the case for or against the feature.

It's a really interesting point that you don't need runtime dynamism for this so maybe that shouldn't be the go-to solution. It's easy to just decide to do it that way because that's how it works currently.

Honestly, determining that all methods that start with "test" are your unit tests is pretty bad. We do this because this was the most obvious solution in obj-c. A much better Swift solution is to instead use an attribute, such as `@test`, to mark test functions. This requires compiler support for now, but the long-term goal could then be to come up with a generic way of declaring and handling attributes.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact