Swift for TensorFlow Shuts Down
github.com
github.com
Swift's a delightful language to use. It has a lot of the nice things about Rust's type system, but is a heck of a lot easier to use at the expense of a bit of performance. For a lot of use cases, I think this is a great value proposition. ML/data science is a great example where practitioners could benefit from a more grown-up type system than what Python has on offer, but would still be able to keep low level details at arms length.
I think Serverless would be another ideal use-case for Swift, where the productivity, clarity and correctness tools it offers would be a huge benefit.
Some very interesting things came out of the S4TF project - like the work on autodiff, and python interop. It's a shame the project never really seemed to get legs, it seems like it just languished for years with no clear direction.
These days I do most of my work in Rust, and I'm happy to do so because the tooling, community, and ecosystem is really amazing. But there are a lot of language concepts and features I miss from swift. I guess it goes to show that the governance and availability of a language have a lot more to do with adoption than the merits of the language itself.
Python has exceptional libraries but, as a language, it's a bit dated on several fronts. This has an impact on library design. In Python, ML libraries are huge monoliths and they depend on a lot of code written in other languages. They are really hard to understand or modify.
In Julia, things are really small and composable. For example, you have a probabilistic programming library like Turing and a differentiable programming one like Flux, and it's trivial to implement some Bayesian neural networks. Same applies to many other things. It's small and beautiful, but it needs more manpower to compete against Python.
I was taken aback when looking at Turing for Bayesian modelling that the distributions were just the standard distributions found in the Distributions package! In Python, every Bayesian framework has its own implementation of everything from distributions to log probabilities, but it all composes in Julia.
> It's small and beautiful, but it needs more manpower to compete against Python.
Agreed. Docs of major projects are still incomplete or non-existent, there's a lot of projects that have been nigh abandoned (cough naive bayes cough), and the composability of Julia coupled without strong leadership leads to an ecosystem of overlapping functionality. Still, I hope by leveraging PyCall, Julia can overcome some of these issues.
You mean that, in Julia, we the users have to "compose" our own implementations of models (e.g. log probabilities), as opposed to using the already-made ones in Python?
(The same is true if you use something that's built on top of Stan or JAGS or BUGS or something else.)
In Julia's Turing.jl, everything is built around data structures that are first-class parts of Julia, so there's no need to have special Turing.jl versions of, say, probability distributions.
In Julia, if the DataFrame library is missing something I can just loop like an array and have a method that works just as well as if the library provided it, the CSV, DB and table processing libraries all use the same conventions so if library "A" solves my issue I'm not forced to use the same library "A" serialization method. Basically instead of twisting the logic to what I'm given, I just fill in the blanks. Sure Julia has way more blanks, but Julia also has half of the age of some of the Python's library I use, it's more about the maturity of the community than anything to do with the design choices of the language and I can only hope it gets better and better with time.
now python has like 5 identical numpy-like API re-implemented in multiple framework. That's where resources is wasted (unnecessarily)
If all you do is ML/numerical processing, against data that's already been cleaned up, I bet it's really great tho.
But I agree with you that in the short term it is a replacement for Fortran, Matlab and R. But a new language has to start somewhere. Attacking the niche filled by these language is natural as these are old, dated and ripe for disruption. The key is to gain some critical momentum and user base. That will carry the language to other domains.
I've been using Python for ML for the last 3 years and I've never felt this way. It might be that I'm not all about the hip new languages, but I don't really see the benefit of making Python more ML/Haskell-ish.
The ML use case for Python is roughly as follows: you design, train, and evaluate models. Then, if something is decent enough to use in production, you switch over your application to load and use that instead. I don't really see where Haskell or any language from the ML family can improve in that process.
Sure, the code that you used to implement your model may improve slightly, but I don't see that code improving significantly. The fruit of your labor is usually a protobuf file (encoding the TensorFlow graph) or whatever your framework uses to encode the model you built. The code actually surrounding it is very minimal for most use cases.
> In Julia, things are really small and composable. For example, you have a probabilistic programming library like Turing and a differentiable programming one like Flux, and it's trivial to implement some Bayesian neural networks.
There's nothing stopping you from composing things in Python. But it's simply not a goal of 99% of ML libraries to be composable with other libraries. You're probably never gonna run TensorFlow and PyTorch in the same application (trust me, I've tried, it was a nightmare) and I don't see why you would compose a TensorFlow model with a PyTorch model without incurring tons of overhead in your application around gluing these two things.
There is, and you pointed it out yourself:
> I don't see why you would compose a TensorFlow model with a PyTorch model without incurring tons of overhead in your application around gluing these two things.
This is where Julia is profoundly different. Reusing stuff from different libraries is trivial compared to Python. You could take an activation function made for one libraries use it without any modification or wrapping in another ML library.
These is where Julia will win long term. If you look at the ML libraries in Julia they are tiny. The Python side of things require gargantuan effort because things are not composable. The wheel is reinvented over and over again.
In Julia you can compose a custom distribution, with a bayesian model with an ODE with a neural network with unit number types with custom Julia written CUDA kernels and multithreading.
Edit: That are not designed specifically to work with each other
Can python even hope to do a fraction of that, still be fast and differentiate through everything?
[0]: https://www.tensorflow.org/guide/create_op
[1]: https://pytorch.org/tutorials/advanced/cpp_extension.html
Julia is not ML-ish. In fact, at first blush, Julia reads very similarly to Python. You even get list comprehensions in Julia!
> Sure, the code that you used to implement your model may improve slightly, but I don't see that code improving significantly. The fruit of your labor is usually a protobuf file (encoding the TensorFlow graph) or whatever your framework uses to encode the model you built. The code actually surrounding it is very minimal for most use cases.
It's really about breaking down the compositional boundaries here. Upthread, someone talked about how they could play around with Bayesian Nets by simply mixing Flux.jl (the differential programming library) with Turing.jl (the Bayesian programming library). Mixing Tensorflow/PyTorch with PyStan, for example, can be a nightmare. That's also why there's so many implementations of probabilistic programming frameworks (Edward, PyMC3, PyStan, Pyro, etc); they all use different underlying libraries. In Julia they just all compose together.
> I don't see why you would compose a TensorFlow model with a PyTorch model without incurring tons of overhead in your application around gluing these two things
I find the change to be illuminating. Before I started spending more time with Julia, I would often do derivations on paper for more experimental work, and then implement it using TF/PyTorch in Python from scratch, reading other code where I could for some help. In Julia I can import a library and I'm ready to go. It feels just like working with math itself.
Julia also lets you compose long trains of operators together. That also helps when I'm doing long sessions in the REPL exploring data. It lets me define a few functions in a file, import the file, and just pipe (Julia has a pipe operator which is just function application) output between functions to plot data or calculate errors.
Moreover Julia is a lot more performant for REPL work than Python. In Python I'll usually work with a subset of a dataset to get an idea for it, then run a file with code to process the entire dataset. In Julia I can often prototype and run the algorithm in the REPL itself.
I also want to stress that Julia is quite a bit faster for REPL development, both in terms of raw speed
function julia_blues(bummers...)
I largely agree, Julia is such a cool language and had so much potential. It definitely surprised me when they went with Swift instead, but realizing that Chris Lattner worked at Google at the time explained a lot. Unfortunately, every time I try to get into Julia, it just feels awkward coming from Python and a bit like stepping back in time.The stupidest, (stupidest in the sense that I really wish they didn't bother me, because they're silly things!), things that bother me are:
1. The 'end' keyword. It's everywhere! Loops, if-else statements, function bodies. I mean I understand why it's helpful for parsing and providing more info to the compiler, but honestly, I would've rather we just stuck with curly braces '{}'! At least it's fewer characters to type and it just feels less crowded on screen while reading. It feels like such a petty complaint, but honestly, it feels like I'm writing Pascal or Matlab all over again. Which leads me to my second point.
2. The default choice of 1 based indexing. I'm not going to go into it, because plenty of people before me have beat this dead horse already[1][2][3], but I can't help but be saddened by this choice and its implications. It's important to acknowledge the fact that Julia started as a competitor to Matlab and Octav, so it makes sense from that perspective. However, it could have been a much more general purpose language, with huge performance benefits over popular interpreted languages like Python, JS, and Ruby. It could have been a unifying force in the scientific computing community, bridging the gap between R and Python users with a greenfield approach that would have been a force to be reckoned with. Instead, rightly or not, it's viewed largely as 'just' a matlab replacement.
Now, regardless of whether 1 or 0 based indexing is truly 'better' or the 'end' keyword is no big deal, the reality is that there's a huge demographic of potential users that won't buy into Julia, because it doesn't quite feel as ergonomic as Python/JS/Ruby and won't take it seriously as a general purpose language, because it looks/feels like Matlab and they only use 'real' programming languages. Again, I'm not saying this is right, but it is the reality we're faced with and it just feels like a huge missed opportunity and bums me out.
end
1. https://github.com/JuliaLang/julia/pull/16260#issuecomment-2...
2. https://groups.google.com/g/julia-dev/c/tNN72FnYbYQ?pli=1
3. https://github.com/julialang/julia/issues/558I share your frustration with the `end` keyword - it's just needlessly verbose, and for something used so frequently it makes sense to be as terse as possible.
I have some similar quibbles with Rust syntax: I know it's a minor issue, but I'm really disappointed that snake_case was adopted. It's just ergonomically inferior to camelCase in every measure. It's one more character to type for every word, and on top of that, on a US keyboard, the underscore character is a pinky key way far away from the center of the keyboard. Making this one of the most frequently typed characters in the language makes no sense.
It makes a huge difference, so much so that using camelCase feels like a huge drag.
Qwerty is frankly awful for programming. I encourage everybody to look into alternate layouts.
`end` marks of blocks of code much more clearly than curly braces. It is also requires fewer keyboard taps. To type {} requires holding down four keys in total (shift-[ twice). end is just three key strokes.
But more importantly is saves curly braces for other uses where it is more needed.
Also braces have a nice symmetry, which is also convenient for parsers and tooling to count opens and closes.
I also think "end" is just more visually noisy. Braces are a symbol, so it's easy to filter them out when you're looking at code, but a trail of "end"s takes up more real-estate than is semantically justified.
Seems to me that "end" is one of the worse available choices; if we're going for keywords, why not make them "endif", "endfor", "endwhile" (or "wend") which makes it explicitly clear what each of:
end
end
end
is ending.Re: 0-indexing vs 1-indexing. If you use 0-indexing, you turn off a lot of non-engineering scientific programmers. My personal experience is that 0-indexing is better for more engineering applications, while 1-indexing is better for math. I'm a weirdo in that I don't seem to mind either one though.
I think you mean "non-CS engineers". CS is a minuscule branch of engineering. Plenty of chemical, mechanical, civil (and so on) engineers had their whole education doing maths and programming with 1-indexing.
> I'm a weirdo in that I don't seem to mind either one though.
You are not, as an outsider this is one of the less appealing parts of practical CS, endless bickering about non-substantive issues which most of the time boil down to a matter of personal preference (see also tabs vs spaces, vim vs emacs, react vs vue, golang vs rust and on and on and on...)
I love experimenting with programming languages but I don’t like recommending languages just as I don’t like recommending movies: I figure that everyone has their own tastes, and that is a good thing.
Nearly every Google project eventually gets abandoned because the engineers that made it get promoted and move on to their next promotable projects. The root cause is the ongoing failure of Google's leaders to align employee incentives with the long-term interests of the company or human society.
Even if S4TF had become popular, I expect it still would become neglected and rot like most Google projects.
Oh yes, I would love to have Swift framework for Firebase on server, not only for iOS. Its atrocity to write the server logic in NodeJS after making the user App in Swift.
Every time I switch from Swift to JS I deeply appreciate the beauty of Swift. On swift I do much less silly mistakes where the NodeJS code feels like up and running by some miracle and everything can collapse due to something I did but could't catch it before something horrible happens.
For example, TypeScript is nice but it's not a "real" language in a sense that you can write something in it and expect it to work when it's fed into the compiler or interpreter. To use it, you need to set up an environment where all the moving parts are working in harmony and the code you write in Typescript is transcribed into the actual code that NodeJS and the browser will understand and that is JS. The debugging of unusual bugs and doing something non-conventional instantly becomes multiple times harder because you have layers and layer over the actual stuff that is executed which means you loose the browsers or runtimes debug capabilities since those would rarely tell anything useful about the pre-transcription code.
Sometime you have a library where someone a few years back tried to do something similar to your idea but never had a complete solution and stopped working on it and when you try to benefit from this work to build on top of it, you find out that you need to modify you working environment to support some spacial case of legacy code. You do that and it all falls apart, now you must choose to try to fix it or give up and restore your setup. It's just horrible.
The greatest thing about working with Swift on iOS is that starting something new is as easy as creating a new Word document so you can start working on your idea right away without worrying about the tooling and see where it goes. On the JS world, I used to be exhausted and loosing all my motivation by the time I have my environment ready to go. Templates and project starters tend to be no good because they are all opinionated that you must be creating a list or a blog app. They all need extra work for a good clean start and that clean start often is too customised to be used as a general use case template.
There are so many solutions for the same problem in the Web Tech world, each comes with its own shortcomings and taht's how someone else creates the next framework. On iOS it's easy, the answer is UIKit and SwiftUI if you feel more adventurous and bleeding edge.
> Sometime you have a library where someone a few years back tried to do something similar to your idea but never had a complete solution and stopped working on it and when you try to benefit from this work to build on top of it, you find out that you need to modify you working environment to support some spacial case of legacy code. You do that and it all falls apart, now you must choose to try to fix it or give up and restore your setup. It's just horrible.
So far Swift code has not aged well, although it's gotten better during the last two years. The perpetual brokenness has moved on to Swift's tooling (binary stability, SwiftPM etc.) which wouldn't affect serverless.
But I agree, Swift is a pleasure to work with.
Ninja edit: I don’t mean easiest necessarily to learn. But easiest to use. Xcode is great.
Might not be to everyone’s tastes but it feels like a solid tool to me.
I'm doing it on NodeJS currently and I hate it. I used to like JS but Swift showed me that there's more, there's beauty in the world.
The only thing I miss on Swift is async/await and that's coming.
Luckily, I don't think Swift on other platforms is dead. SwiftNIO seems worked quite well as a project. Bazel support is solid. They still release Linux / Windows Swift toolchains.
Also shameless plug, I did implemented my own deep learning framework in Swift: https://libnnc.org/s4nnc/
I wonder if Kotlin is too far from "arms length" from the low level details in your mind? Because other than that, I actually prefer the language over Swift, generally.
I don't know which one is the best. So I've been experimenting with several.
Both. (The type annotation system is deeply tied to the type system, since the latter is what is statically verified, but there are improvements both in what can be checked—the type system—and how that is expressed/annotated.)
What else is missing in the python3 type system?
I agree, but sadly none of the big cloud providers has any interest in pushing it - Google's got Go, AWS and Azure seem focused on Typescript.
If you're talking about a container workflow, I'm pretty sure every cloud provider will support this just fine currently.
Given how opinionated the Python maintainers can be, it baffles me that they accepted to get these optional, noisy, half backed type hints into the core language.
In my experience given that they're optional and you'll almost never get 100% of your code and its dependencies with correct and up to date signatures it's just a nuisance. Maybe in the right projects if all the devs are very thorough with them it can be helpful, but that's really not my experience. If at least it triggered an assertion at runtime when the type doesn't match it would be massively more useful. And even then, if you're so thorough with your typing, why not just use a proper statically typed language?
I really don't get why it's even there to be honest.
If you do the legwork, you can get mypy[0] type-checking done on your codebase in a way that is similar to how TypeScript does type-checking. There are stub files that are provided by project maintainers that are then used by mypy to infer things like e.g the return type of a function.
Type hints are also inline in the code, and not technically comments. They can be retrieved from class attributes using facilities from the standard library [1] and can facilitate other tooling that is specific for your project or that are more general.
> And even then, if you're so thorough with your typing, why not just use a proper statically typed language?
That would remove a lot of the benefit of choosing Python. Python is dynamically typed. Type hints make it possible to do type checking statically, but with a lot of extra leg work (as I described above). Making Python itself statically typed is not something that would interest 99% of the Python community IMO.
[1] https://docs.python.org/3/library/typing.html#typing.get_typ...
Not quite. You can reflect on and interact with them at run-time, too. This does make it possible to implement run-time checking as a library solution.
I can't speak to why run-time checking wasn't built into the language as a default behavior, and the PEP doesn't explain why (though perhaps the answer is in the mailing list), but one possibility is that it would be wasteful. Most functions that are only prepared to accept certain types already have some form of run-time type check baked in, either explicitly or incidentally, so adding a second check would likely introduce overhead without producing a whole lot more type safety.
Guido joined the Mypy team while he was Python’s BDFL.
Also, there’s nothing half baked about either Python’s type hints or Python’s type system, or it's major type checkers. It's not Haskell, sure, but it's an expressive to system, the typecheckers are reasonably smart, and the annotations are readable and sensible if somewhat verbose; there were some infelicities regarding alternate names for core types in annotations, but that's been improved recently.
> In my experience given that they're optional and you'll almost never get 100% of your code and its dependencies with correct and up to date signatures it's just a nuisance
In my experience they start to provide value in preventing bugs and easing development because of tooling support way below 100% coverage.
> If at least it triggered an assertion at runtime when the type doesn't match it would be massively more useful.
Python’s type annotations are annotations, and are used by some libraries for runtime (validation, serialization/deserialization, etc ) as well as static checking purposes (e.g., pydantic.)
> And even then, if you're so thorough with your typing, why not just use a proper statically typed language?
All a “proper statically typed” language is is a language with a static type checker run ahead of time, which Python is of you choose it to be. There's a lot of code in the ecosystem that is more broadly types than it needs to be, because no annotated code which checkers can't infer anything better for use Any, but that's evolving over time as it is more common for popular libraries to be typed, or at least have typings available.
The chorus of people asking for increased typesafety had become too loud to ignore. Type hints gave them enough support to cover 95% of their needs, which were/are largely organizational rather than technical: developers must feel sure they are using the right classes in their code, pulled from the right places in their project, and don’t have to look up docs at every step (because the IDE will autocomplete stuff). What happens later, the low-level implementation, it doesn’t really matter; what matters is the information about types is surfaced somewhere, so that IDEs and tooling can use it to document projects and help developers.
That’s what type hints do, and yeah, they are basically glorified docs, but integrating docs into syntax is one of Python’s many traditional strengths (see docstrings, doctests, etc). That’s also why they are optional, thank goodness, so people who don’t have big-org / big-project needs can still be productive.
This was always kinda false (type hints can be composed unlike eg docstring param @type). But with the introduction of dataclass, this is empirically false. You can readily hook into the type hints, reflect on them, use it to marshal data, etc. Using __post_init__, you can leverage any kind of runtime checks you want to enforce invariants.
Also type hints greatly help transpilation.
You don't need 100% to reap the benefits. In fact I will annotate small bits of un-typed code and it makes it way easier to reason about.
Why not?
Static enforcement of invariants that doesn't change the space of what is possible in the language when you aren't asserting conflicting invariants doesn't make Python any less Python.
But for applications that require a GPU (i.e, most ML applications) cutting over to Swift from Python will likely win you nothing in performance, and wouldn't be worth it at all.
Most of the other things I miss are ergonomic:
- Swift has better inference, so for example in a match statement over an enum, in rust you always have to type: `MyLongEnumName::SomeEnumCase`, where in swift you can just type `.someEnumCase`
- Swift's operators for optionals are much cleaner imo than how it's handled in Rust. For instance, the `?` operator is kind of magical in Rust, because it effectively changes the flow of control of the enclosing function. Optional handling constructs in Swift are always local to the statement, which I find to be easier to reason about, and more composable.
- Rust's module system is needlessly complex and verbose, and adds boilerplate and redundant busy work when you want to refactor code and move things around
- Trailing closure syntax is really nice
- It's sometimes useful to have types as runtime constructs as well as at compile time
- I like Swift's more flexible approach to scopes/namespaces. Like in Swift, when I declare a struct, I can just declare the methods inside the struct body without needing a separate impl, which reduces boilerplate. Also for instance if you need to declare a throwaway data type which is only used internally by a couple functions in a Swift type, you can declare it right inside the struct declaration where it's relevant. Rust is more restrictive, and I have to declare types either at the module level, or inside an execution scope like a function body. So with Swift I just feel like my code is organized in a more semantically coherent way which reads like a book, where in Rust it's more organized according to the ceremony which is required by Rust syntax.
I could go on, but basically I just feel that when I am coding with Swift, the syntax melts away and I am mostly focused on the problem domain. When coding in Rust, the syntax is very present, and is a big part of what I am dealing with.
Doing machine learning stuff in Julia is simply much more user friendly than doing the same in Swift. Swift is nice for iOS development, but I think in data science and Machine Learning Julia will always be a much better choice.
It is a pity Google did not go for Julia. Julia has gotten exceptionally far despite limited resources. With Google style resources, Julia could have been massive.
Despite modest investment, the Julia JIT beats almost anything out there. It would have been amazing to see what they could have pulled off if they had put the kind of resources that was put into the JavaScript V8 JIT into the Julia JIT.
Julia uses a method JIT, which are quick to implement, but which makes latency gets bad. Meaning if you load a whole new package, running the first function can cause some delay. With a JavaScript style tracer JIT added into the mix one could have probably managed to have both high performance and low latency.
Alternatively with more investment they could have had better precompile caching, meaning libraries that had been loaded in the past would JIT really fast. Julia does that today, but it could have worked a lot better than it currently does. It isn't that it can't be done, but it just requires resources.
I also think it’s blurry as to whether mathematicians and programmers see indexing numbers as merely indices or richer numbers.
This is actually the other way around -- Method JITs are harder to implement and all the major JavaScript JITs are method JITs, not tracing JITs. There are many reasons that contribute to the latency but I don't see what makes method JITs inherently slower than tracing JITs.
Despite its many shortcomings, Python has become the lingua franca of AI and ML, to the point that whenever I come across a newly published AI or ML paper that I find interesting, I expect to be able to find code implementing it in Python.
For example, yesterday I saw a post on HN about approximating self-attention matrices in transformers, which have O(n²) computational cost, with a seemingly clever approach that has O(n) computational cost: https://news.ycombinator.com/item?id=26105455 . "Huh, that looks interesting," I thought, "let me see if I can find some code." Three clicks later, I found myself at https://github.com/mlpen/Nystromformer -- the official implementation... in Python. A few moments later, I was playing with this thingamajiggy. No other language comes close to having this kind of ecosystem in AI and ML.
Julia still has a shot at becoming a viable alternative to Python, especially if the Julia developers can shorten the "time to first interactive plot" to make it as fast as Python's, but they face an uphill battle against such an entrenched ecosystem.
AI/ML on the other hand has no such restriction. Your new startup could build all their ML models in Java with DeepLearning4J and it would probably work fine. Python is used because it's easy to work with for experimenting, which is a big part of research and for production your can extract your weight and graph structure to run on TVM/TensorRT/ONNX. There is no equivalent vendor lock-in.
At any rate you’re right - the dominance of each language for their respective use cases (JS-Web / Py-ML) emanates from different sources.
For all the comments on HN about how great Swift was, there were hundreds if not thousands of ML engineer and research scientist who did not know it existed and frankly did not really care about it either.
Swift for Tensorflow was not addressing the issues of ML in productions and felt like "Just another framework" but with the added handicap of needing its users to learn an entirely new language which is not something most scientists want to do. One might argue that engineering might be more interested, but in a lot of cases the science team will push the models and then the engineering team will put them in production, leaving very little room to migrate from TF/Pytorch to Swift for TF.
In contrast, S4TF's target audience seems to have been Swift developers, and they didn't really appeal to the data science crowd.
Anyone knows if chris latner is at least using swift in his new company ? I have the feeling swift never really worked in the server side, data science is now officially a failure, and all that is left is now a very niche market of 100% native mobile development.
I love this language, but i'm eager to see it handled by a proper foundation with big names behind, as it's a really great language.
I mean, it also works for native desktop development. And is there really an issue with that? Objective-C basically had no reason to exist beyond iOS/Mac programming and at least now we don't have god damn [myString stringByAppendingString:@"another string"].
I was looking at the upcoming async/await stuff for Swift, and it's still not comparable to some of the lower-level threading systems.
That said, I have not done system programming for a long time (unless you count drivers). I think Swift is an almost ideal application-level language.
I'm not especially bothered by it being Apple-only. It works on all Apple-supported hardware, has a new application toolkit coming into play (SwiftUI), and has a very active development community. Spend some time on the Swift discussion forum to see some pretty heady discussions.
There are already controls in Big Sur and iOS 14 (Color Picker) which are SwiftUI and bridged to UIKit/AppKit.
There's no such indication. "The number of binaries using Objective-C is still growing with each iOS release." https://blog.timac.org/2020/1019-evolution-of-the-programmin...
Which just happens to be one of the biggest development niches in the world.
The only things left are a very small percentage, and add to that the fact that you either 1/ have the budget for 2 development teams, or 2/ afford to skip the other "half" of the market staying iOS only.
IBM dropped Kitura more than a year ago [1]. There's Vapor [2] which seems popular, but I don't know how much.
Vapor [1] is wonderful to work with and has a large user base. Apple is also putting significant resources into Server Side Swift with Swift NIO [2]. Lots of really cool stuff happening in that ecosystem
[1]: https://vapor.codes [2]: https://github.com/apple/swift-nio
Now there’s still go market of « server middleware ». But for that it would need a much higher quality of core libraries, tooling, and a much better concurrency story. Maybe it’ll come with the incoming actors, but somehow i doubt it (the underlying concurrency libraries remaing grand central dispatch, which looks too heavy compared to, for ex, goroutines)
There is no way out of it.
* Swift lets you write code that's as concise as Python while still being fast, and therefore allows you to get away from the problem of having to write ML code in multiple languages (TensorFlow is actually mostly C++, which makes it difficult for a Python developer to debug.)
* That the lack of static typing is a major pain point in Python, and Swift's type system would help write code with fewer errors.
> (TensorFlow is actually mostly C++, which makes it difficult for a Python developer to debug.)
To be honest, if I had to choose between Python and Swift I'd still choose Python. Swift is a nice evolution from Obj-C and all but it is nowhere near as simple as Python, or Ruby, or PHP, or Javascript, or Kotlin. And Apple's documentation of these things is pretty woeful at the best of times lately.
I also disagree with the pitch, is what I'm saying.
I'm curious if you've seen https://docs.microsoft.com/en-us/visualstudio/python/debuggi..., and if so, to what extent it helps with C++/Python interop in TensorFlow context?
1. Backslashed opening parens for string templating
2. Parameter labels and the use of _ when ignored
3. Splitting method names across opening parens eg. `move (to ....`
4. Verbose NSString Objective-C hangover in regular expressionsSwift is safe (no null pointer exception), has predictable garbage collection performance through ARC, has a familiar C-style syntax (easier to get on-board), has compile-time type checking, good-enough generic programming support, algebraic data types with pattern matching, and will very soon get actor support.
Plus, it has the potential to become a good cross-platform language since it’s using llvm, all it needs is a bit more love on tooling and libraries.
I don’t see many other languages with those characteristics..
There's nothing wrong with this. Swift can be the best language for the Apple platform and find lots of success in that.
Apple took the code and extended it, they had little choice for the source code license.
I can think of dozens of examples from Microsoft and Google, which are more "outside ecosystem" inclusive as a means of gaining mindshare. TypeScript, Golang, Visual Studio Code, protobuf, gRPC, ...
Other companies think of the things living outside their moat more flexibly, or their moats are less rigid. That's not to say that Apple's approach is wrong (look at their market cap!), but it has different consequences in terms of the open source code mindshare they cultivate.
The churn may not be a deliberate strategy but it is certainly very effective in locking developers in.
[0] As far as I know, the only system feature that requires Swift is iOS 14/macOS 11's new widgets, which must be written in SwiftUI.
Apple have had significant churn in dev tooling, languages, sdks, frameworks, chip architectures over the last couple of decades. Perhaps that is completely normal but it does mean developers are always struggling to keep up, and an app written for iOS 1.0 needs significant alterations if not a rewrite to work with later versions. Almost everything has been completely replaced, from language to frameworks to dev tooling like resources.
Java was introduced alongside Objective-C, with a common bridge to call into Objective-C runtime, as Apple was unsure if the Apple developer community would be welcoming to Objective-C.
They dropped it after the community was more than happy to adopt Objective-C.
About the same time they introduced PyObjC support and for a while there was MacRuby, which due to internal politics was eventually dropped, the creator left and now sells RubyMotion for mobile development, originally based on it.
Then if we switch back to the System days, there was Object Pascal, replaced by C++ frameworks, Hypercard, Lisp, Dylan.
Are you nervous about a language that is designed and supported by the largest and most successful company in the world?
> very niche market of 100% native mobile development
That "niche" is at least 1.5 billion devices. Devices bought by the 1.5 billion richest people in the world because they like them, not because their employers forced them to. Seems like a pretty ideal "niche".
But I wouldn't agree that "swift never worked server side". I've built several backends in Vapor and it's amazing.
Yes, I am. The concentration of power between facebook and google for ML frameworks is worrying enough, but to their credit, they have so far been very open and collaborative and are giving a lot back to the ML community in terms of research
Apple on the other hand is the dictionary definition of walled garden. Their controlling and insular nature has been the reason for their success, and power to them, but for something as fast moving and community driven as machine learning, I would be very wary if relying on them for any part of it.
What possible future are you trying to ward off here? Swift is an open-source project, it's self-evidently in Apple's interest for as many people as possible to use it.
Be concrete, please. What scares you about using an open-source language which is mostly developed by Apple? Do you have the same paranoia about clang? If not, why not, what's the difference?
For me the lesson is that just because a new technology/language is out doesn't mean you should jump on it. Things need time to mature, and if you're Uber, you can't risk having half of your income rely on something new. Compilers, linkers, and programming languages (and databases and OS kernels) take years to mature. Hell, just earlier this week was a post about diagnosing a 21 year old bug in the Linux networking stack for rsync of all things.
I'm quite shocked that enough experienced people felt that level of confidence. In earlier versions of Swift I personally experience slow compiles and that was on a not terribly large code base -- no where near Uber. That alone should have been a big clue of the state of things.
(Missing the -with-kotlin at the end)
This kind of tactics has been used since the beginning of time.
There was no way to produce a hard evidence, and everyone knew that.
https://twitter.com/clattner_llvm/status/1222032740897284097...
That work is still happening (as noted in the link). One of the primary engineers who was working on it at Google works at Apple now.
At the end the engine that compiles the mathematical expression to hardware is what matters, and I don't think that LLVM IR that uses is the best IR for the optimizations.
I do not. Unfortunately, high performance and python do not go hand in hand. Yes, I know the heavy lifting is done by C/C++/Rust/Cuda/Blas/Numba and so on, but, when you run simulations for millions of steps, you end up with billions of python function calls.
Afaik only Jax actually performs any optimizations because it constructs an analytical gradient. Zygote seems to be able to that and more on the LLVM IR level which, I think should enable more optimizations.
And that something better is certainly not Julia and it's definitely not Swift.
> Yes, I know the heavy lifting is done by C/C++/Rust/Cuda/Blas/Numba and so on, but, when you run simulations for millions of steps, you end up with billions of python function calls.
For ML purposes, if your model isn't running on the GPU, it doesn't matter if you're using Swift, Rust, or whatever, your stuff is gonna be slow. Like it or not, Python is one of the best glue languages out there, and the reason why libraries like TensorFlow and Torch are not used in their native languages (C++) [0] is because they're significantly simpler to use in Python and the performance overhead is usually one function call (e.g run_inference(...)) and not billions.
If you find yourself writing a simulation, and you need to optimize away billions of function calls, you can use the C++ API provided by TensorFlow.
I prefer to just use Julia and get that for free. Also can write custom cuda kernels in pure Julia. And differentiate through arbitrary julia code, compose libraries that know nothing about each other etc
Python's performance is sufficient when the bottleneck is actually the computation done in the accelerator. In my flavour of ML, we use small models, think 3 layer NN 64 neuron wide and in some cases a small CNN. During training, most of the models reported using <150MB.
Most of the community finds python sufficient because they do not need to interleave training and simulating.
> For ML purposes, if your model isn't running on the GPU, it doesn't matter if you're using Swift, Rust, or whatever, your stuff is gonna be slow. Like it or not, Python is one of the best glue languages out there, and the reason why libraries like TensorFlow and Torch are not used in their native languages (C++) [0] is because they're significantly simpler to use in Python and the performance overhead is usually one function call (e.g run_inference(...)) and not billions.
You don't know in what I am running/doing, hence your comment comes off as ignorant.
This is the setup:
Run X number of simulated steps on CPU, collect X samples, store them in a buffer of size either X, or Z>>X, train for Y number of steps sampling from buffer, copy model to CPU, repeat for total of 1M steps, repeat 10+ times to get a good average of the performance.
All of that without any hyper parameter tuning.
Now, you also need to note that a non trivial amount of work is also done in python to augment the inputs as necessary. If the work is done in numpy, there's usually little overhead, but, it is often the case that the environment I am simulating is wrapped in wrapper functions that modify the behavior, e.g. I may need to remember the last 4 instances created by the environment, and so on. All these modifications quickly accumulate and for a single experiment of 1M steps, you end up with billions of python calls. The community uses more or less the same package/framework as the intermediary between simulations and models.
The issue is so prominent, that the community as a whole moved away from running in single core the simulations, to having multiple parallel actors to collect transitions/data points, this also requires new theory. Furthermore, there have been many proposed architectures for distributed and asynchronous training because the bottleneck is not the GPU or the model, but rather, how fast you can collect transitions. Infact, there was a distributed architecture by google that literally sends the transitions over the network into a few GPUs, the reason is that the network cost is amortized because you get to run hundreds of simulations concurrently.
IIRC, a maintainer of a popular project/framework that I contribute saw improvements upwards of 2x when using C++ over python.
This is becoming increasingly outdated as significant parts in scientific machine learning require parts to be written that don't simply compile to GPUs. Think, for example, when you mix a physics model, say for RF or some such, and deep learning to model parts of the function. In python, you cannot write the RF model because python is vastly too slow, so you're forced to write the RF model in something fast, like C/C++, then integrate that to python, then integrate that to your favorite tensor network, needing more languages than you can do immediately with Julia.
Deep learning is moving rapidly out of simply being a tensor engine, and being a tool in much larger problems, where many high performance pieces need developed. Julia is light years ahead of Python for these domains, and I cannot see Python ever catching up because it suffers from performance and/or multiple language problems to solve these.
If you've never learned about scientific machine learning - go read some or watch some videos. It's fascinating and growing rapidly.
I’m sure that Julia is better for some specific tasks, for example phyisical simulations, that are important for some types of scientific tasks, but I don’t see any valid argument on why a simple tensor engine in Python is not smart enough to simulate the human brain, which is just a bunch of connected neurons.
That's funny, since protein folding uses the methods I described to achieve it's results. Multiple stages in their work [1] uses physical modeling, not NNs, to do protein folding, most likely because the problem becomes currently intractable to solve with simple Python + TF. NNs are a step to adjust the physical model, exactly like I described above.
Simply read their paper and note all the physics models incorporated at about every step of the process to enforce physical constraints - this means vastly less parameters, less training time, less training data, faster evolution of the process, etc.
Here's their repo [2]. They did that work in Python and TF, likely because it was started years ago. As Julia becomes a much faster develop tool for this type of work I expect this will change. They also used TF 1.14 - showing the age of their development. They did not release the feature generation code which is a significant component; the released code only works on the specific dataset they provide. This is likely because this component is not simply simple python they wrote, but an amalgam of things written to make the physics parts of the chain fast enough. But they don't clearly state either way.
Also, by your argument, since it's possible to solve any NN problem with a network only 3 layers deep, why not just claim that's all one needs? Because it's also not computationally feasible.
The point is that by adding outside knowledge, such as physics models, you can have vastly smaller networks, require less training data, train and infer faster, with the end result of being able to solve a much larger class of problems efficiently.
So yes, you can do it in python, or any language, if you want to waste orders of magnitude more effort and resources to do it, effectively limiting the things you can practically do.
This is why Python incurs a unnecessary cost for such development.
By willfully ignoring learning about these methods and being ignorant about even the results you cited you will miss out on extremely useful knowledge.
[1] https://www.nature.com/articles/s41586-019-1923-7.epdf?autho...
[2] https://github.com/deepmind/deepmind-research/tree/master/al...
Given how divergent the current crop of ML frameworks are, is this really a realistic expectation? Having played around with Julia and Flux for ML, I find I have to do just as much rewriting when translating e.g. TF -> Flux as TF -> PyTorch. You get some limited mixing and matching with Caffe2 <-> Torch and TF <-> JAX, but that breaks down the moment you leave a company's walled garden.
> I don't think that LLVM IR that uses is the best IR for the optimizations.
I think Chris Lattner agrees, which is why he also helped start https://mlir.llvm.org/. If anything, I predict we'll see more frameworks targeting it (prototypes for Numpy, PyTorch, TF and general XLA already exist). This implies that languages that target LLVM now will actually have a leg up because their compiled semantics can be more easily lowered to something accelerator-friendly.
It may not be quite as mature, but it's getting there quickly.
It's also far more interoperable because of Julia's multiple dispatch and abstract types.
For example, the https://github.com/alan-turing-institute/MLJ.jl ML framework (sklearn on steroids), works with any table object that implements the Tables.jl interface out of the box, not just with dataframes.
That's just one example.
Julia is like, the poster child for being able to mix and match and compose code and algorithms: Flux/Zygote can do auto-differentiation on the entire language without modification and you can drop in quite literally arbitrary Julia code as components of your network and it works.
> don't think that LLVM IR that uses is the best IR for the optimizations.
What makes you say this? They community has been able to do some pretty amazing things performance wise-e.g. pure-Julia implementation of BLAS/LAPACK reaching and in some cases exceeding performance parity, plus there’s been plenty of work in CUDA support for arbitrary Julia code, which is impressive.
As a Software Engineer, who's been working on teams for the past 15 years and seeing the craft devolve, and the market saturate with people whom don't understand that fundamentals but memorize the frameworks, you need a language like Swift to bridge that gap.
It's hard enough to get people to program to an interface, let alone communicate what they are gonna return from a function or how a function behaves. 70% of people don't understand software engineering is legitimately just plumbing, they think its pretty much an artistic endeavour with no rhyme or reason. This makes it pretty difficult to stay on the same page, when building a product to scale up.
Having a strong type system solves that problem. When working with ML people my question 100% of the time is what does that function, return what type?, so I can build off what you are doing, or even debugging requires understanding of the type and the values.
It seems like team orientated programming is foreign to most people.
Swift has a low cognitive load pushing you to solve problems, with Software Engineering and reducing communication lead time between engineers.
All languages eventually converge Swift, I think Chris L has solved the language UI problem.
It's another classic example where it's simply not enough to open source something, you have to really allow and encourage the developers to contribute to increase the adoption.
For instance, maybe it's fixed now, but for years running the Swift REPL on linux would spit out a few error messages every time you ran it. It still worked, but it gave the impression of being poorly supported.
What really killed it for me was the rollout of features like FunctionBuilders (now result builders) and property wrappers. These were just basically crammed into the language in a half-finished state with no community review, to support the requirements for SwiftUI, despite many other features languishing for years and not being implemented due to concerns about how they would affect swift's "design space".
Following that, I had the impression that Swift was and would always be prioritized towards Apple's goals, and any use-case outside of this would be a distant follower.
If I had to guess, they don't do it because:
1. they don't think the resources it would take would represent a good ROI,
2. and/or they think it's good for them that developers who invest in their ecosystem have skills which are not transferrable to other domains
I would personally assume the shutdown was due to a combination of reasons:
- There simply being no good reason for Python users to ever move to Swift. There is no big painpoint being solved for the broad ML user community
- Organisational momentum lost with Lattner leaving
- General disarray of TensorFlow as a project, the parallel rise of Jax from/within prominent Google orgs, it being the cool new thing
As a swift and python user, I would have been really happy to be able to use swift for ML applications. Having a half way decent type system solves so many problems. But while I can see that from my vantage point, I know for a vast majority of the ML community python is "good enough" and there would be quite a lot of inertia to overcome in that regard which is probably not realistic.
Also I don't see why Swift would perform worse than python in any case. If python is fast, it's because it's wrapping a C++ library. There's no reason Swift could not wrap the same library, but on top Swift could communicate better type information back to the user.
There's many other advantages of Swift over Python for ML (concurrency and performance) but I just don't see the type system as one. At least not anymore.
What problems does it solve for you? When building ML applications I mean. Because that's what S4TF was supposed to be.
ML researchers produce models that are used by ML applications for a particular purpose. The code to train the model _could_ be statically typed, sure, but I really don't see what the improvement would be. It would be more verbose, less readable, have significantly more noise. Just try reading some TensorFlow C++ code equivalents of their Python API.
From the "WhySwiftForTensorFlow.md" document (https://github.com/tensorflow/swift/blob/main/docs/WhySwiftF...):
.. static types: * can catch bugs at compile time instead of runtime. People get very frustrated when a silly type error brings down a long training run hours into it. * directly improve tooling experience like code completion/intellisense, jump to definition, etc. * make it easy to know what operations are Tensor operations.
> can catch bugs at compile time instead of runtime.
OK, but what bugs? For most use cases of TensorFlow that I've seen, if there is a type error somewhere, you will catch it long before it hits production, and if you only catch it 100hr into training, your training code is either non-deterministic or there's some other issue that is not type related. Unless we're talking about dependent types a-la Idris, I don't see how Swift's type system can help catch these kinds of bugs.
> directly improve tooling experience like code completion/intellisense
Sure, but type-hints provide the same improved experience with language servers like PyLance [0]. Not a reason to jump to a new language.
> make it easy to know what operations are Tensor operations.
Easy. Anything that starts with "tf." is a tensor operation.
Yes, I'm being a bit trite, but I was never convinced by the premise of S4TF, because I've never heard an ML researcher or engineer say "static typing will fix my problems".
[0]: https://devblogs.microsoft.com/python/announcing-pylance-fas...
I was also once convinced that static typing was not so valuable - when I was working a lot with js, python and ruby, but the more time I spend with static typing the more I like it.
There is an "activation energy" to overcome with static typing: when you first start it feels like a tedious burden to have to add type annotations, when your python code ran just fine without them. But in my experience, with a little bit of practice the type system starts to feel completely effortless, and it saves you from all kinds of strange runtime issues you run into when nobody is checking your types.
Also type systems encode a lot of intention into the code. If I look at a function signature in Swift, I know exactly what has to be passed in, and exactly what will come out. In python, I have to rely on documentation, or even maybe I have to dig into the source to see what this function expects.
In my experience, the real difference is seen when you come back to a weakly-typed language after working with types for an extended period. Returning to Python after spending time with Rust or Swift feels like walking down the street with one of my senses missing. There are whole categories of dangers I now have to watch out for which the compiler would have caught for me automatically. It is not pleasant to go back.
You can easily find out if you like it or not, you can use the C++ API for TF/PyTorch and you'll have a statically typed program running your model for you. Sure, it's not Haskell, but C++ is statically typed, and although it's not the most popular or loved language on HN, you can use it to get stuff done.
One of the things that frustrates me with a lot of the languages I'm having to grok these days, is they often lack consistency, because it's one carrot after another to get buy in from different sub communities. And in the end it tastes like vegetable soup--edible, but not tasty (if you love vegetable soup, this reach of an analogy probably won't work for you).
The recent language additions have made me much less enthusiastic about it because like C++ it’s becoming a language where each person uses their own subset and style, instead of having a common elegance.
Swift is a gem of a language with an unfortunately Apple-centric ecosystem, but at least you know Apple won't abandon the effort.
But they are notorious for being poor at keeping some projects and products alive.
Would love to know Jeremy Howard's too.
I do a lot of functional style programming in Julia today, but I also love how Smalltalk works. There is a place for both styles. Swift IMHO is the worst of both worlds. This very OO style syntax mixed in with functional programming makes everything kind of messy. I easily get confused when looking at Swift code for this reason.
When you use anonymous functions, you don't want named arguments. That is an idiotic idea. However if you want to pass a message to a random object, then named arguments is quite nice.
I feel Chris Lattner is not a guy who could really appreciate the Smalltalk heritage of Objective-C.
Since ML has been a large rage for the last few years, and TensorFlow is one of the most popular frameworks that ML engineers use (although I use and prefer PyTorch) it seemed like the "perfect storm" for Swift to break out of the iOS mold.
But it was clear to me (and many of my peers) that while this was an interesting project, the need for it is really low, and that nobody is going to throw away years of experience with libraries like TensorFlow and PyTorch (via Python) in the trash just so we can use Swift, which for me isn't really that crazy of a language as all the hype makes it out to be, and I'm sure the same is true for many ML devs and researchers alike.
added lots of novel paradigms and rarely trodden code paths to the compiler and then peaced out.
I hope the inherent complexity added doesn’t impede future Swift development much, or is expeditiously deleted.
[1] - https://docs.google.com/document/d/1Fm56p5rV1t2Euh6WLtBFKGqI...
[2] - https://github.com/tensorflow/swift/commit/1b1381ccb89a342ba...
https://twitter.com/texasmichelle/status/1360287563898974211
I think we just have to wait for the meeting video to be posted
My guess: Google concluded that investing in a language developed behind closed doors of another company is a bad deal.
I don't blame Apple, it may be a good business decision for them, and of course it is completely within their rights.
https://forums.swift.org/t/differentiable-programming-for-gr...
https://github.com/rxwei/swift-evolution/blob/autodiff/propo...
I guess this is sort of an ad.
Swift was a weird choice for statically typed TensorFlow, being only popular on the platform, that does not have GPU/TPU support in TensorFlow, which is, basically, a requirement for any serious work. The fact, that they had to fork the compiler did not help either.
TensorFlow for C# is much like TensorFlow for Swift. There's a statically typed binding to the core types with the rest of the TensorFlow API available through an open source Python.NET project [1]. Unlike Swift version though, that second part is also mostly statically typed, so you can get IDE autocompletion hints. Also, .NET runtime has native support for dynamic languages.
Like with Swift for TensorFlow, we ported all recent interesting neural network architectures (and maybe even more): Transformers (GPT-2) [2], CNNs (YOLOv4) [3], Q-learning (e.g. RL, actor-critic) [4], and even some cool ones, that have lots of unexplored potential like Siren [5] (this one uses sin/cos as activation functions).
Although we have not worked on automatic differentiation yet, unlike Swift, it will not need compiler support. .NET (and Java) can inspect and generate code at runtime, so autodiff can be implemented in a library.
We also have integration with Unity ML Agents for training robotic agents [4].
[1] https://github.com/pythonnet/pythonnet/
[2] https://github.com/losttech/Gradient-Samples/tree/master/GPT...
[3] https://github.com/losttech/YOLOv4
[4] https://github.com/losttech/Gradient-Samples/tree/master/RL-...
[5] https://github.com/losttech/Siren https://vsitzmann.github.io/siren/
This is available now (not sure if it's in mainline).
https://blog.tensorflow.org/2020/11/accelerating-tensorflow-...
In my opinion, Rust will end up winning this contest, but others have perfectly good arguments against that view. Unfortunately for server-side Swift and the many good people who've worked on it, there seems little chance for it, in TensorFlow or other usecases.
Rust will eventually win low-level programming from C++, but massively networked applications will always be slightly easier in Go. Swift is a bytecode language, it competes against .NET (mainly C#) and JVM (Java and variants), not Rust or Go.
IMHO Swift seems to losing when not tied to Apple's ecosystem, its future will be as some Apple-niche language.
I'd say 'GC runtime languages' are somewhat dubious for low latency etc. (but see Unity and ZGC!), while 'low-level languages' are overkill for typical UI/CRUD apps, I don't see any useful advantage for Rust there.
* Go would be in the middle I guess - technically requires a runtime, but the runtime is relatively light and all binaries are static - unlike .Net whose static compilation support is frankly rather theoretical right now due to common use of its powerful reflection capabilities.
The intention was to merge the fork into the main language making Swift differentiation tools first class within the language.
The best explanation I can think of is that the people naming it wanted the first word to emphasize the thing that's most important to them. In Microsoft's case, that's of course Windows. Perhaps the same is true for the S4TF folks.
BTW, the Haskell bindings for TensorFlow have been actively maintained for years. The latest update was 3 days ago.
While the readme tells us that the project is in archive mode, it also tells us that the differentiable programming part is still worked on by the compiler team. Is there further information on that?
They should just had chooen Julia.
Until the video of the last meeting is posted im guessing maybe its bc the execs set a deadline and it got passed
How hard is it to have a program that takes in neural network architectures & trained waits so as to do inference?
Way nicer to use Swift than python for this, and I have rewritten this bot several times in different languages + frameworks (objc php java python swift tf1.0 theano keras s4tf) since 2012.
Doing authentication for brokerage apis + correctness from pulling from the db is easier to get right in Swift than python bc of the static typing + grand central dispatch for parallel queries.
It is also way more productive for me to have the compiler catch issues at the beginning instead of 6 hours into a data generation job where the python interpreter sees a None for something I didn't think of.
The only functional features I can think of are closures, map/reduce/etc., and value types.
I have a lot of criticisms about Swift but this one seems weird/outdated to me.
Putting aside the Python 2/3 transition, I think that Python does a good job of introducing new features carefully. For example, the "X if P else Y" syntax. While I prefer the C approach, the Python approach works fine and fits in the language well.
I had a mild dislike of Swift from the beginning, but it was a lot more palatable than working in Objective C. What bothered me was all the gimmicky syntax. Sometimes "let" unwraps an optional, sometimes it doesn't. ! and ? seem badly overused. ARC doesn't compose well with other language features. There is a ton of syntax whose only purpose appears to be to stuff logic into and around assignment syntax. Then it got worse, with major language changes across versions 3-5, each one introducing lots of new concepts and syntax.
And of course, Swift is a proprietary Apple language, (in the same way that C# is tied to Microsoft). When I stopped doing iOS programming, I very happily but Swift behind me.
I saw the TensorFlow additions to the language and thought the whole thing bizarre. I put my reaction down to my lack of involvement with data science. Maybe I'd appreciate those changes more if I knew more about data science. But I also remember thinking that it was quite odd to make such extensive additions to the language to support this one application area, which was very, very far from the language's sweet spot.
that's not say I would use Swift, but I'd choose Julia any day over Python.
It certainly isn't a functional programming language. It's intentionally imperative.
Tensorflow for nodejs makes much more sense, node community is lit bigger and not sponsored by big corp.