News for hackers. Stuff that matters.
Re:Rust 1.56.0 and Rust 2021 by xamolxix on Thursday October 21, 2021 @11:27AM (#28945841)
> 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?

Re:Rust 1.56.0 and Rust 2021 by masklinn on Thursday October 21, 2021 @12:08PM (#28946577)
Aside 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.

Re:Rust 1.56.0 and Rust 2021 by neandrake on Thursday October 21, 2021 @01:44PM (#28948163)
It’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.
Re:Rust 1.56.0 and Rust 2021 by masklinn on Thursday October 21, 2021 @01:49PM (#28948265)
That 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).
Re:Rust 1.56.0 and Rust 2021 by tialaramex on Thursday October 21, 2021 @03:08PM (#28949448)
The 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?

Re:Rust 1.56.0 and Rust 2021 by stormbrew on Thursday October 21, 2021 @04:18PM (#28950303)
Personally I'd kinda like it if preludes were decoupled from editions in some way. Like, fine to have a default per-edition but there are times I would really like to have a prelude without all the `impl<T> X for T`s included.

You can kinda do this now with `#[no_implicit_prelude]` I think but it has somewhat odd semantics. It applies to all submodules, unlike most attributes, and then if you define your own prelude you need to use it in every submodule because they won't all have their own.

If it's gonna have global effect I think it'd be better if it was:

    #[prelude]
    mod my_prelude {
        use std::whatever::*;
    }
and then my_prelude would be included in all submodules by default.
Re:Rust 1.56.0 and Rust 2021 by nextaccountic on Thursday October 21, 2021 @10:26PM (#28953107)
There was a proposal for that, but it wasn't accepted https://github.com/rust-lang/rfcs/pull/890
Re:Rust 1.56.0 and Rust 2021 by stormbrew on Friday October 22, 2021 @08:46PM (#28964566)
Hm. Not really fond of the way that RFC was closed tbh. I feel like far more dubious suggestions sit open for ages and the main argument against this one is that it had narrow use cases but was otherwise uncontroversial. Like, there's a fine line between a feature request is quiet because no one really wants it vs. because it's just kind of an easy small win that's not even worth bikeshedding.

Meanwhile, the thing that is in the language is.. weirder and arguably worse.

Re:Rust 1.56.0 and Rust 2021 by nextaccountic on Saturday October 23, 2021 @11:58AM (#28969675)
If you feel like it, maybe open a thread on internals.rust-lang.org? This issue can still be debated..

Also, it was closed in 2015; it was a different time back then. I don't think that RFCs from 2015 should be kept open just because. Arguably, Rust shouldn't have 88 RFCs open (as of now), either.

Re:Rust 1.56.0 and Rust 2021 by nicoburns on Thursday October 21, 2021 @04:58PM (#28950765)
Seems like it ought to new possible to rename std::iter::Iterator to std::iter::OldIterator, add std::iter::NewIterator, and then vary which iterator std::iter::Iterator points to based on edition.

Maybe that would be considered too confusing though.

Re:Rust 1.56.0 and Rust 2021 by EdSchouten on Thursday October 21, 2021 @11:34AM (#28945968)
Yes, in that in C++ it would break if one library used a modern language feature as part of its public header files.
Re:Rust 1.56.0 and Rust 2021 by chc on Thursday October 21, 2021 @12:05PM (#28946533)
Surely the difference there is that Rust doesn't have header files.
Re:Rust 1.56.0 and Rust 2021 by masklinn on Thursday October 21, 2021 @12:10PM (#28946620)
Not necessarily, you could imagine a system where the header file specifies its edition.
Re:Rust 1.56.0 and Rust 2021 by cpeterso on Thursday October 21, 2021 @03:21PM (#28949636)
A 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
Re:Rust 1.56.0 and Rust 2021 by dralley on Thursday October 21, 2021 @04:00PM (#28950105)
But don't header files generally get concatenated together due to the way "dumb" textual includes work?
Re:Rust 1.56.0 and Rust 2021 by hiccuphippo on Thursday October 21, 2021 @12:39PM (#28947117)
Can't you compile libraries to object files independently with whatever version of c++ they require and then link them together?
Re:Rust 1.56.0 and Rust 2021 by tialaramex on Thursday October 21, 2021 @12:53PM (#28947354)
Yes. 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.

Re:Rust 1.56.0 and Rust 2021 by MaulingMonkey on Thursday October 21, 2021 @02:12PM (#28948642)
The 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.

Re:Rust 1.56.0 and Rust 2021 by int_19h on Thursday October 21, 2021 @03:21PM (#28949630)
You'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.

Re:Rust 1.56.0 and Rust 2021 by pornel on Thursday October 21, 2021 @03:23PM (#28949653)
Yes, 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).

Re:Rust 1.56.0 and Rust 2021 by alerighi on Thursday October 21, 2021 @04:28PM (#28950430)
C 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.

Re:Rust 1.56.0 and Rust 2021 by nicoburns on Thursday October 21, 2021 @05:03PM (#28950810)
> 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.

Re:Rust 1.56.0 and Rust 2021 by lfairy on Monday November 01, 2021 @01:35AM (#29063322)
> 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++-...

Re:Rust 1.56.0 and Rust 2021 by heftig on Thursday October 21, 2021 @11:34AM (#28945977)
If 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.

Re:Rust 1.56.0 and Rust 2021 by pjmlp on Thursday October 21, 2021 @12:53PM (#28947346)
Or you make use of the preprocessor or if constexpr, and then have the specific code for each language version.
Re:Rust 1.56.0 and Rust 2021 by tialaramex on Thursday October 21, 2021 @01:27PM (#28947898)
It's certainly true that if C++ library maintainers are up for the ever-growing maintenance burden, they can all individually deliver the same promise Rust gets out of the box.

This is in practice what the maintainers of the three standard libraries have to do, perhaps one or more of them will offer their opinion about that experience?

Re:Rust 1.56.0 and Rust 2021 by int_19h on Thursday October 21, 2021 @03:22PM (#28949647)
The 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.
Re:Rust 1.56.0 and Rust 2021 by pjmlp on Thursday October 21, 2021 @03:37PM (#28949828)
I 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.

Re:Rust 1.56.0 and Rust 2021 by tialaramex on Thursday October 21, 2021 @08:13PM (#28952416)
> 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.

Re:Rust 1.56.0 and Rust 2021 by pjmlp on Friday October 22, 2021 @01:11AM (#28953926)
For starters epochs could never work in ecosystems that value binary libraries, regardless of possible ABI issues, which is also a reason why Apple went to such an effort to define an ABI alongside language versions.

Lets say you have a noexcept function compiled in C++20 that calls a throws() function, compiled in C++03, which actually ends up throwing, linked together.

What is the runtime supposed to do now?

To which semantics does it follow now?

Call std::unexpected() as it is supposed to do pre-C++14 or call std::terminate() as it should do in C++20?

What about the user defined handler that was configured for such scenario? Which of them gets called, or do both get called, in which order?

Maybe I am doing it more complex that it is, but I see several scenarios from point of view where multiple compilers, binary libraries and semantic changes come into play, editions turn just into another way to define language versions, because they don't cover all possible uses cases how a language might evolve.

Anyway, history will tell how things work out in the end.

Re:Rust 1.56.0 and Rust 2021 by tialaramex on Friday October 22, 2021 @04:10AM (#28954738)
> For starters epochs could never work in ecosystems that value binary libraries

Not solving everybody's problem is not the same thing as not solving anybody's problem.

You present subtle considerations which, ignoring the fact that they assume Epochs don't exist in C++ 20 yet ask what Epochs should have done in C++ 20 - might have taken up committee time if Epochs had advanced, and which now can only be answered in the vaguest way, they should definitely have decided on a coherent strategy for resolving such problems.

It is true that for any conceivable change, Hyrum's Law applies, and so it would apply to Epochs just as it does for Rust's editions. Mara's "competition" for writing Rust that gives different results when re-formatted provides examples of the sort of stuff Hyrum's Law invariably breaks. Nobody should be writing non-toy programs like that and in Rust it seems like nobody is. It's a sad fact that too often C++ programs are written in a very fragile way and many of them can and do break with the least provocation.

You can't magically rewrite all those programs, but you can make fragile techniques like SFINAE unattractive to propagate into new programs, and I argue Epochs would have allowed C++ to begin the much harder part of Stroustrup's ever-evolving quest to ship a good programming language - not adding yet more kitchen sinks but removing parts of the language that in hindsight were a bad idea and revisiting old design decisions in the light of what has been learned.

Re:Rust 1.56.0 and Rust 2021 by pjmlp on Friday October 22, 2021 @08:35AM (#28956481)
That is the thing with ISO/ECMA languages, it has to work in every possible scenario there is a certified compiler, if not then as you know, we go down the path of nasal daemons.

For example, the Epoch semantics in xlCC would have to behave as in VC++, to avoid too many nasty surprises in cross platform code that is in production for decades.

Re:Rust 1.56.0 and Rust 2021 by tialaramex on Friday October 22, 2021 @08:03PM (#28964339)
First, it seems weird to suggest that "nasal demons" are a particular fear of WG21 at this point. As a reminder when C++ got an Optional type std::optional the committee insisted that it have Undefined Behaviour if you for any reason don't check whether it is empty before using the contents.

We're not talking about 1998 here. This is in 2017. By this point plenty of people have experience already using languages with Optional types that do what you actually want here, but the C++ committee decided no, C++ is the footgun language, it's what we're known for.

But OK, in an alternate universe where the committee doesn't introduce footguns on purpose to prove their Real Programmer credibility, and where we do get Epochs, what should happen for fraught situations so as to deliver consistency?

The committee should decide on a rule. I know that's often portrayed as too difficult for such problems, but it won't get easier in subsequent versions. That's why I think it would have made sense to delay long awaited work like Concepts if that was the only way to land Epochs. Concepts is already too late for the main act and being a little later barely makes a difference. Whereas Epochs gets harder to do every version, so the sooner the better.

Re:Rust 1.56.0 and Rust 2021 by int_19h on Friday October 22, 2021 @02:42AM (#28954313)
You might well be right, but if the scheme lasts 20 years (and makes it easier to maintain old code during that period), I'd say it's a very good run by PL standards!
Re:Rust 1.56.0 and Rust 2021 by orra on Thursday October 21, 2021 @11:36AM (#28946000)
I 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.