
What’s New in Swift 5.2 - ingve
https://www.hackingwithswift.com/articles/212/whats-new-in-swift-5-2
======
sixstringtheory
I frequently am disenchanted with the new sugar the Swift project introduces.
They add way too much surface area to the language by allowing too many ways
to do a given thing. When you're looking at a particular line of code, it's
very difficult to tell what exactly is going on without pulling up declaration
sites for multiple involved things because there's too much magic.

This time around it's callAsFunction. Yeah, pretty easy to understand in their
toy example. When it's deployed IRL with a ton of other things going on, and
larger distances between declaration and usage, it looks like a nightmare.

I love writing Swift for myself, but I write it in a pretty boring way. When I
have to work with people who get creative and clever, it's awful.

~~~
BubRoss
What no one seems to be able to do is make a simple language and leave it
alone to focus on tools and ecosystem. It always seems to be that the momentum
of solving an initial problem with the language is carried into solving more
problems with the language instead of tools.

~~~
enos_feedler
I hope we can get to a point where we don't need to build tools and ecosystems
around a single language. It seems there is just an explosion of domain and
generic languages and I see that as a good thing. I want more tooling
compatibility so that developers can pick and choose what works for them and
maybe even mix them together better. Better educational tooling so we can pick
them up faster, or read languages we don't understand easier. etc, etc. things
like WebAssembly, LLVM/MLIR, python->jupyter notebooks give me hope.

------
jmull
Eh. Improved error messages is good.

The rest look like they aren't worth complicating the language over. Consider:

    
    
        map(\.name)
    

Isn't really more concise than

    
    
        map { $0.name }
    

There's one more character and the conventions for whitespace are different.
Both require that you know special Swift syntax sugar features, but at least
the second one is more generally useful. All we get here is a virtually
identical way to do the same thing but with alternate arbitrarily different
syntax.

And what's better... this?

    
    
        struct Dice {
            var lowerBound: Int
            var upperBound: Int
    
            func callAsFunction() -> Int {
                (lowerBound...upperBound).randomElement()!
            }
        }
    
        let d6 = Dice(lowerBound: 1, upperBound: 6)
        let roll1 = d6()
    

or this?

    
    
        struct Dice {
            var lowerBound: Int
            var upperBound: Int
    
            func roll() -> Int {
                (lowerBound...upperBound).randomElement()!
            }
        }
    
        let d6 = Dice(lowerBound: 1, upperBound: 6)
        let roll1 = d6.roll()
    

callAsFunction() makes it a little harder to relate the calling code to the
implementing code -- you've got to internalize the new syntax-sugar rule --
and the calling code gets a little less clear in some cases.

Default arguments to subscript functions is probably OK. It's better if all
kinds of function have the same capabilities.

~~~
anextio
callAsFunction() isn't really intended to be used in a type like Dice there.
It's a bad example.

It's for Swift for TensorFlow's integration with Python, in which a bridged
Python object can be called as a function. Functions are, of course, objects
in Python, so that makes sense, but it would be a pain to have to call
fn.call(bar) instead of fn(bar) when fn is a reference to a python object that
is a function in its runtime.

It's also used in TensorFlow models, in which callAsFunction() is usually
implemented as passing the model's input through all the defined layers in it.

This makes it easy to treat models as if they were functions, which they
mathematically are, unlike Dice.

Example:

    
    
        struct MLP: Layer {
            var layer1 = Dense<Float>(inputSize: 2, outputSize: 10, activation: relu)
            var layer2 = Dense<Float>(inputSize: 10, outputSize: 1, activation: relu)
        
            @differentiable
            func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
                let h0 = layer1(input).withDerivative { print("∂L/∂layer1 =", $0) }
                return layer2(h0)
            }
        }
    
    

(from:
[https://www.tensorflow.org/swift/tutorials/custom_differenti...](https://www.tensorflow.org/swift/tutorials/custom_differentiation)
)

~~~
zionic
>It's a bad example.

It's a bad example _enabled_ by a bad language feature. Just you wait until
answers on stack overflow, sample code, and open source libs are littered with
these "bad examples".

Meanwhile, this example is terrible. There is no real need for callAsFunction
in your example when you could have added a simple named function on the
object to do so. Better yet, you could define a protocol and make sure your
layer conforms to said protocol.

~~~
chc
There is an argument to be made against features that are more likely to cause
harm than good (i.e. "footguns"), but I don't think this example of using it
poorly sheds any light on whether that's the case here. You could, with
roughly the same level of rigor, argue that allowing people to name variables
is bad by constructing an example with variables named CONFUSING, CONFUSlNG
and CONFUS1NG.

Any feature, no matter how good, can be misused. Pointing that out about a
specific feature isn't interesting, because it is true of _every_ feature. And
the absence of nearly any feature can be worked around, as ultimately all
these features compile down to machine code, which doesn't have most features
of a high-level language, so the existence of a workaround is also not a very
compelling argument.

------
metalgearsolid
I'm pretty apprehensive about this "callAsFunction()" feature. Requiring users
to name things in a specific way was the kind of awful UX our customers
struggled with when using our hobbled-together marketing software.

IMO, some better alternatives, in order of personal preference:

* Give away the functionality to all types that implement only a single function.

* Require an explicit protocol conformance. I get that the language does not want features to be hidden away, but requiring a user to implement a function with a specific name and signature is literally the job of a protocol. It doesn't seem like much of a hurdle for non-beginners, who have likely been familiarized with core protocols like Sequence or Collection, to acquire a knowledge of a CallAsFunction protocol.

* Introduce a new keyword, or tag (like @implicit).

* Allow the user to unlock the functionality through a more obscure phrasing. Even something as ugly as "func ` `()" could be preferable.

~~~
mantap
There is a danger of overengineering. This is a feature that will only be used
in rare situations. So it doesn't really matter that it's just a magic
identifier. As long as you aren't likely to use it by accident... I'm assuming
they checked GitHub that nobody has named anything callAsFunction before
choosing it

~~~
smabie
Apply on objects is used constantly in Scala, why would it be different in
Swift?

------
diebeforei485
I'm starting to feel Swift is being overly influenced by PL nerds. I hope they
keep learners in mind - plenty of kids might be learning Swift as their first
language.

~~~
mantap
It's been like that ever they set up the mailing list, what happened is that
people with an abundance of time on their hands started drowning the swift
team with shitty ideas. The swift team tried to resist but eventually the
lunatics took charge of the asylum. Swift didn't start with a very elegant
foundation because of all the ObjC baggage, but instead of simplifying the
language as time goes on they have just kept adding crap to it.

------
Doctor_Fegg
> The first beta of Swift 5.2 just landed with Xcode 11.4 beta

> Xcode 11.4 requires a Mac running macOS Catalina

Shit.

~~~
sixstringtheory
So much for semver. This should be a breaking change warranting an Xcode 12
major version.

~~~
estel
It's been pretty standard for the last several years that the ~.3/4 Xcode
point release increases the minimum macOS version.

~~~
sixstringtheory
True, and I've said the same thing every time. The status quo's fucked up.

------
RandallBrown
I've wanted to do the keypath expressions thing for awhile. It's not a giant
improvement, but it's certainly welcome.

Subscript default arguments will also be really useful.

Not sure about the callAsFunction() stuff, but I'm sure people will come up
with good ideas for it.

------
ollysb
What was the motivation for `callAsFunction`? It's a toy example so
`Dice(...)` is clearly bad compared to `Dice.roll(...)` but what's an example
where it brings clarity over the alternative?

~~~
jshier
You can read the motivation in the evolution proposal:
[https://github.com/apple/swift-
evolution/blob/master/proposa...](https://github.com/apple/swift-
evolution/blob/master/proposals/0253-callable.md)

~~~
ollysb
The first example with polynomials could be achieved using closures already.
Type erasure on closure contexts seems unfortunate and fixing that seems like
a better long term solution (granted it's probably far harder to solve). Was
excited to see talk of ML though :)

------
ed_blackburn
Swift on the server? Swimming against the tide? Or expressive language, ideal
for writing information systems and backed by Apple with the fantastic LLVM
tool chain at your disposal?

~~~
zionic
IMO Vapor (Swift) is the future. I absolutely love it for server side.

~~~
cerberusss
Which distro do you use on the server? And is Swift easily
installable/upgradeable there?

~~~
microtherion
Not the person you were asking, but I find the Swift docker images
particularly easy to install/upgrade/run in parallel.

------
cknoxrun
I feel like Swift is becoming more like Ruby over time. 2 of the features here
(Key Path Expressions and Subscript default arguments) were recently
introduced to Ruby. This isn't a bad thing, just an interesting progression.

~~~
dep_b
Key path solves a real problem for me, since you can pass in a function that
accepts the value to map which looks really clean, but you cannot operate on
the variable unless you create a block.

------
joshuawright11
I love Swift. Writing in it is awesome, the community is great, and it has
traditionally been focused on a truly wonderful dev-focused experience.

That being said, releases like this are pretty frustrating because they seem
to reflect a focusing on tiny bits of sugar (can we even call them that?)
instead of features that have a much more positive influence experience.
Besides "better error messages" how do any of these things improve the
development experience?

`map(\\.name) vs map { $0.name }`. Why...?

`callAsFunction()` feels bizarre... how is `obj()` more elegant or less
confusing than `obj.callAsFunction()`.

Meanwhile the Swift dev experience still has lots of annoying bugs & usability
issues (though to its credit it has improved by leaps about bounds). My
personal pet peeve is that sensible compiler synthesized inits[1] still have
not been implemented despite requests (and proposals!) coming up again[2] and
again[3] and again[4] and again[5]

Sometimes I wonder if anyone is actually asking questions like "what value is
this providing to the user?". Maybe there's so many strong opinions nothing of
substance can get through the approval process?

Announcements like this[6] get me excited that the language is heading in the
right direction, but it'll be a lot more convincing when the a release shows
that.

[1] [https://github.com/apple/swift-
evolution/blob/master/proposa...](https://github.com/apple/swift-
evolution/blob/master/proposals/0018-flexible-memberwise-initialization.md)

[2] [https://forums.swift.org/t/it-should-be-possible-to-
generate...](https://forums.swift.org/t/it-should-be-possible-to-generate-
public-default-initializers-for-structs/20646)

[3] [https://forums.swift.org/t/explicit-memberwise-
initializers/...](https://forums.swift.org/t/explicit-memberwise-
initializers/22893)

[4] [https://forums.swift.org/t/default-struct-initializer-
intern...](https://forums.swift.org/t/default-struct-initializer-internal-
even-if-class-declared-public/4923)

[5] [https://stackoverflow.com/questions/26224693/how-can-i-
make-...](https://stackoverflow.com/questions/26224693/how-can-i-make-public-
by-default-the-member-wise-initialiser-for-structs-in-swif)

[6] [https://forums.swift.org/t/on-the-road-to-
swift-6/32862](https://forums.swift.org/t/on-the-road-to-swift-6/32862)

~~~
slavapestov
> That being said, releases like this are pretty frustrating because they seem
> to reflect a focusing on tiny bits of sugar (can we even call them that?)
> instead of features that have a much more positive influence experience.
> Besides "better error messages" how do any of these things improve the
> development experience?

This article is about changes to the language. The bulk of the effort in this
release went into improving the _compiler_: better error messages, faster
compile times, smaller code size, and fixing bugs.

------
spullara
The subscript example will print Missing not Unknown.

~~~
azinman2
And the best friends compact map example will return the names of the best
friends, not the users with best friends. The article needs a bit of fine
tooth QA.

------
blkhp19
Minor correction:

> And this will return all users who have a best friend:

should be

> And this will return all best friends of users:

`let bestFriends = users.compactMap(\\.bestFriend)`

------
lenkite
Fundamental Truth of Computing: All languages become C++ eventually.

------
grezql
I cant stand swift. Without ios apps, would anyone even touch this crap?

Add to it constant major releases requiring new xcode or MacOs. Suddenly all
your existing App codes have to be upgraded to even release to appstore. I
swear justice will one day be served Apple for abusing the high end smartphone
monopoly.

~~~
dcgudeman
You would prefer objective-c?

~~~
grezql
Neither. I do js,php, java, .net and swift.

~~~
ianai
They really lost me as a developer in the ObjC->swift change. I was trying to
learn stuff and hopefully deliver as a side project, but that language change
was too much in addition to the day job.

