📜 ⬆️ ⬇️

Rust and Swift (introduction, first and second parts)

From the translator: I decided to take on the translation of the cycle in which the author simultaneously studies Rust and Swift and compares them to each other. I tried to preserve the style and manner of writing the original, although in some places I allowed myself to shorten the text (I hope) without losing meaning.
The author at first seems too biased toward Rust, but then his judgments become more balanced. True, I myself am very superficially familiar with Swift, but in Rust, I would like to think I understand something, so I am not impartial in this matter either. The comparison becomes more interesting, starting with the fourth part, but, as they say, you can’t throw the words out of the song.

Rust and Swift

Comparing two fascinating, new and, obviously, (although not always) similar programming language.

Prehistory

In the summer of 2015, I began to study Rust . Then, in September 2015, I took up the Swift . At first glance, the similarities between the two languages ​​are obvious, and they reached a stable version at about the same time: Rust 1.0 was released in May 2015, and Swift 2.0 (which is actually similar to 1.0, since 1.0 served as a public beta) in June 2015. Both were inspired by languages ​​such as Haskell, while at the same time preserving C-like (in fact, of course, ALGOL-like) syntax, more familiar to many developers who are oriented to these languages.

So when I started the book about Swift , I could not help comparing. Although both languages ​​seem very similar, they are also very different in terms of the design of the language and the philosophy behind it - and these differences are very interesting!

Few notes

I am by no means a guru in the theory of programming languages. (Or at least it wasn’t. This project, along with several others, can make me like this). I'm also not an expert. My opinions are thoughtful, but not necessarily comprehensive, and you will find the places where I added corrections as I learned new information from the reviews.
')
I openly admit that I'm leaning towards Rust. I like Swift, but I really loved Rust. I think it will be honest to admit that this is a matter of my personal language preferences. I love Python more than Ruby, and Rust feels more like Python, and Swift more like Ruby.

Now I open the cards completely - I also made my contribution to the future of Rust - I lead a podcast about him that brings me (quite a bit) money.

One more thing: in February 2016 I did not have the opportunity to write anything serious in any of these languages, although I hope to change the situation during this year. Thus, I had many superficial impressions about these languages. My thoughts and feelings about them may change over time.

And finally: this series of articles in the literal sense of the word began with comments in Slack. In the following sections, you will notice significant changes in tone, structure and content. The first part was just my first impressions of what I read. Starting from the second part, I approached this more intelligently. In the following parts, this approach was strengthened, which was also due to my work on the podcast “New Rustacean”.

Rust and Swift (I)

Thoughts after reading the introduction to the book about Swift

- .. <- seriously?
This must be one of the most annoying operators I've ever seen. It complicates perception, because "<name", at first glance, is perceived as the beginning of a generic and you have to re-examine and comprehend.

After the first chapter of the Swift tutorial, my impression was as follows: “a pitiful similarity to Rust.” It was based on the first approach and everything I saw and read about Swift over the past two years: roughly speaking, this is the syntax of Rust and the desire for security, replaced by compatibility with the semantics of Objective-C. (Pay tribute to Apple - this compatibility was probably necessary).

An example clearly illustrating the difference in approach is how structures are transmitted: by reference or by value (transfer of a copy). In Swift, two separate language constructs are used for this: structures and classes, respectively.
In Rust, there is only one type of structure for both cases. They are immutable if not declared mut, and you can pass them by value by implementing the Copy Trait (which looks something like the protocol in Swift, but I haven't dug so deep enough to see the difference). That is, instead of introducing these entities into the language, simpler language constructs are used to define behavior.

Recently, I read the opinion that Go is not a bad language, it is simply not good enough. After I was doing Rust for the last month, my first impression of Swift was very similar.

Fuh. There is something that I now appreciate in Rust, Haskell, and other languages: there is a difference between an implicitly / automatically imported set of standard functions and the presence of truly global functions. Are there actually functions in Swift, such as print in the global namespace, which seems to be implied in the book, or are they imported automatically, as in Rust / Haskell, etc.?
Correction: Swift works in the same way, but you cannot directly access the corresponding module. Looks like a half decision.

Hmm ... Why do we need Double and Float? Is it only to interact with Objective-C?
Amendment: a friend told me that there are 32 and 64-bit architectures. Sometimes you just don’t want to use 64-bit floating point numbers. By the way, Rust also has two separate types: f32 and f64.

In continuation of the conversation about classes, structures and protocols: the difference in approach is also valid for extension methods that are not identical to the implementation of the protocol. In Rust, the one and the other is solved by the same construction - impl. This is not because impl is overloaded, but because the underlying language mechanisms work the same way.

(I feel that learning Swift makes me even a big fan of Rust.)

Parallel reading of two books proved to be really productive in terms of understanding how these two languages ​​approach the solution of the same problems. I have never done anything like this, and it is fascinating.

I especially like the way semicolons are used in Rust to convert expressions into statements (statements), which makes it easy to distinguish one from the other (including by allowing the implicit return of any expression).

Here is another interesting comparison: match in Rust and switch / case in Swift are used for pattern matching (pattern matching). I wonder how they differ. Does Swift allow comparing an arbitrary expression?
I also see the choice of syntax in both languages, and, although I tend to Rust more, I think both options are pretty good. Swift syntax, for obvious reasons, will be more familiar to programmers in C and Objective-C, and this is completely justified.

Rust and Swift (II)

Basic types and syntax associated with them

At first glance, the extra syntax around optional values ​​is more confusing than helpful. It seems to me that this is caused by the fact that I prefer the approach taken in Python: “the obvious is better than the implicit” and “there should be one and preferably only one obvious solution”. This goes against many different ways in which you can interact with optional values ​​in Swift. Optional types are declared in two ways:
- Operator "?" creates an explicit optional type that needs to be checked one way or another.
- Operator "!" creates an “implicit optional type” by “unpacking” and causes an error at runtime if the optional value is empty.

After creating an optional value, you can interact with it as follows:

In Rust, on the other hand, you are always forced to explicitly use the unwrap method or pattern comparison. It does not have implicitly decompressed types. Moreover, in Rust there is no special syntax for creating them: they are simply declared via Option or another type with the same behavior. try!, which reduces error handling, is not a special syntax, but the use of another standard language construct (in this case, macros).
[Translator's note: since writing this article in Rust, after all (almost) a special syntax analogous to try has appeared! - "?", Which, however, does not the same as "!" in swift. It is worth noting that not everyone accepted this innovation with joy. Unfortunately, alternatives suggest the presence of higher order types (HKT), which are not yet available in Rust.]

The discussion of assert in the Swift tutorial again raises the question of the global namespace: “The global function assert (_: _ :) is used for these cases”.

This is another sign that Swift actually uses a real global namespace, rather than automatic import, which can be important in certain cases, for example in system programming, when you have a reasonable desire to replace the standard library with another. (See # [no_std] in the Rust and RFC documentation on this topic) .
Correction: I learned from reliable sources that I was wrong, and I am glad about it. As in Haskell, these functions are implicitly imported and are included in the Swift module.

In Rust assert! is not a function, but a macro: this distinction is of interest, but it does not matter in this case. (Although it may have, I need to see the implementation of both in order to understand how they differ).

In any case, this underscores another significant difference: in Rust, testing takes center stage , while the Swift manual does not mention much (and is not included in a separate chapter in the table of contents). Support for testing at the language level is very important.

After reading the introduction and the first part of the Swift tutorial, I believe that, although this language is much more suitable for developing applications than C or C ++ (and, presumably, Objective C, but since I don’t know it, I can’t judge it) Rust is still better. Both languages ​​are more modern than their predecessors, but the same problems in them are solved in surprisingly different ways, despite the similar syntax. So far, I like the Rust approach more.

In particular, I prefer not to add a special syntax for each individual case. Providing good language constructs and primitives on which everything else builds seems best for many reasons:

Source: https://habr.com/ru/post/280274/


All Articles