←back to thread

364 points Klasiaster | 10 comments | | HN request time: 1.244s | source | bottom
Show context
akira2501 ◴[] No.41851912[source]
I personally dislike rust, but I love kernels, and so I'll always check these projects out.

This is one of the nicer ones.

It looks pretty conservative in it's use of Rust's advanced features. The code looks pretty easy to read and follow. There's actually a decent amount of comments (for rust code).

Not bad!

replies(2): >>41852794 #>>41855386 #
wg0 ◴[] No.41855386[source]
Otherwise is a decent language but what makes it difficult is the borrow semantics and lifetimes. Lifetimes are more complicated to get your head around.

But then there's this Arc, Ref, Pinning and what not - how deep is that rabbit hole?

replies(5): >>41855987 #>>41855995 #>>41856204 #>>41856306 #>>41856588 #
KingOfCoders ◴[] No.41855995[source]
I always feel Arc is the admission that the borrow checker with different/overlapping lifetimes is too difficult, despite what many Rust developers - who liberally use Arc - claim.
replies(5): >>41856058 #>>41857157 #>>41857254 #>>41857856 #>>41859332 #
jeroenhd ◴[] No.41857157[source]
Lifetime tracking and ownership are very difficult. That's why languages like C and C++ don't do it. It's also why those languages needs tons of extra validation steps and analysis tools to prevent bugs.

Arc is nothing more than reference counting. C++ can do that too, and I'm sure there are C libraries for it. That's not an admission of anything, it's actually solving the problem rather than ignoring it and hoping it doesn't crash your program in fun and unexpected ways.

Using Arc also comes with a performance hit because validation needs to be done at runtime. You can go back to the faster C/C++ style data exchange by wrapping your code in unsafe {} blocks, though, but the risks of memory corruption, concurrent access, and using deallocated memory are on you if you do it, and those are generally the whole reason people pick Rust over C++ in the first place.

replies(1): >>41857894 #
1. GoblinSlayer ◴[] No.41857894[source]
Looking at the code, it consists of long chains of get().unwrap().to_mut().unwrap().get() noise. Looks like coping with library design than ownership tacking. Also why Result<Option<T>>? Isn't Result already Option by itself? I guess that's why you need get().unwrap().to_mut() to get a value from Result<Option<T>> from an average function call?
replies(2): >>41858336 #>>41858604 #
2. LinXitoW ◴[] No.41858336[source]
If I ask my repository (backed by an sql db) to get a user, there might be 3 different scenarios I'm interested in:

- Technical problem (like connection problems) means I don't know what's in the db

- No technical problem, but no user entry

- No technical problem, and a user entry

You need the Result for the technical problems, and the Option for whether there's a user entry or not.

replies(1): >>41859945 #
3. thesuperbigfrog ◴[] No.41858604[source]
>> Also why Result<Option<T>>? Isn't Result already Option by itself?

No. I've written code that returns Result<Option<T>>. It was a wrapper for a server's query web API.

The Result part determines whether the request succeeded and the response is valid.

The Option part is because the parameter being queried might not exist. For example, if I ask the API for the current state of the user session with a given Session ID, but that Session ID does not exist, then the Rust wrapper could return OK(None) meaning that the request succeeded, but that no such session was found.

replies(2): >>41859652 #>>41859658 #
4. GoblinSlayer ◴[] No.41859652[source]
Presumably missing session is an alternative scenario and thus should be reported as an error, then you match and handle this error. Your design complicates the common scenario: in case of valid session you need double unwrap, cf File::open that could return Result<Option<File>> if file is not found.
replies(1): >>41860445 #
5. oniony ◴[] No.41859658[source]
Result is whether an operation returned an error or not. Option is whether you have a value or no value.
replies(1): >>41860266 #
6. GoblinSlayer ◴[] No.41859945[source]
Surely Result is supposed to hold both system errors and business errors.
7. thesuperbigfrog ◴[] No.41860266{3}[source]
Exactly.

That is why a query that successfully returns no items can be represented as Ok(None).

A successful query with items returned would instead be Ok(Vec<Item>).

An error in the completing the query (for example, problem with the database), would be Err(DatabaseError) or Err(SomeOtherError).

8. thesuperbigfrog ◴[] No.41860445{3}[source]
>> Presumably missing session is an alternative scenario and thus should be reported as an error

But in this case, a query using an invalid session ID is not an error. It is asking for details about something that does not exist.

>> cf File::open that could return Result<Option<File>> if file is not found.

This type of query is not like File::open which gets a handle to a resource. Trying to get a handle to a resource that does not exist is an error.

This type of query is read-only and does not allocate any resources or prepare to do anything with the session.

It simplifies the control flow because it distinguishes between errors in completing a query versus the presence or absence of items returned from the query.

replies(1): >>41864904 #
9. lenkite ◴[] No.41864904{4}[source]
How does the caller know whether the response was empty because of an invalid session id ? You have conflated empty response with an erroneous situation. The simplest solution is just Result<T, E>.
replies(1): >>41865871 #
10. thesuperbigfrog ◴[] No.41865871{5}[source]
>> How does the caller know whether the response was empty because of an invalid session id ?

Documentation and how SQL database queries work.

The documentation states that a valid session id will return a SessionInfo struct (since it is an Option the type is Some(SessionInfo) ), and that an invalid session id will return None.

If the SQL query is something like "SELECT * FROM USER_SESSIONS WHERE USER_SESSION_ID = $1" then if an invalid session id is provided the database returns zero rows. The query was successful, but there were no matching sessions with that session id.

>> You have conflated empty response with an erroneous situation. The simplest solution is just Result<T, E>.

Again, an empty response is not an error in this situation. If your database query returns zero rows, is it an error? The database query succeeded. There are no sessions with the provided session id. What error occurred?