3 ms·
Are you able to explain the problem a little more because “const” does exist as a keyword, so I assume it’s doing something different to what you’re referring t
by hnlmorg 1y ago
Are you able to explain the problem a little more because “const” does exist as a keyword, so I assume it’s doing something different to what you’re referring to with regards to C++ constants. Is Go not substituting constants like a macro? Or are we discussing something entirely different and I’m misunderstanding the context here?
- kentm 1y agoI’m assuming they mean const function/method parameters. Being able to mark inputs to functions as const to guarantee that they aren’t mutated in C++ which often means you can just pass in the value by reference safely.
- jerf 1y agoJava, Go, and C++ all have enough differences here that at this level of detail you shouldn't assume any other conversion will have exactly the same result that msteffen lays out. Java generally has more sophisticated compilation and a lot more engineering effort poured into it, but Go often ends up with less indirection in the first place and started life with what Java calls records [1] so they are more pervasive throughout the ecosystem. Which effect "wins" can be difficult to guess in advance without either a deep analysis of the code, or just trying it. What msteffen talks about is a general principle that you can expect even small differences between languages to sometimes have significant impact on code. I think this is also one of the reasons Rust libraries tend to come out so fast. They're very good at not copying things, but doing it safely without having to make "just in case" copies. It's hard to ever see a benchmark in which this particular effect makes Rust come out faster than any other language, because in the natural process of optimizing any particular benchmark for a non-Rust language, the benchmark will naturally not involve taking random copies "just in case", but this can have a significant impact on all that real code out in the real world not written for benchmarking. Casually written Rust can safely not make lots of copies, casually written code in almost anything else will probably have a lot more copying than the programmer realizes. [1]: https://blogs.oracle.com/javamagazine/post/records-come-to-java https://blogs.oracle.com/javamagazine/post/records-come-to-j...
- hnlmorg 1y agoAhhh right that makes a lot more sense. Thanks for the explanation
- wolfspaw 1y agogreat comment! And you're right, one of the biggest Strengths of Rust is Move done right. With const, borrow, move, ref rules... the default way usually does not make unnecessary copies. And when you want to make a copy, to escape lifetime annoyances for example, you do a .clone() that very explicit marks a point of a Copy.
- masklinn 1y agoThey mean const in the sense of readonly guarantees. In java types are generally shared and mutable so let's say you want a list input, you generally don't store it as is because the caller could modify it at any point, so if you accept a `List`, you defensively copy it into an inner type for safety, which has a cost (even more so if you also need to defensively copy the list contents). And likewise on output otherwise the caller could downcast and modify (in that specific case you could wrap it in an unmodifiableList, but not all types have an unmodifiable view available).
- msteffen 1y agoSorry for the slow reply here, but in Java, “final” variables can’t be updated to reference a different object, but the underlying object can be modified with method calls (e.g. you can append things to a “final” ArrayList, whereas in C++ you can’t append to a const vector. In C++, you mark methods const to indicate that they don’t mutate the underlying object, and only cost methods can be called on const variables). The Guava docs give an example of the defensive copying: https://github.com/google/guava/wiki/ImmutableCollectionsExplained https://github.com/google/guava/wiki/ImmutableCollectionsExp.... Any time an Immutable collection is created from another collection, the elements are deep-copied to avoid the possibility that they’re modified elsewhere, even if there’s no possibility of that happening. Even if you’re using e.g. an ImmutableList.Builder, the elements are copied when they’re Add()ed to the Builder, so that they’re the same when you call build(). I’m not sure but I think even some mutable collections make defensive copies of their arguments. I believe that Josh Bloch (who was in charge of Java at Google when I joined) also advocates for this in his book. On writing this, it occurs to me that some kind of move constructor into these mutable collections might also do the job? Though you’d have to make sure there were no mutating references outside the mutable collection as well, which might require some kind of ownership model, so you might just wind up with Rust. Finally, this is dumb but it’s killing me: I meant to type 400qps to 1200qps/core.