I used to be a big Swift fan but as I go back and forth I must say Julia is a much better language, and a lot of that is down to syntax.
Swift syntax is really a pain to deal with. I programmed Objective-C for many years, and that syntax makes sense for object-oriented programming. But it is a disaster for functional programming.
Making closures and calling function objects gets really confusing with Swift syntax. Swift methods cannot naturally be passed around like a Julia function.
> str.parse(Int).abs is more readable than abs(parse(Int, str))
The problem is that the Swift approach entirely lacks composability. Julia's `abs` and `parse` can easily be passed around as first class objects. Besides a lot this readability cases can be solved with the `|>` operator like this:
parse(Int, "-12") |> abs
The Julia approach makes it easy to use functions as arguments to higher order functions such as map and broadcast. Using dot (.) is shorthand for broadcast which lets you do stuff like:
abs.(parse.(Int, ["-12", "-3"]))
parse.(Int, ["-12", "-3"]) .|> abs
Both cases show parsing an array of numbers and taking the absolute value.
> 1-based indexing.
I know many people hate this but I don't get it. I have spent most of my life with 0-based indexing yet this represents no obstacle for me. When I use Julia I just think as if I am writing math. All my math text books are 1-indexed based and that is just something you get used to. In fact after using Julia for a long time, I frankly prefer 1-based indexing.
0-based indexing IMHO is quite nice when you are dealign with inserting numbers into arrays, or with C-style loops. But neither is usually done in Julia.
> Lack of good support for nullability, think of "if let", "guard let", "??", "object?.property".
That used to bother me as well coming from Swift. But this request actually makes not sense in a dynamic language. What you are basically asking it to have programming constructs to give you type safety at compile time. But Julia is a dynamically typed language, so you will never have this anyway. It if a fools errand.
Julia is built to catch type problems at runtime, not at compile time. Those problems will be caught at runtime in Julia even without `if let` and `guard let`. They don't actually add any value to a language like Julia.
Swift NEEDS these constructs because statically typed languages are quite poor at catching type problems at runtime. They are very dependent on catching type problems at compile time.
> OOP support is "meh".
I kind of view that as a positive. I have spent years doing object-oriented programming but I must say the Julia way just makes a lot more sense. It is so much easier to work with. I find OOP inherently bad for a REPL environment. And REPL environments make me a lot more productive. You can built up functionality in a far more incremental and iterative fashion.
I still quite like Swift, but I feel it is going in the wrong direction. I tell tale sign for me when going back to Swift code these days is being reminded just how complex the language and the tools have gotten. If you do Swift everyday, that is easy to forget, but the whole toolchain is actually kind of complex.
For instance getting a closure setup correctly with appropriate tagging for life time/ownership of data is not easy. The Schizophrenia between trying to be both an object-oriented language and a functional one becomes more and more apparent.
Sometimes I wonder if Apple made the right choice and whether going with something more akin to Objective-Smalltalk would have been better. It would have been a more natural fit with the Objective-C syntax, which feels very wrong in a functional setting.