Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

In C++ if the string is a rvalue reference you could std::move it into part of the return value. Think a signature like

    template<typename T>
    std::pair<std::string, std::vector<std::string_view>>
    tokenize_string(T &&str);
This would be efficient when the user passes a temporary, and it would be safe.

Which isn't to say the Rust solution isn't totally cool. Being able to easily check this class of errors at compile time is probably a lot nicer than needing to learn all the relatively complicated parts that would go into a easy to use / safe /efficient / still slightly weird C++ solution.



Sure, and then somewhere along the way you throw away the first element of the pair, because you're not using it, but you're still using the views, and oops you just reintroduced the bug you tried to fix.

Which is to say, yes, you can obviously write C++ code that works. But you run the risk that one tiny mistake, or a change weeks, months, or years later, causes memory issues. Being able to completely rule out this class of error at compile-time is really amazingly useful.


Yes I agree completely. I was thinking about that after I wrote my comment, the code is only safe relative to the original sample, and it's only a band-aid for the lack of more comprehensive lifetime guarantees.

Of course you can jump through more hoops, by encapsulating the string, string_view data in a proper class. But when there's tradeoffs between safety and convenience, there's a point where people will understandingly choose convenience.


That's a forest for the trees argument. The ability to introduce bugs ("make a tiny mistake") in future changes is an inherent property of software, and you can't fix this in the general case. Rust just fixes this for the case of free-memory-read bugs. That has value, but it's a much more limited scope than you're implying.

Really I think this is the biggest problem with Rust. The stuff broken about C++ isn't really its memory model, it's simply its complexity. And every time I look at what's happening in Rust I see the same kind of complexity being introduced at every turn. I mean seriously: "named lifetime parameters"? And the syntax is a bare single quote? That's a joke, right? No one but Rust nerds is going to grok this, and real code needs to me maintained by mediocrities.

Frankly Go seems to have this "don't introduce new nonsense" problem under much better control, so if I need to pick a horse in the race, it's that one, not Rust.


Rust prevents significantly more than reading freed memory, it is designed to make all memory safety problems (dereferencing an invalid pointer, reading freed memory, data races, ...) impossible without explicitly opting in.

Memory safety bugs are particularly bad bugs, as they represent a program that is completely off the hooks, allowing an attacker to take control of the program/computer by inserting shell code or to read private keys directly out of memory (for example). Even if you're not in a situation with aggressors, memory safety problems can lead to the program scribbling all over memory resulting in random crashes and misbehaviour, and these are so hard to diagnose since there's spooky action at a distance, and they can easily be timing sensitive/heisenbugs.

The memory model of C/C++ is definitely broken, look at all the security flaws in programs in those languages.

> Frankly Go seems to have this "don't introduce new nonsense" problem under much better control, so if I need to pick a horse in the race, it's that one, not Rust.

If you're doing something were Go is the appropriate tool for the job, that's sensible... but, if you're trying to write a library to be called from other languages, or run on embedded devices, or have precise control over memory layout (including the heap), languages like C, C++ and Rust will likely be much easier.


This comment is a joke, right? I find it hard to believe that any programmer would say "the compiler prevents me from writing broken code? That's too complex!"

Yes, a proper typing system involves more visible moving parts than a broken typing system. But a proper typing system is vastly more powerful. C++ may not have lifetimes, but every time I touch C++ I have to be really careful that I don't accidentally introduce memory or threading bugs, because they're both really easy to do. Someone who's programmed C++ for a long time might not even realize it, but then again, the vast majority of C++ code in this world almost certainly contains numerous memory and threading bugs.

And why the comparison to Go? Go doesn't live in the same world as Rust. It's not a systems programming language. At this point it's mostly a glorified web server application language. And if you're going to pick Go because of the lack of memory lifetime issues, you may as well pick any other garbage-collected language out there.


Again, forest for the trees. Your laser focus on one particular type of bug blinds you to the fact that complex systems lead to bugs in general. I'm not interested in defending C++ (or Go, or anything else). I'm saying I see Rust falling down the same "cool new ideas" rabbit hole as C++, and Haskell, and Erlang, and Common Lisp, and... Of those languages only one has achieved any notable success.

And btw: the idea of calling something a "systems programming language" that can't even make a system call is laughable. Can I mmap a buffer to pass to a hardware video codec or make an ioctl to an audio driver in rust? Guess which language I can do that in? If "Go doesn't live in the same world as Rust", then Rust isn't in the same galaxy as C/C++.


Rust has inline asm support, so system calls are easy and efficient, e.g. http://mainisusuallyafunction.blogspot.com/2014/09/raw-syste... .

If you quibble that it's not in the standard library, note that we are talking about the actual languages here, not their standard libraries (that crate could easily be pulled into the official distribution if it was deemed sensible to do so).


> Your laser focus on one particular type of bug blinds you to the fact that complex systems lead to bugs in general.

Therefore it is clearly in your interest to use languages that remove various classes of bugs. No language claims to be able to prevent bugs. But if your compiler can prevent you from making silly mistakes, that's a win.

> I'm saying I see Rust falling down the same "cool new ideas" rabbit hole as C++, and Haskell, and Erlang, and Common Lisp, and... Of those languages only one has achieved any notable success.

What bizarre argument that is. Haskell is a research language, what else could it be but be about "cool new ideas"? And it does effectively remove different classes of bugs, though like most functional languages, it's a managed language, and thus not terribly suitable for low-level programming. Erlang was designed to solve a certain class of problems, and it clearly solves these issues better than C++. Not everything and everybody needs to solve low-level issues or use inline assembly.

Rust can use unsafe code (guarded by unsafe blocks), but this code has to expose a sane interface. So you can do pointer trickery that is otherwise impossible, but instead of having an entirely unsafe program, locations with dangerous code are clearly outlined.


I don't know where you got the idea that you can't mmap a buffer or call an ioctl in Rust. You certainly can do those things.


I got the idea from the docs, honestly, which don't talk about system interfacing at all. Though I do now see the "unsafe" page, which at least has assembly hooks.

Serious question though: has anyone ever done this? I mean, are there kernel header import utilities I can use to get the flag definitions and parameter structs, etc...? You can sneer and downvote me all you want, but it seems that the clear truth is that Rust has not been used as a "systems programming language" in the only regime where IMHO that term has any meaning.

Basically: drilling a hole through the compiler to the assembler (which I'll state again is done in Rust as yet more complicated syntax users need to learn and not as, say, a native library interface) is a valuable tool, but it does not a syscall interface make.


There is rust-bindgen, which you can use to convert C headers to Rust FFI declarations. This should be able to convert the kernel userland headers to Rust declarations, so that you can call directly to the kernel.

(I didn't downvote you.)


> Rust has not been used as a "systems programming language" in the only regime where IMHO that term has any meaning.

Rust has been used to make a toy kernel (as in press key, get message printed and/or change the color of the message). And this was several months ago. I'm pretty sure that makes it a decent systems programming language.


The Rust language provides the tools required for people to write a system call interface (which can be in the standard distribution or outside it, both have the same power), I don't think building such a thing into the language (rather than in a library) is at all sensible.

As others have pointed out people have written linux kernel modules, kernels and all sorts of other low-level things in Rust.

(Rust's inline assembly interface is essentially "write in ASM"... If you're truly needing to go that far down yourself, then knowing assembly seems very reasonable. However, this shouldn't be needed much, just use libraries that do it internally.)


People are writing kernels in Rust. If that doesn't qualify as systems programming language, I don't know what does.


> And btw: the idea of calling something a "systems programming language" that can't even make a system call is laughable.

So C and C++ are laughable for systems programming, because the language standard doesn't cover system calls.

The APIs for systems calls and support for inline assembly are language extensions.


That we can't fix all bugs doesn't mean we shouldn't take steps to fix as many as we reasonably can.

Your argument applies equally well to sandboxing, for example--why go to all the trouble to lock down a complicated Windows sandbox if installing malicious software is only one kind of security vulnerability? The amount of subtlety in a Windows sandbox is incredible (all it takes is one leaked privileged file handle), and there are plenty of ways that security vulnerabilities can happen that aren't thwarted by a sandbox. But nobody is arguing that sandboxing is pointless, because it massively improves security.


"No one but Rust nerds is going to grok this"

This is the first rust code I've looked at, and I grok this. As someone currently doing C dev in my day job, and who's done a lot of C++ historically, ability to enforce lifetimes sounds outstanding - particularly as it probably combines marvelously with RAII.


It does combine marvelously with RAII, you're absolutely right! For example, the Rust Mutex class contains the data it's protecting, and it returns a RAII object when you take the lock. This RAII object provides mutable access to the contained data, and it uses lifetimes to a) prevent you from keeping a reference to the data after unlocking, and b) prevent the RAII object itself from outliving the Mutex.

This would wonderfully, and it means it's impossible to bypass the lock. Which is something I really wish I had in other languages; just a few days ago I finally fixed a subtle intermittent crash in a C++ program that was caused by taking the wrong lock when touching shared state.


s/This would wonderfully/This works wonderfully/


As a mediocrity, I think you are making a big fuss about it.

Yes. Lifetimes are hard. Yes, it requires lots of compiler wrestling. However Rust compiler gives pretty good hints what lifetimes should be added and deduces lifetimes in few simple cases. Additionally you can opt out if if you are willing to allocate more memory.


Actually, it should be written more like this:

    template<typename T>
    std::pair<T, std::vector<std::string_view>>
    tokenize_string(T &&str);
So then it uses `std::forward` to conditionally move the string for rvalues, and `T` will be a reference to the original string for lvalues.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: