WWDC 2018 What's New in Swift Recap
roadfiresoftware.com
roadfiresoftware.com
Enums are really the best feature of Swift. I enum all the things everywhere. This is kind of the finishing touch to it.
Binary stability would be nice. I do care about the download sizes of my apps. What's really missing from the language is a way to add custom tags like @discardableResult @objc to define some kind of property. It's such a kludge to set up things like ViewModels while I really would like to have something like:
@twoWayBinding[username]
lazy var username: UILabel = { /* etc */ }()You can have one way binding, you can have binding with a transformer function to go from a number to a string etc.
Here's a playground where I did this a while back. You get type safety and nice syntax too.
https://gist.github.com/desugaring/828e9880f747678ac5912a070...
I bet this doesn't really happen, though it probably makes the day when it really happens closer.
(I don't just mean they might miss the date, but that (1) they miss the date by a lot; and/or (2) they drop binary compatibility from Swift 5; and/or (3) they claim they've achieved binary compatibility but it doesn't out to be true for long, less than 5 years )
Whether it turns out there are things missing from that list, who knows, but they're definitely getting closer.
>>Hash values vary from run to run (so don’t depend on hash values or order)
I must be reading this wrong. One of the requirements for a good hash function is determinism - specifically that any given value in the input space maps to exactly one value in the output space.
to be "deterministic for the lifetime of the program" sounds like a pepper is being applied, not that the hash algorithm is different.
So, what you shouldn’t do is:
- storing a hash value on disk, assuming it to be valid in a later run.
- assume that a hash map that has the same content as a hash map of a previous run has the same iteration order (not even if the calls used to construct them are 100% identical, and not even if both were constructed from the same literal).
I expect this was added to thwart DoS attacks (http://ocert.org/advisories/ocert-2011-003.html)
with some explanation for where the seed comes from here:
https://github.com/apple/swift/blob/master/stdlib/public/cor...
Within that code you will see references to Core which by default is this:
https://github.com/apple/swift/blob/82226642c2459c0f5d2054fe...
So you can see the hash function itself is deterministic given the seed it is initialized with. And the seed is generated at process start time during static initialization in C++ so it is effectively a constant for the lifetime of the process.
You can see in the code that there is a way to make hashing fully deterministic by making the seed generation not use random numbers, but it is ill-advised for a variety of security reasons.
[* said as someone who's implemented probably a ton of poor hash functions in their time]
How compares with Objective-C compile times?
let result = jsonList.map { Class(from: $0) }.filter { $0.isSelected }.map { T(from: $0 }
Or worse: let myDict = ["key": 1, "key2": 0.2, "key3": "something"]
It has to figure out it's not an int, not a number but an Any dict. Complexity to figure out the real type can quickly ramp up. foo->bar()->baz()
And the compiler has to get the type for the bar() result. That's one a small step from: let x = foo->bar()
Also that dictionary is most likely parsed and assigned a type in the expression whether you specify the variable type or not. let x = (f ? makeDerived1() : makeDerived2()); // no error, x is inferred to be Base
let x = 1;
x *= 2;
x = sin(x) / x; // no error, x is inferred to be Float
The problem is not just that extra computation is needed, it's language design. For example, you probably do not expect a dictionary of Floats and a zero to be a dictionary of Any, but how are you going to implement that in the compiler?And yes, the next example does need backtracking. I agree that it does need extra work in some cases. Most of the time though it's a very straightforward process.
Admittedly, there are exceptions. For example, it's possible in C++ to create humongous types:
auto p1 = std::make_pair(0, 0); // pair<int, int>
auto p2 = std::make_pair(p1, p1); // pair<pair<int, int>, pair<int, int>>
auto p3 = std::make_pair(p2, p2); // pair<pair<pair<int, int>, pair<int, int>>, pair<pair<int, int>, pair<int, int>>>
auto p4 = std::make_pair(p3, p3); // ...
Also, since templates are Turing complete, it's possible to create situations where type checking a single expression takes arbitrarily long.But neither of those are situations you're likely to run into by accident. In most real C++ programs, all the types in the program are reasonably simple, and the template system isn't used to do anything especially clever, so the O(n) bound should hold.
On the other hand, full type inference, at least in a language like Swift that allows arbitrary overloads, is inherently a process of exhaustive search over an exponential number of possibilities. Now, as described in this post[1], it ought to be possible in most cases to reduce that exhaustive search to something much simpler – and I actually agree that the Swift compiler could be much, much better at doing so (although it has improved over time). But the post also mentions at least one case where Swift type checking can simulate 3SAT, an NP-complete problem; and I think there are other cases the author didn't think of. So it's really far from straightforward.
[1] https://www.cocoawithlove.com/blog/2016/07/12/type-checker-i...
Could be 2 seconds to compile a very large (like 20 items) untyped dictionary declaration in the days of yore. If you would put:
let dict: [String: Any] = [ /* bunch of confusing key-values */ ]
The compile time would go down to 100ms or less. Because it would only check if all of the keys were Strings and all of the values conformed to Any.I'll just stop you there to consider why foo->bar()->baz() works and how does compiler know "baz" can be referenced. It may not have type hierarchy, but it sure has types.
I wrote type inference like that and yeah, in pathological cases it take some time. But if you spend dev-visible time on a mixed type dictionary, that's just bad implementation.
Never tried it though. I don't select stacks primarily based on programming language.
It goes without saying simplistic benchmarks like this are flawed but at the same time, you have to start somewhere.
[1] https://www.techempower.com/benchmarks/#section=data-r16&hw=...
It's not super up-to-date but you can see there's definitely some competition even on Swift level in terms of JSON performance. https://github.com/bwhiteley/JSONShootout
Swift JSON encoding/decoding should approach C/C++ levels of performance when optimized for speed.
It’s somewhat lower-level than web frameworks people may be used to coming from a Ruby/Node background, but it’s pretty powerful.
---
[0]: https://perfect.org
That said, Swift's C interop will work if you write an `extern "C"` interface to your C++. Obviously it's not ideal, but people have done projects like llvm-swift[0], with LLVM obviously being a C++ project.
There's also no direct equivalent to arc4random() in the new API - you always have to pass a range, which discourages people from using % to reduce the range and introduce modulo bias.
I think that’s a weak argument. arc4random’s source code isn’t platform specific, complex or large and is available under a permissive license, so they could easily put it in the runtime.
I would think they added this because of the modulo argument you give and to give it a better name (there’s nothing wrong with ‘arc4random’ for _a_ random number generator, but _the_ random number generator on a platform should have a simpler name)