You have a compiler that can only compile a specific subset and use that subset to write the real compiler. There are endless book examples how to do it.
Given who Go designers are, I think they don't have any issue keeping the C code around.
Many generations of the compiler are created. Let's say the compiler-in-C is worked on until it compiles subset Gosub1 which is just enough to write compiler-in-Gosub1 that duplicates compiler-in-C's behaviour. From now, compiler-in-C atrophies. G-2 features are implemented in G-1's compiler, though nothing uses them yet. The compiler's source then uses these, making it G-2 source, only compilable by a G-2-grokking compiler.
Weeks later we have a G-40 where a bug is discovered, introduced in G-20. It wasn't in the compiler-in-C so that's not useful. Choices include fixing it at `head', which can sometimes be awkward as described earlier, or fixing the initial G-20 implementation and then rolling forward all changes from there assuming the fix doesn't break code that was depending on the errant behaviour.
Given that compiler design was one of my three main focus on my CS degree, I read a few books along the way. :)
> Many generations of the compiler are created. Let's say the compiler-in-C is worked on until it compiles subset Gosub1 which is just enough to write compiler-in-Gosub1 that duplicates compiler-in-C's behaviour. From now, compiler-in-C atrophies. G-2 features are implemented in G-1's compiler, though nothing uses them yet. The compiler's source then uses these, making it G-2 source, only compilable by a G-2-grokking compiler.
It is not required to do this so fine grained.
The first version of the primitive language can already be good enough to offer the minimal set of features to compile itself.
Afterwards the full language compiler gets implemented in this minimal version and used for everything else.
There aren't thousand versions of the compiler, you just need to be restrictive of what is used in the base compiler.
> Weeks later we have a G-40 where a bug is discovered, introduced in G-20. It wasn't in the compiler-in-C so that's not useful. Choices include fixing it at `head', which can sometimes be awkward as described earlier, or fixing the initial G-20 implementation and then rolling forward all changes from there assuming the fix doesn't break code that was depending on the errant behaviour.
As I explained this is not required because you only have G-2 as starting point, which is able to compile whatever is the current version of the language.
Additionally you get the benefit to eat your own dog food and as compiler designer check if you are doing the right design decisions on how the language works.
Now that Go 1.0 release exists and is stable. One could write a Go compiler using Go 1.0.
Eventually the compiler will reach a state that it can fully compile Go 1.0.
Now replace the C implementation of Go 1.0 by this new compiler and use it to write Go X.Y using only Go 1.0 features.
When the need to target a new OS or CPU arises, add a new backend that generates code for the desired target system in the Go 1.0 compiler.
Use the cross-compiler to compile itself with the new backend. Copy the binary to the new system, now use the Go 1.0 compiler to compile the Go X.Y version, whatever X and Y are.
You don't need to use multiple versions of the language and by keeping the feature set of base compiler small, it makes it easier to write cross-compilers.
Have you ever done multiplaform C development across using OS vendor specific C compilers?
There are lots of nice bugs to be found, just check the available bug databases of any C compiler.
So this does not make it any better.
This isn't getting us anywhere. We disagree. I value the opinion of that lot given their many decades of experience. I used to have your opinion, based on textbooks. They've made a good point, one I can see has considered thought behind it.
I do have compiler development experience, but alas as you say this is not getting us anywhere.