Live data from Hacker News

Rust means never having to close a socket

blog.skylight.io

111–120 of 165 posts

Re: Rust means never having to close a socket

#111
Slightly off topic, how do I go about doing any meaningful GUI programming in Rust? Do Qt bindings exist for Rust? How easy or difficult is it to create such bindings? It's a great language but if it doesn't have a bridge of some sort to the existing legacy code (C++ included), then it's no good to me.

Re: Rust means never having to close a socket

#112
post #99
post #54

Earlier quoted context omitted.

1. Familiarity to C++ programmers, for whom taking a reference via `&` is a familiar operation. 2. There are two different kinds of references: `&` is immutable and `&mut` is mutable. One way or the other you'd need some sort of differentiation. 3. Borrowing, though crucial to the idea of Rust, is still less fundamental than ownership. You can have a language with ownership and without borrowing (indeed, this is how…

Doesn't #1 matter less in Rust? C++ has to deal with backward compatibility in syntax, Rust doesn't. Based on this article, immutable references are the most common kind of declarations. It seems to me that rust code would look much cleaner if they had the shortest syntax (including in pattern matching etc)

Rust's primary intended audience is C++ programmers, and familiarity is a powerful asset. It's not the sole determinant of syntax concerns, but it's an important consideration.

Re: Rust means never having to close a socket

#113
post #85
post #63

Earlier quoted context omitted.

Props to Rust for tackling this head on, more languages should provide resource allocation that's deterministic, predictable and syntactically convenient. CPython's behavior is nice, but it seems to me it came about by accident. Big heavy resources use refcounting because everything uses refcounting. Plus, if CPython had true concurrency, across-the-board refcounting probably wouldn't have lasted nearly as long (reas…

I agree that refcounting is a great and usable compromise in this space, but your own comment flirts with why I don't think modern languages are chomping at the bit to base resource management on it: concurrency. Granted, I have no idea how much overhead is imposed by atomic operations vs. a stop-the-world or concurrent GC (if anyone has some data, I'd love to see it!). But given how it's become de rigeur for new lan…

"Granted, I have no idea how much overhead is imposed by atomic operations vs. a stop-the-world or concurrent GC."

An atomic read/write/increment/decrement is a non-blocking (from the point of the view of a user code running on the CPU) CPU operation. The CAS operations required to do atomic inc/dec are relatively expensive compared to normal memory read/writes of course but nowhere near the scale of stop-the-world GC (where all threads in the runtime have to be blocked for a potentially large amount of time, sometimes measured in whole seconds or even 10's of seconds for large heaps).

Anyone who has had to troubleshoot JVM's handling large heaps (in the ~10GB range) quickly learns to love deterministic costs of refcounted resource management.

Re: Rust means never having to close a socket

#114

"Rust achieves both of these features without runtime costs (garbage collection or reference counting), and without sacrificing safety." If it is freeing everything at the scope boundary it is incurring a huge runtime cost relative to garbage collected languages. GC scales with the number of live objects during GC while this scheme scales with the number of allocated objects. It is far more predictable than GC but I…

In general, idiomatic Rust puts most objects that would be in a semispace nursery on the stack instead, which has all the advantages of a semispace collector, plus improved locality and the lack of a mark phase. The lifetime system means that the traditional limitations of escape analysis (higher order functions, separately compiled functions, virtual functions, returning objects on the stack) largely don't apply.

Re: Rust means never having to close a socket

#115
As someone who's been using (and really liking) rust for about 6 months, there are two things in this article which are, I'd say, 'common misconceptions' about rust:

    One of the coolest features of Rust is how it automatically manages 
    resources for you, while still guaranteeing both safety 
    (no segfaults) and high performance.
In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your entire code path contains only safe code.

NOT, if you only write safe code.

That is, if you write entirely 100% safe code, and use some library that uses 'unsafe' code at a low level (this is very common; for example, an C binding or memory optimization), then rust does NOT guarantee safety.

Furthermore, there is no way to know if your code path includes unsafe code.

Rust is relatively safe; it's just not totally safe. Using rust does a reasonable job of protecting you from segfaults most of the time; but it's not a silver bullet.

    As soon as the program stops using the resource, its cleanup logic gets 
    invoked.
    
    ...

    Because only one scope owns an object at a time, you can tell just by 
    looking at it which objects will be destroyed when it's done executing.
This isn't always necessarily true.

Rust uses 'drop flags', which are extra bytes at the end of struct instances in memroy, to track objects and keep meta information about them to determine if they should be dropped.

At the end of scope when the drop checker runs it checks against these drop flags to determine if an object should be dropped or not.

(For example, if a closure captures a variable it may no be dropped at the end of the scope it would normally have been dropped in).

There seems to be this myth that resource deallocation in rust is magically determined at compile time and the has 'zero cost'; it's simply not true.

There is a runtime cost to the drop checker; it's not particularly large, but it's certainly not just a sequence of drop operations.

Don't get me wrong; I really enjoy rust, and I like it a lot. ...but those two ideas pop up repeated in discussions about it, and they're not exactly correct.

Re: Rust means never having to close a socket

#116
post #98

Earlier quoted context omitted.

OP is correct. You've quoted the general language around move semantics but unique_ptr itself has a stronger gaurantee. From 20.7.1 Additionally, u can, upon request, transfer ownership to another unique pointer u2. Upon completion of such a transfer, the following postconditions hold: — u.p is equal to nullptr, unique_ptr isn't what's unsafe here. Null pointers are. The difference, admittedly, is mostly semantic. Th…

> There is nothing undefined about using a unique_ptr after moving unless you use the internal pointer in undefined ways. If you dereference (i.e. use) a moved unique pointer you get undefined behavior. When talking about "using a pointer" most people mean dereferencing it, not for example comparing against null. It may be somewhat imprecise language, but it's what security people mean when they talk about "use after…

This is definitely outside the scope of my knowledge, but if you dereference a null pointer, won't you get an illegal memory access?

Undefined behavior, at least colloquially, is about dereferencing a pointer to memory that may or may not be accessed and may or may not work/crash-the-program. That's what makes it undefined and an absolute disaster to track down.

I'm pretty sure that if you try to deference memory address zero the OS will bark at you.

Again, it's not my area of expertise, so please correct me if I'm wrong

Re: Rust means never having to close a socket

#117

As someone who's been using (and really liking) rust for about 6 months, there are two things in this article which are, I'd say, 'common misconceptions' about rust: One of the coolest features of Rust is how it automatically manages resources for you, while still guaranteeing both safety (no segfaults) and high performance. In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your enti…

> In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your entire code path contains only safe code.

I think this is actually a misconception. In every high-level language (Ruby, Python, etc.) there are APIs for interacting with low-level code. These APIs (C bindings and FFI) are unsafe, and are in the path of virtually all high-level code. It is the responsibility of somebody implementing a C binding for Ruby to ensure that the publicly exposed API is safe.

If you use `nokogiri` in Ruby and get a segfault, that is a bug in nokogiri. It is not an indication that Ruby is unsafe. Similarly, the "safe" dialect of Rust is Rust. Rust provides a low-level binding to unsafe code via the unsafe dialect that is philosophically equivalent to the FFI API or C bindings in Ruby. If somebody uses the low-level binding and exposes a Rust library that segfaults, there is a bug in that binding, full stop.

I think this is very important. If you use regular Rust code with the expectation that "anyone in your path may cause you to segfault", something has gone very, very awry in the ecosystem. This is not an expectation in other high-level languages when people write low-level libraries with unsafe code in them, and it should not be an expectation in Rust.

> Rust uses 'drop flags', which are extra bytes at the end of struct instances in memroy, to track objects and keep meta information about them to determine if they should be dropped

This is in the process of being eliminated (see https://github.com/rust-lang/rfcs/pull/320). I didn't mention it because it's runtime overhead that will not be present shortly, and certainly by the time 1.0 is reached later this year.

Re: Rust means never having to close a socket

#118
post #117

As someone who's been using (and really liking) rust for about 6 months, there are two things in this article which are, I'd say, 'common misconceptions' about rust: One of the coolest features of Rust is how it automatically manages resources for you, while still guaranteeing both safety (no segfaults) and high performance. In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your enti…

> In rust there are two types of code. 'safe' and 'unsafe'. The above is only true if your entire code path contains only safe code. I think this is actually a misconception. In every high-level language (Ruby, Python, etc.) there are APIs for interacting with low-level code. These APIs (C bindings and FFI) are unsafe, and are in the path of virtually all high-level code. It is the responsibility of somebody implemen…

> If you use `nokogiri` in Ruby and get a segfault, that is a bug in nokogiri. It is not an indication that Ruby is unsafe.

Rust has a strict definition of safety; not all rust code for fills that guarantee.

We're not talking fast and loose here. These are absolute definitions.

You can write safe code that crashes in rust. That absolutely violates the safety guarantee whatever the reason for it.

> This is in the process of being eliminated

No it's not.

    Keep dynamic drop semantics, by having each function maintain a (potentially empty) 
    set of auto-injected boolean flags for the drop obligations for the function that need 
    to be tracked dynamically (which we will call "dynamic drop obligations").
What's happening is some of the run time overhead is being reduced.

Re: Rust means never having to close a socket

#119

Great post. I think it's the first I've ever read about Rust clearly clarifies the owner of a ownership is scope. It may sound ridiculous but all other talking about ownership without mentioning who is exactly the owner.

Yeah, I sort of had to figure that out for myself too. Everyone talks about ownership being recursive without specifying the base case.

Re: Rust means never having to close a socket

#120

In garbage collected languages with macros and an "unwind protect" operator, we avoid explicitly closing files and other resources using with scoped binding constructs implemented by macros. (with-locked mutex ;; ... critical section ) ;; mutex is released here

That only works if the lifetime of a resource is a lexical region, right?

Right. One case in which I've come across this problem in Python is writing unit tests for code using Twisted (and Trial, Twisted's unit test framework) with @inlineCallbacks, and trying to also use this style of resource management for mocks (or, essentially the same, the @patch decorator to set up the mocks).

If you have something like:

   @patch('some_module.some_object')
   @inlineCallbacks
   def test_my_stuff(self):
       do_stuff()
       yield some_operation()
       do_more_stuff()
       self.assertFalse(True)
Then you run into the problem that @patch has cleaned up all of your mocks by the time the yield returns.

Now, I haven't tried to do anything equivalent in Rust; I'm not sure what the idiomatic equivalent would be. But having more explicit control of lifetime, rather than it always depending specifically on that stack frame, seems like it might help here.

Post reply on HN