
RFC: Evolving Rust Through Epochs - JoshTriplett
https://github.com/aturon/rfcs/blob/epochs/text/0000-epochs.md
======
Animats
It's really language version pinning for source code.

Rust uses version pinning heavily. This gradually builds up a legacy code
problem, as old versions never really go away. A recent article on HN pointed
to some bloated non-Rust phone app which shipped with four different versions
of some libraries.

How does this work when crates with different epochs are mixed? The business
with "core Rust" suggests that all code must be compiled with the same core
compiler, because the run-time model might change, but some crates may have
different epochs.

~~~
steveklabnik
> How does this work when crates with different epochs are mixed?

It Just Works. (The discussion contains some stuff about macros, which may be
a bit more complex, but that's the core concept anyway.)

> the run-time model might change

Rust has no more runtime than C.

It's in fact in the opposite; the only kinds of changes that can be made in
epochs are basically to the parser, everything below that has to stay the
same. This is for both technical debt reasons as well as for "mental debt"
reasons; the core way that Rust works cannot change.

~~~
GolDDranks
I think he means run-time semantics.

But anyway, the promise of stability means that the semantics can't be changed
in a breaking way. So having epochs is no free pass to do arbitrary kind of
breaking changes, and the Rust people are well aware of that.

------
Ericson2314
Shamelessly reposting my comment [https://github.com/rust-
lang/rfcs/pull/2052#issuecomment-312...](https://github.com/rust-
lang/rfcs/pull/2052#issuecomment-312981730), but I'm concerned about using
semver for the tools, and what is effectively just a major version for the
language.

This is backwards. Every new language feature should get its own minor
version, and if tools never drop support, there is no need for a (tool) major
version.

~~~
TokenDiversity
Exactly. This is just a bad use of "Semver". It's still a "version" right?
2018 vs 2015?

If they're so concerned, maybe add another figure to the left.

Current version could be 1.1.42.0 and the "eopch" could be 1.2.3.9? Maybe
breaking could be 2.0.0.0? I'd much rather see a unification around semver
then create a different identifier called epoch only to stay radically
faithful to a definition of semver

~~~
OskarS
I feel like this is only a problem if you stick religiously to semver. This
problem more or less boils down to:

1) We want to indicate that a major update to the language has happened, so we
want to bump the major version number

2) We can't bump the major version number, because we're not making breaking
changes, so our semver dogma forbids it.

3) Lets add a completely new version number that's even MORE important than
the major version number and call it "epoch", and lets not have that follow
any semver semantics!

You have a major version number already. Just bump that. Don't make up a new
one. There's no federal law saying you have to follow every rule of semver,
you can just make the decision to release Rust 2.0.

Don't get me wrong, i think semver is a great policy for version numbering.
But you have to recognize when it's causing more problems than it solves.

~~~
Ericson2314
They are indeed making a breaking change in that some new code will not be
valid previously, and some old code will not be valid after.

They are totally correct that since everything interfaces with each other,
this is _not_ a problem in practice. But they are worried about the stupid
knee-jerk negative publicity that well occur—I don't dispute that.

But this is extra complexity to pander to idiots.

------
cronjobber
For a little language I designed, I decided that keeping the evolutionary
pathway open means introducing new keywords once in a while. But we don't want
to break existing code; code is expensive. Valuable. We don't want to break
valuables!

So I added a mandatory file header to the language which (amongst other
things) specified the language version.

I thought this was a win... with _one_ exception that would have bothered me a
lot if this had been a language intended to achieve world domination:

Mandatory version headers totally ruin your "hello, world!" comparison chart
story ;-)

~~~
Animats
_Mandatory version headers totally ruin your "hello, world!" comparison chart
story ;-)_

Once, when the C standards committee was struggling with the semantics of
"main" under Windows, I suggested that "main" not be part of the language at
all. You would include <unix.h> or <posix.h> or <dos.h>, and get "int main(int
argc; char *argv[]);" as a prototype, which you must define. Or you include
<windows.h>, and "int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE
hPrevInstance, LPSTR lpCmdLine, int nCmdShow);" is the function you must
write. The runtime pulled in would call the appropriate function. "main" would
no longer be a special case. This was generally agreed to be the correct
solution, but too upsetting for beginners.

~~~
JoshTriplett
It'd be unfortunate to have to include a platform-specific header in otherwise
portable code. Why have to include a <posix.h> versus <dos.h> if they both
define main the same way? (Windows aside.)

~~~
mrec
You can use vanilla `main` for Windows apps too, just need to override the
default subsystem when invoking the linker. I never understood the point of
`WinMain`; IIRC there's nothing it does that you can't do just as well without
it.

------
buzzybee
Contrast with FPC's compiler mode pragmas for different dialects. [0] FPC
shows the effects of this story in the long term: there are several major
divergences in behavior supported by the modes, and some individual features
can be toggled per-unit or sometimes with a finer grain. [1] Since you're
allowed to mix and match different units, the fragmentation poses little
threat to any individual programmer, and it's possible to dial in assertions,
optimizations, and calling conventions in a targeted fashion.

[0] [https://www.freepascal.org/docs-
html/user/userse33.html](https://www.freepascal.org/docs-
html/user/userse33.html)

[1] [https://www.freepascal.org/docs-
html/prog/progch1.html#progs...](https://www.freepascal.org/docs-
html/prog/progch1.html#progse2.html)

~~~
pjmlp
That is part of the Pascal culture, we were already making use of such pragmas
during the MS-DOS / VAX / Compaq / Apple days.

------
goodplay
This is good news for us who want alternative implementations like gccrs. GCC
(and software developers) can target static "epoch"s (c89, c99, c11, ...)
rather than a moving target.

Hopefully, this will be enough to make development of GCC's rust front-end
viable again.

~~~
Manishearth
FWIW the GCC frontend development seems to have started up again. I'm hopeful!

However, epoches don't really help alternate frontends. Rust 1.42 on epoch
2015 will still have all the features Rust 1.42 on the latest epoch has,
except for the features that require an epoch shift (which will be a small
handful)

But compiler versions already help here, targeting a compiler version gets you
all of this.

I suspect if a compiler backend project nears completion there will be a lot
more collaboration between rustc and the project in order to make evolution
less painful.

~~~
JoshTriplett
> FWIW the GCC frontend development seems to have started up again. I'm
> hopeful!

I'm curious: any particular goals or results you hope to see out of the GCC
frontend? Do they have any plans to share front-end code with rustc, such as
the parser?

~~~
steveklabnik
One thing I'm hoping is that it brings support for some more obscure arches.

~~~
JoshTriplett
The ones that GCC supports and LLVM doesn't?

~~~
steveklabnik
Yup. There's a lot, in my understanding.

------
cpeterso
If the Rust compiler promises to support all previous epochs, can it ever
remove the compiler code that implements deprecated language features?

~~~
JoshTriplett
No, and they've specifically specified it as always available. Just as GCC
still supports C89.

However, they also specified this as only affecting translation/desugaring,
which makes the additional code minimally invasive.

------
TazeTSchnitzel
If "catch" becomes a keyword in a future epoch, how does code in that new
epoch call functions with that name defined in libraries from previous epochs?
Does Rust support stropping?

~~~
Manishearth
It can't, I presume code on an older epoch will have to expose it with an
alternate name, or upgrade to the new epoch.

The epoch RFC doesn't attempt to improve this, but the hypothetical catch RFC
can. It can for example provide an oldcatch!() macro that expands to the catch
path instead of the keyword, making it possible to import things or define
things. Or have some system of attributes.

Solutions are possible!

~~~
ben0x539
Is it possible to have a syntax extension (or even macro?) that creates
identifiers that wouldn't be legal in plain source code?

~~~
Manishearth
It can try to; but it will fail to parse, usually (both macros and new-style
syntax extensions go through a sort of re-parse step)

Old-style (AST-based, unstable, will go away) syntax extensions can do this.

But this isn't relevant, the compiler can define custom syntax extensions that
do whatever it wants :)

------
tveita
So it looks like you end up with two syntaxes for the same feature, one of
which you can use without any extra declarations. From a user's perspective,
why not just use the "do catch" syntax everywhere? What happens with that
syntax, is it eventually deprecated?

It seems like you end up with an 'ugly' way and a nice way, under the
assumption that the ugly way will be temporary, but really both ways end up
sticking around, and users can and will use them interchangeably.

I see the motivation, but realistically it may be better to just stick with
the not-so-nice syntax everywhere. Or at least have a good way to
unambiguously namespace future keywords - instead of "do catch", say
"futurerustkeyword catch" or something. Or maybe a per-file declaration like
"use __future__::catch" ;)

