8 ms·
I love the concept of editions. I haven't anything like it in other languages. Having the ability to have one project made up of crates of many different edit
by stusmall 5y ago
I love the concept of editions. I haven't anything like it in other languages. Having the ability to have one project made up of crates of many different editions is brilliant. It makes breaking language changes that would otherwise be a nonstarter become minor and easy to manage. Love it
- xamolxix 5y ago> I haven't anything like it in other languages Is that different from compiling one lib with --std=c++11 and another with --std=c++17?
- EdSchouten 5y agoYes, in that in C++ it would break if one library used a modern language feature as part of its public header files.
- chc 5y agoSurely the difference there is that Rust doesn't have header files.
- masklinn 5y agoNot necessarily, you could imagine a system where the header file specifies its edition.
- cpeterso 5y agoA header file can check #if __STDC_VERSION__ or __cplusplus versions to make some code conditionally available for, say, C11 or C++11. #if __STDC_VERSION__ >= 201112L // C11 feature #endif #if __cplusplus >= 201103L // C++11 feature #endif
- dralley 5y agoBut don't header files generally get concatenated together due to the way "dumb" textual includes work?
- deleted 5y ago[deleted]
- hiccuphippo 5y agoCan't you compile libraries to object files independently with whatever version of c++ they require and then link them together?
- tialaramex 5y agoYes. If the only value the library brings to you is that it generates a particular object file, you can divorce that object file from your chosen language version entirely. If you have libraries that you don't care if they're C or Pascal or a Lisp implemented in raw machine code, then this works just fine and you needn't care about Rust's editions feature. Rust will also cheerfully consume these libraries although of course everything about them is by definition Unsafe in Rust terms. But most people want their C++ libraries to deliver a bit more than "Here is some machine code, and here are some symbol names that map to the machine code or to raw binary data". Like maybe they want to be able to implement an Interface the library describes, or they want to use a Concept the library names. You can't do those things using language-independent object files. Rust library A, from edition 2021 can implement a Trait from library B (edition 2018) on its thin wrapper of a type from library C (edition 2015) and then you can consume the resulting type, with its trait implementation, from your Rust 2018 program.
- MaulingMonkey 5y agoThe problem is a C++ library's headers must be compiled with the settings, context, and flags of every downstream thing that depends on them, rather than separately. Which isn't such a big problem if your C++ library exposes a minimal C-like API from it's headers, with most of the meat of the library hidden away in source files, but might be a very big problem if your C++ library is a miserable little pile of ~~secrets~~ templates, a la boost.
- int_19h 5y agoYou'd still need the header that describes the public interface of such a separately compiled object file. Also, this doesn't work with templates, and modern idiomatic C++ tends to be template-heavy.
- heftig 5y agoIf the application is using C++17, wouldn't the headers of the C++11 lib then be compiled as C++17, potentially breaking things? PS: The other way around is more obviously broken, with the C++17 lib headers getting compiled using C++11.
- pjmlp 5y agoOr you make use of the preprocessor or if constexpr, and then have the specific code for each language version.
- int_19h 5y agoThe maintainers would have to do it for every new language version that breaks them, though. The edition system keeps old stuff working without any effort.
- pjmlp 5y agoI don't want to start this discussion thread yet again, but I am a firm believer that edition system only appears to work right now because: 1 - Rust is still quite young and doesn't have 30 years of accumulated editions 2 - There is still only one major Rust compiler 3 - Editions are designed only to work when compiling the whole project, including 3rd party dependencies, from source code within a single build 4 - So far the editions don't have semantic breaking changes across editions, where behaviour changes across the edition border 5 - There is no plan to ever have editions work across ABIs So "The edition system keeps old stuff working without any effort." might not be true when Rust achieves an adoption scale similar to C and C++, in about 20 years, with several accumulated editions, and a couple of compilers in use. I might be proven wrong, but that is how I see it today.
- tialaramex 5y ago> 1 - Rust is still quite young and doesn't have 30 years of accumulated editions Rust 1.0 was six years ago. When do we start the clock on six years of C++ evolving while also having "old stuff working without any effort" ? C++ 98 to C++ 03 was five years, and that introduces almost no features at all. C++ 11 was eight years later but it's notoriously incompatible to prior versions of C++. C++ 14 is only three years, C++ 17 has breaking changes, as does C++ 20... I think C++ 20 should have taken Epochs (yes even at considerable cost to other new features like Concepts) for this reason. I think ten years from now even if Rust has found it can't achieve everything it wants to via editions, this feature will be generally considered to be a good idea, like generics or string literals. Something you need a specific rationale for not including in your general purpose language. I might be proven wrong too about how far this can go, but I feel like the Rust 2018 and 2021 editions already prove the value of the idea.
- orra 5y agoI don't know what guarantees your typical C++ compiler gives you that those can link together? Regardless, at the very least, you would need to write the headers to be interoperable.
- masklinn 5y agoAside from the header issue, it doesn't allow for or support backwards-incompatible changes. Because editions are opt-in (and library-level source metadata) the language itself can be modified in non-backwards-compatible ways. So for instance a C++ with editions could make ctors `explicit` by default, or it could entirely change the automatic member generation (by removing it for instance). As long as the ABI and API remain compatible, that's fine.
- neandrake 5y agoIt’s probably worth noting that the backwards compatibility breaking changes I think only applies to the language and not the standard library. I’m unable to look up the details right now but I believe there’s a trait function defined in stdlib which is deprecated, supersede, but can’t be removed even as part of an Edition, or it would break older code.
- masklinn 5y agoThat is correct, editions are mostly about language-level syntactic changes, the APIs have to be compatible between editions. The only place where that isn't the case is the standard prelude (the "builtins" you don't have to import).
- tialaramex 5y agoThe ability to replace the prelude does mean that you can imagine if somebody invents a much better thing than, say, Rust's iterators Rust 2050 can have a prelude that brings in std::better::Iterator instead of std::iter::Iterator and then most coders will end up using the new better iterators, just because that's the kind you get out of the box. Anybody who literally refers to std::iter::Iterator gets the old ones of course as does any library code from prior editions, but the documentation could lead those few people in the right direction. And presumably std::better::Iterator politely implements std::iter::IntoIterator because why not. I would be interested to understand if they're allowed to replace the macros. The standard macros aren't actually from the prelude, but instead if you aren't no_std you get all the standard macros anyway. Are they allowed to change those in a future edition? Or not?
- pornel 5y agoYes, because C versions are frozen in time, and editions aren't. Today Rust added brand new features to Rust 2015 and Rust 2018, and will continue to expand them forever (every new feature lands in all editions whenever possible). Rust editions are closer to source code parsing modes. More like enabling trigraphs in C or "use strict" in JS. Additionally, textual header inclusion in C makes mixing versions tricky. Rust has properly isolated crates, and tracks edition per AST node (so that even cross-crate macros work correctly with mixed editions).
- alerighi 5y agoC compilers usually backport features in older standards as well (I know, they are breaking the standard). One example are C++ style comments, that are in the standard only from C99, but basically every compiler supports them even in ANSI/C90 mode. By the way the difference is that Rust is not a standard, thus is easier to evolve (the process is much shorter). On the other side, the fact that a language changes slowly it's something good in a way, it means that you don't have to continue to change the way you do things, and update older projects. That to everyone that has to maintain code for decades it's important. And every serious software project (not hobby stuff) does stay in production decades really. I don't use Rust, or even C++, for that reason.
- nicoburns 5y ago> On the other side, the fact that a language changes slowly it's something good in a way, it means that you don't have to continue to change the way you do things, and update older projects. Isn’t the point of Rust editions that this is also true for Rust? Don’t want to update to a new edition? Then… don’t. The old ones are maintained.
- lfairy 5y ago> By the way the difference is that Rust is not a standard, thus is easier to evolve (the process is much shorter). Another thing is ABI. C and C++ are ABI-stable, which means that many historic mistakes (intmax_t, std::regex, polymorphic allocators) are impossible to fix. Rust only promises source compatibility, not ABI compatibility, so it has a lot more freedom to tweak its design. https://thephd.dev/binary-banshees-digital-demons-abi-c-c++-help-me-god-please https://thephd.dev/binary-banshees-digital-demons-abi-c-c++-...
- emteycz 5y agoES(year) for JavaScript
- RussianCow 5y agoNewer versions of JavaScript do not break compatibility with older versions, whereas different editions of Rust break compatibility in various ways while still allowing interoperability between libraries written in different editions. That makes the two approaches very different.
- nicoburns 5y agoA better JavaScript example would be strict mode, which is opt-in with "use strict" and changes quite a bit of the semantics of the code while being completely interoperable with non-strict JS code.
- Macha 5y agoYeah, and the "use" statements for this came from Perl which is probably the originator of this pattern here.
- steveklabnik 5y agoWhile there's nothing exactly like it yet, we did consider the ways that many similar systems work. There's a lot of similarities, even though I do think Editions end up being meaningfully distinct. As an example, here's a comment of mine on the original RFC (which was called "epochs"): https://github.com/rust-lang/rfcs/pull/2052#issuecomment-315175143 https://github.com/rust-lang/rfcs/pull/2052#issuecomment-315... (the part with "Some language development comparisons")
- avgcorrection 5y ago> I think the main problem here is semver. Maybe it’s ironic that semver (machine-readable versioning) ended up being a liability due to interpretation by people (i.e. we can’t release a 2.0 because it would “send the wrong message”).
- steveklabnik 5y agoWhile semver was intended as machine-readable versioning, and still mostly is, given that sevmer does not say what an "api" is in any way means that it's still defined by humans at the end of the day. I think I'm in agreement :)
- avgcorrection 5y agoAnd I agree with you on the solution: version the language (or whatever other more conceptual thing) by year and the program by semver. It’s the only thing that makes sense given the constraints.
- stouset 5y agoOf course there's always Hyrum's Law[1], which can be summed up as > All observable behaviors of your system will be depended on by somebody. Even minor bugfixes will at some point invariably break somebody who depended upon the broken behavior. So semver really boils down to a human assessment of whether any potential breakage is incidental or intended. [1]: https://www.hyrumslaw.com/ https://www.hyrumslaw.com/
- nivertech 5y agoSolidity (a PL in which Ethereum's so called "smart contracts"[1] are developed) has version pragmas [2] at the top of each file. That's necessary b/c there are lots of breaking changes between language/compiler versions[3]. -- [1] they are more like DB triggers than contracts [2] https://docs.soliditylang.org/en/develop/layout-of-source-files.html#version-pragma https://docs.soliditylang.org/en/develop/layout-of-source-fi... [3] https://docs.soliditylang.org/en/develop/050-breaking-changes.html https://docs.soliditylang.org/en/develop/050-breaking-change...
- woodruffw 5y agoVersion pragmas themselves aren't new -- even Perl has them[1]. What makes Rust's implementation nice (and somewhat unique) is its commitment to backwards compatibility while allowing codebases to incrementally move towards a new edition. [1]: https://perldoc.perl.org/functions/use https://perldoc.perl.org/functions/use
- tialaramex 5y agoFrom one your links: > It just instructs the compiler to check whether its version matches the one required by the pragma. If it does not match, the compiler issues an error. This is very different from Rust where your Rust 1.56.0 compiler will cheerfully compile Rust 2015, Rust 2018 and Rust 2021 code, into the same program even. Rust editions are not about the compiler version, they're about the language and every Rust compiler will compile every language edition it knows about.
- bee_rider 5y agoAlthough if they hit Rust version 2.XX.Y this might add some (probably brief) confusion.
- RussianCow 5y agoI remember reading somewhere that Rust will never have a v2, but now I can't find a source.
- nicoburns 5y agoThere are currently no plans, but I don’t think it’s a hard never. I’d probably be willing to bet it’ll be at least 10 years though.
- cygx 5y ago> I haven't anything like it in other languages Perl can do it not only at module level, but at block level within a single source file.
- remram 5y agoLots of languages have opt-in features/extensions/pragmas, which are more granular but somewhat similar. Like Python's __future__, Haskell's #LANGUAGE, and Rust's #![feature]. Adding 20 lines of #[!feature(...)] to every project would get old quick.