Live data from Hacker News

Thoughts on Rust, a few thousand lines in

rcoh.me

71–80 of 183 posts

Re: Thoughts on Rust, a few thousand lines in

#71
post #48

let foo = "..."; let foo = parse(foo); let foo = escaped(foo); ... doSomethingWith(foo); I don't see how this is helpful for avoiding the bug described. The most common bug with this type of code is mistaking which form "foo" represents at a given line of code, or that form changing as the code evolves. For example, if one programmer writes let foo = "..."; let foo = parse(foo); ... doBarWithFoo(foo); and another pro…

In your particular example, the ownership system would help here, since `foo` is consumed by `doBazWithFoo`. (Only exception is when `foo` is `Copy`.)

Re: Thoughts on Rust, a few thousand lines in

#72
post #48

let foo = "..."; let foo = parse(foo); let foo = escaped(foo); ... doSomethingWith(foo); I don't see how this is helpful for avoiding the bug described. The most common bug with this type of code is mistaking which form "foo" represents at a given line of code, or that form changing as the code evolves. For example, if one programmer writes let foo = "..."; let foo = parse(foo); ... doBarWithFoo(foo); and another pro…

I believe the way this is solved is by having the type of escaped(foo) different than that of parse(foo) and only accepting a EscapedString in doBaz and an ParsedString in doBar.

Your type structure at no extra runtime cost is String : ParsedString : EscapedString.

This ensures you don't escape strings before parsing them too. Nice!

Re: Thoughts on Rust, a few thousand lines in

#73
post #31

Earlier quoted context omitted.

String slicing using byte indices has to exist in some form, since it is the only thing that is efficient (O(1)). But, I guess it could have used syntax other than somestring[...].

It could slice on bytes and return a slice of bytes since the String type is a wrapper over Vec .

That means one loses all the conveniences and guarantees of the string types and, in many cases, forces an immediate revalidation the byte slice as UTF-8 to get back to &str, which is O(n). Furthermore, this is also rather clunky.

I suppose one could have it return StrWithInvalidSurrounds, where just the first (at most) 3 and last (at most) 3 bytes might be invalid, which would then allow for O(1) revalidation to a &str, and even other operations like continuing to slice... But this is even more clunky for actual use!

I think a moderately less clunky API might have been to not use integers for byte indexing, but instead some ByteIndex wrapper type that string operations return, meaning one can't just write `s[..5]` in an attempt to get the first 5 characters of the string.

(Also, there's str::get that returns an Option: https://doc.rust-lang.org/std/primitive.str.html#method.get )

Re: Thoughts on Rust, a few thousand lines in

#74

> the escape hatch suggested on the internet, `partial_cmp(...).unwrap_or(Ordering::Less)` This is often a Bad Idea, as you get unstable sorts and you are right back to the same problem. - Explanation: How do I get the minimum or maximum value of an iterator containing floating point numbers? — https://stackoverflow.com/a/50308360/155423 - Example: https://play.integer32.com/?version=stable&mode=debug&editio... See a…

To me this feels quite pedantic. Being able to do less than on NaNs and just having it do something vaguely sensible (as in your linked solution) is a far more common requirement than need to handle NaNs specially. You could even say the reason NaN exists is so that you don't have to check for NaN constantly. Rust is being technically correct but practically really annoying, for basically no benefit.

For what it's worth, many in the Rust community agree with you. Many people consider this a mistake, in hindsight, though not everyone.

Re: Thoughts on Rust, a few thousand lines in

#75
post #63

Earlier quoted context omitted.

It's not clear to me what you're suggesting; is it that String shouldn't have supported indexing in the first place? That code does work, but you have a &[u8] not a &str.

But neither AsciiString. It has a as_str method, but it's still a kludge. This example was basically a suggestion to throw0u1t: if they want to cut in the middle of the utf-sequence for whatever reason, they can [edit:] do it without extra crates. What I don't understand is why slices are indexed in bytes and not in objects. If String has an ability to check that we're cutting in the middle of the character sequence,…

I think the rust designers want to keep the implicit contract that indexing into a string is fast and O(1).

If you want to find the one millionth codepoint of a UTF8-encoded string, you have to more or less (1) visit every byte of the string.

If, on the other hand, you want to find the codepoint that covers the millionth byte, on the other hand, you have to read at most four bytes (read the millionth byte, and there are three cases:

- it’s a full codepoint. If so, you‘re done.

- it is the first byte of a multi-byte codepoint. If so, read forwards in the string for up to 3 continuation characters.

- it is a continuation character. If so, search backwards in the string for the first byte, then, if necessary, read forwards to find more continuation characters.

So, that is O(1)

(1) you can skip continuation characters, but these typically are rare.

Re: Thoughts on Rust, a few thousand lines in

#76

One thing I don't like about Rust is how taking a slice of a string can cause a runtime panic if the start or end of the slice ends up intersecting a multi-byte UTF-8 char. I would prefer it if this feature didn't exist at all rather than cause runtime panics. https://play.rust-lang.org/?gist=e02ce5e9aacfee3a2b4917d5624...

It is a common pattern in Rust to use [] for things that cannot fail and will panic otherwise and a method for things that can fail and return Option or Result. e.g. my_hashmap["foo"] will panic at runtime if the key "foo" is not present, or return the associated value if it is. But my_hashmap.get("foo") will return None if "foo" is not present and Some(value) if it is.

What's the point of the [] version then? It seems inherently more dangerous, and Rust emphasizes safety. I know it wants to be pragmatic as well as safe, but this seems like a strange default.

Re: Thoughts on Rust, a few thousand lines in

#77
Great job. Just a nit/request for that gif illustrating agrind's use -- I keep watching it to see what args you've passed to see how it's being used but the output finishes and loops before I understand what I'm seeing. Not sure if it's a property of the image or my browser but if you can turn off the looping in the image that might work better. Or add static frames at the end for the slow folks like me ;)

Re: Thoughts on Rust, a few thousand lines in

#78

Earlier quoted context omitted.

It is a common pattern in Rust to use [] for things that cannot fail and will panic otherwise and a method for things that can fail and return Option or Result. e.g. my_hashmap["foo"] will panic at runtime if the key "foo" is not present, or return the associated value if it is. But my_hashmap.get("foo") will return None if "foo" is not present and Some(value) if it is.

What's the point of the [] version then? It seems inherently more dangerous, and Rust emphasizes safety. I know it wants to be pragmatic as well as safe, but this seems like a strange default.

There's a few things that come into play here:

First of all, panics are perfectly safe. None of this has to do with safety guarantees.

Second, the [] syntax is controlled by the Index trait, which returns an &T, not an Option. It does this due to Rust's error handling philosophy. There's two kinds of errors: recoverable and unrecoverable errors. When something shouldn't fail, unless there's a bug, you shouldn't be using Option/Result, you should panic. When something may normally fail, and you want to be able to handle that explicitly, you should use Option/Result.

If [] always returned an Option, you'd be seeing tons and tons and tons of unwraps. It's not the right default here. However, that's why the .get method also exists: If you do think that this may fail, but not due to a bug, then you should use .get instead, which does give you an option.

TL;DR: everything is tradeoffs, and we picked a specific set of them, and that's how they all play out together.

Personal commentary: this is the kind of thing that's largely concerning until you actually use the language more, IMHO. Dealing with Options all the time here would feel really bad. Consider the other sub-thread about floats; it often feels like boilerplate for no good reason. That would introduce this for every single time you want to index something, which is a very common operation.

Re: Thoughts on Rust, a few thousand lines in

#79
post #56

Earlier quoted context omitted.

I think he's suggesting that slicing on strings should be by character, and if you want to slice on bytes, you should explicitly ask to treat the string as a byte array. It makes more sense semantically, and it's safe.

Slicing on characters is a linear time operation and indexing is meant to be cheap.

[deleted]

Re: Thoughts on Rust, a few thousand lines in

#80

Earlier quoted context omitted.

Does this bug exist because it would be too expensive to check every string before slicing? (Being Rust-ignorant), can you not type a binary as UTF-8? Are there 2 versions of string functions, fast ones that assume ASCII and slow ones that assume UTF-8?

Every string is checked. But UTF8 is a multi-byte encoding, and slicing works per bytes, so you if you slice in the middle of a multi-byte character, you may get nonsense. The error happens because of this checking, not in spite of it. String always assumes full UTF-8. You could make an AsciiString type if you wanted, but it's not provided by the standard library.

The obvious follow up question would be: so why is slicing a string a byte-wise operation and not a character-wise operation? If a string is an array of characters, why does it let me refer to individual bytes without explicitly casting it to a byte array? How often comparatively do you want the nth byte compared to the nth character? I would suspect that's pretty rare.
Post reply on HN