894 karma · joined October 9, 2013
Funny, wildly different times, I don't think github was even popular (existed?) back then.
You are, in fact, right. But I advise you to read about HTTPS here, so you can more clearly understand the points others are making: https://en.wikipedia.org/wiki/HTTPS.
The idea would be that the function names are so good that one does not need to read the function contents, right?
But some things are complicated and may not be expressible with the function name alone.
That's why people write comments. To help readers understand the code.
Let's say I am implementing some algorithm. I may mention the performance characteristics in the comment. Or I may let the readers dig into the code to find out what they are. Seriously, please don't follow "no comments" rule dogmatically.
Usually you construct the pipeline to switch between these as you need. If you need to share the result from one mutation to the other, you can do it by passing a simple immutable value that communicates the state change to other mutation, but don't try to do both at the same time. This is simply a good practice enforced at compile time. Of course, sometimes these rules prevent some valid cases, but overall it is worth it.
If we are talking about HashMaps, the Rust std lib has useful Entry api to for get-or-insert use cases. In rare cases where you need to share the value between different parts of the system, there are primitives you can wrap your value in and enable reference counting, as well as internal mutation (even if wrapper is immutable, it provides safe api for mutation). In cases where the concurrency is needed, there are mutexes, channels, and multiple libraries to parallelize the code (like rayon or crossbeam).
I have removed a bit where I say that rvalues are same as returned values, to avoid confusing other readers.
It took me a month (of my free time) to start feeling like I can write code in Rust. It felt like I was learning programming all over again.
There were several reasons for that: first, I assumed that Rust can be used the same way as Javascript, with callbacks everywhere, and second, I was used to OO patterns that can not work in Rust. So, to overcome that, I had to realize that while Rust may have modern features, it is fundamentally a low-level language; and I had to really understand what the OO patterns actually give me to find the alternatives in Rust. I think that these things have made me a better programmer overall.
I remember these distinct stages.
Rust is low-level stage: It took a while to realize that Rust structs live on stack, and the pointer to such struct can not be freely passed around like an object, because the stack frame will be gone at the end of a function.
I found out how to do virtual dispatch: the fact that borrowed traits have virtual dispatch table was missing from docs at the time (they are called Trait Objects). This is what I was actually missing from OO: a way to use the interfaces without putting everything into enums, and have a way to invert dependencies.
There is a borrow checker, but you need to think in ownership: Again, I was trying to use references as if they were objects in OO language, while the primary model is ownership. I wrote a bog post at that time discussing this: http://nercury.github.io/rust/guide/2015/01/19/ownership.htm...
Rust is more functional than it seems: At that point I found that you can model anything in Rust if you can express it as a data-flow from the input to output. Turns out, anything can be expressed as the data flow. The data that flows can be uniquely mutable, processed in parallel. I had to ditch thinking in highly shared hierarchies of objects and focus on flows that transform one set of structures to other sets of structures.
Destruction after last use (RAII) ensures that resources such as files, sockets, db connections are closed. Also unavailable in majority of languages.
Also the language is expressive (type inference, generics, pattern matching, traits).
These three things are the main reasons, although I wish other languages (old or new) would pick up the first idea too.
For example, if I have a big string, I may create a hashmap where both keys and values are references to some portions to that original string.
Then, I may pass this hashmap to another function that will transform this hashmap into structs that contain reused portions of those string references.
Rust compiler will make sure that the original string is not destroyed or moved in any way in memory while this is happening.
While it is certainly possible to do this in C and C++, the development cost there is way higher. In C++, one would be sensible to stick to a slower version that copies and allocates data, unless he/she is really sure that the need for performance justifies the code complication.
Meanwhile, juggling the references this way in Rust is common and almost sloppy: the hashmap contains references to strings because it was probably created from iterator that iterated over references. The developer might not even need to notice it unless the string reference in result might be kept around longer than original. The compiler will tell about the type mismatch, and the developer will then create a new string from the reference, and then he/she will move on.
There is a similar story when such code needs to be refactored. The word "sloppy" still works here, but in a good way: offloading "being very, very careful" stuff to compiler is deliciously fun.
TDD workflow is fine; it's not thinking about the pink elephant (the source code) idea that bugs me.
You CAN indeed cover all your branches with tests afterwards. You can even give that a fancier name, like "Exploratory Testing". Of course it may be more boring or tedious, but is a perfectly valid way to ensure coverage when needed.
TDD was great for popularizing writing test first; However I much prefer the methodology called CABWT - Cover All Branches With Tests. Let the devs choose the way to do it, because not everyone likes these pretend games.
For example, C++ Core Guidelines [0] is longer than Rust Book. Core Guidelines is itself a great example of things one needs to keep in the head while writing C++ code.
Look at implementation of something as basic as optional<T> [1]. The amount of things one needs to know is so high most C++ developers would never attempt it.
[0]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppC...
[1]: https://github.com/akrzemi1/Optional/blob/master/optional.hp...
Yes, unless there is some other mention of Vec, i.e. it is returned from the function.
> This is impossible without varargs, no?
Varargs would definitely help, and would allow Rust to borrow more ideas without workarounds. But one can do it manually for each tuple variant.
It may be possible to implement `.zipped` on tuples though.
On every request, PHP reads and parses every file that is referenced somehow. It is in direct contradiction to the language constructs the PHP itself provides - especially Exceptions, Interfaces and Inheritance.
People want to use these features, because they help design better systems, where the concerns are separated, and features are plugins instead of hardcoded all over the place.
Unfortunately, the required files for a request can pile up quite quickly, to the point where bytecode cache does not help, serving multiple requests per PHP load does not help, prewarming cache for frontend such as Varnish does not help, memory usage is over the roof because of trashed heap memory.
So, to sum up, the author here is right: this is insanity, until PHP provides a module system that can handle PHP abstractions.