3 ms·
GP made a great point and I get the impression you're fighting really hard to ignore reality. Idealistic thinking doesn't win the practical exams. Zero-terminat
by jstimpfle 4y ago
GP made a great point and I get the impression you're fighting really hard to ignore reality. Idealistic thinking doesn't win the practical exams. Zero-terminated strings are a fact of life and essential to using many useful APIs. Like it or not, if a new ecosystem wants adoption it had better interoperate with the established ones without much friction.
Apart from that, zero-terminated strings aren't strictly bad. They offer an in-band signal that is sometimes very practical. Slices are more generally flexible, especially w.r.t substrings, but when you look at a memory dump for example it's great to have those terminators.
> once you're not talking directly to the kernel ABI you're free to choose abstractions which better suit both sides.
Requiring string copies just to reshape arguments according to idealistic beliefs is a huge yak shave. It means creating all those wrappers, handling all those extra failure modes, and coming up with extra versions of records (often on-disk structures) that have fixed size zero-terminated string buffers embedded.
- tialaramex 4y agoI've been on both sides of this fence, decades writing C before I wrote any Rust - and no, IMNSHO the Yak barbering necessary is much more extensive and annoying with zero terminated strings. The on-disk fixed size structure stuff is actually nicer in a language that favours slices, because with C-strings we're incurring a special case, what happens when the sub-structure is full? With slices that's just fine, but with zero termination that's not a valid string (because the sentinel is missing) and so you have to decide what to do about that.
- jstimpfle 4y ago> so you have to decide what to do about that No, you need to do what needs to be done according to the on-disk format. The disk doesn't care what you think is the ideal string representation. If the available space is used up, it is used up. That's just the semantics that come with the physical reality of existing systems where you can't just malloc an extra space on the heap. Having an internal representation that matches what's on the disk is the right call, everything else is only layering complexity. Also, you're making it look like it was hard to use, but those semantics are very easy to program against, using something like snprintf(buffer, sizeof buffer, "%s", ...), or just do it manually.
- tialaramex 4y agoMaybe the problem you've got is that you actually haven't understood what the alternative you don't like even is in practice ? // Assuming buffer is a mut [u8] and text is the text value we'd like to write into it // if we've got some string, just let text = string.as_bytes(); if text.len() > buffer.len() { // As with snprintf we need to decide what to do if it won't all fit // ... for example let's just truncate it let truncated = &text[..buffer.len()]; buffer.copy_from_slice(truncated); } else { let (left, _) = buffer.split_at_mut(text.len()); left.copy_from_slice(&text); } As I thought I'd explained, the yak shaving problems for your C-style strings are on the other side, reading this structure. With pointer + length strings this is no trouble but with a 0-terminated string you have to conjure that sentinel from somewhere, maybe allocating in the process. Slower and uglier.