Hacker News new | past | comments | ask | show | jobs | submit login

I am talking about the actual conversion of an unowned object to an owned object, which as nearly as I can tell involves copying the object? Implicitly? All the time?



Well, it's not implicit. It's explicit both inside the function body (".into()") and in the function signature (where "into" alerts the user that something may be going on). You can also avoid the copy by just supplying String in the first place, in which case it gets moved (avoiding the allocation), not copied.


I see. Having to say .into() makes me feel a little better about it. But it does make it clear there is a runtime performance cost to insisting on a strict ownership model.


If the API has to hang onto the string, sure. But not all APIs have to do that. The only reason why the Elasticsearch API requires owned strings in this case is that the JSON API does, and this is a trait that many JSON APIs share, regardless of language. (For example, the first Google result for "c json api" pulls up this API [1], which also copies strings.)

You could write a JSON API that doesn't insist on a strict ownership model, if you wanted. There is even a type, MaybeOwned [2], in the standard library to support this kind of API. In such a library, the JSON type would have a lifetime parameter, which could be 'static for owned strings, but which could be non-static for JSON types that contain references to strings.

[1]: https://jansson.readthedocs.org/en/2.7/apiref.html#string

[2]: http://doc.rust-lang.org/0.11.0/collections/str/type.MaybeOw...


Incidentally, MaybeOwned is now written `Cow<str>`. http://doc.rust-lang.org/std/borrow/enum.Cow.html


The only runtime performance cost here is one you would need regardless for correctness- you only need to copy if you're going to hold onto the data longer than a borrow would allow.

In fact, Rust's semantics allows a fewer number of copies than naive use of std::string, since an already-owned value won't be copied, as mentioned above.


I don't see what you mean. Borrowed pointers (and `AsRef`) work fine in Rust.

In fact, Rust's borrowing model provides some perf gains easily where it would be hard to do so in C++ (http://manishearth.github.io/blog/2015/05/03/where-rust-real...)


I would be really interested in hearing you elaborate on specifics here, possibly even with code.

(Also, I can't wait until I can download Jai and give it a go, keep putting out videos.)


Well, keeping in mind that I don't know much of the specifics of Rust, and am just making a guess at what it's like to use, this is what I mean:

Actually predicting where data is really going to go involves solving the halting problem. So by necessity any static analysis of ownership is going to be conservative, in the sense that it has to err on the side of safety.

So there's a process of structuring things so that it's not just the programmer who understands, but the compiler who understands. Structuring the code in alternative ways so that ownership is made clear and/or ambiguous cases are resolved. Sometimes this could be a small amount of work, but sometimes it could be a very large amount of work (analogous to the simpler situation in C++ where you are using const everywhere but need to change something deep down in the call tree and now either everyone has to lose their consts or you have to do unsavory things).

At points, it might be possible to structure things so that the compiler would understand them and let you do it, but it would take a large amount of refactoring that one doesn't want to do right now (especially if one has had a few experiences of starting that refactor and having it fail), so instead one might punt and just say "this parameter is owned, problem solved". And that's great, you can stop refactoring, but you just took a performance hit.

Now, in some cases it is probably the case that this is in reality an ambiguous and dangerous ownership situation and the language just did you a favor. But there are also going to be cases where it's not a favor, it's just the understanding of ownership being conservative (because it has to be), and therefore diverging from reality. But I want to get work done today so I make the parameter owned, now the compiler is happy, but there is a performance cost there. If I were not so eager on getting work done today, I might be able to avoid this performance hit by wrestling with the factoring. But I might deem the cost of that prohibitive.

That's all I mean. But like I said, I have never written a large program in Rust so I am not speaking from experience.


(And really my point is that I perceive there is an ambient pressure toward copying function parameters in general in order to minimize refactoring ... which is what I mean by there being an overall performance impact).


Thanks for elaborating, this was really helpful.

I don't know if I agree, per se, but I will say that Rust is still in such early stages that we'll be seeing how it shakes out as more people work with Rust. I haven't found this personally to be an issue, but I've also been doing Rust so long that it's hard to see things from a fresh perspective, you know?


I don't think there is. It's quite common to use references as usual, and unnecessary param copying happens pretty rarely in most Rust code.


I think there is, honestly—the JSON API is a legitimate example of that—but I think it's no worse in Rust than in C, where equivalent pressure already exists.


Invoking The Halting Problem is a pretty big sledge hammer. Especially for a language that you claim you don't know much (of the specifics) about. And your argument is so broad and without specifics that it just boils down to "expressing things in such a way that the compiler believes you", with no mention of Rust except that it might cost some performance if you are not able to communicate this. But how hard will it really be to communicate? All semantic properties are not created equal across languages -- some languages make a set of them easy to check in all realistic cases, others very hard or impractical.

For instance, there is definitely a concrete conversation to be had about the ownership model and implementing data structures -- you even have to use `unsafe {}` for implementing something as simple as a doubly linked list[1]. So that's a concrete example of how single-ownership makes something conceptually simple and safe hard to express in safe code. But in this case, there is so much vagueness about the supposed "massive performance implications" (HP + laziness = massively inefficient) that it comes off as trying a bit hard to... let's just say "to be negative".

> (And really my point is that I perceive there is an ambient pressure toward copying function parameters in general in order to minimize refactoring ... which is what I mean by there being an overall performance impact).

Well admittedly this argument is more concrete.

[1] But that's just a burden for the implementer, since you can expose a safe interface to the data structure.


This is a waste of time. I am out of here.


I don't see what you mean. Borrowed poitners (and


Rust also has the AsRef<T> trait, which converts to a reference, hopefully without copying. Functions which do not need to take ownership of the object should take an AsRef<T> instead of an Into<T>.


Only if the user is providing borrowed strings in the first place, in which case, there's not much choice. If the user can provide an owned string, it'll just use that, no copy.


That's no different from having a C++ function that takes a std::string, or overloads for const std::string& and std::string&&, instead of only accepting one. Only you have to go out of your way to have Into<String> to do it. And we're talking about an API to make queries to send remotely.


Overloading doesn't scale when there are tons of ways of making a `String`. I don't see why `Into<String>` is "out of your way"; it's actually less verbose than overloading.


Into<String> is "out of your way" compared to having a String parameter in Rust. (Thus the person writing the code is expressly asking for the interface to allow implicit copying.) It is not being compared to C++ overloading. (The point is, this is more "out of your way" than you have to go in C++, where using an unoverloaded argument type of std::string will get you copying with opportunistic moving, and where a const std::string& will get you copying somewhere on the inside of the function. Thus Rust protects you from accidental expensive copies.)


Yeah, and this is one of the many reasons why performance programmers usually do not touch std::string.


Yeah, they might want some sort of string type that you can't implicitly copy, like Rust's.


Rust's String does not implement Copy. &str does. (That means Strings aren't ever implicitly copied.)


That's what I said.


Ah, now that you say that, I see that my brain produced a _very_ poor parse. Sorry :(


I was speaking in TI-85 and you were reading in TI-83 :)




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

Search: