www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - D Language Foundation July 2024 Quarterly Meeting Summary

reply Mike Parker <aldacron gmail.com> writes:
The D Language Foundation's quarterly meeting for July 2024 took 
place on Friday the 5th at 15:00 UTC. It lasted for about an hour.

Our quarterly meetings are where representatives from businesses 
big and small can bring us their most pressing D issues, status 
reports on their use of D, and so on.



The following people attended the meeting:

* Mathis Beer (Funkwerk)
* Walter Bright (DLF)
* Johan Engelen (Weka)
* Luís Ferreira (Weka)
* Martin Kinkelin (DLF/Symmetry)
* Dennis Korpel (DLF/SARC)
* Mario Kröplin (Funkwerk)
* Mathias Lang (DLF/Symmetry)
* Mike Parker (DLF)
* Carsten Rasmussen (Decard)
* Robert Schadek (DLF/Symmetry)
* Bastiaan Veelo (SARC)





Carsten said Decard had been experimenting a lot with 
WebAssembly. They'd stubbed out DRuntime until it worked. They 
had some of their library functions running in a browser and had 
tried different virtual machines. They wanted to do more work on 
that. They had a lot of issues with mobile because different 
chips worked in various ways. They wanted to get their entire SDK 
working on WASM, but it would probably take a year to complete 
because there was a lot of stuff moving around in WASM.

Robert asked if they'd gotten the GC working. Carsten said they 
hadn't focused on that. They were just calling functions. They 
didn't know how to write a GC, so they were hoping to use the 
WASM GC eventually.

He said one thing that had been annoying was that the WASM 
interface was basically POSIX, but the compiler didn't treat it 
as such for versioning. He'd had to implement a lot of versioned 
dummy code to get it to work. He would like to see the compiler 
recognize WASM as POSIX.

Robert said he'd seen that the standardizing body had accepted a 
proposal for GC. Carsten said they'd also accepted 
multithreading. He thought WASM was moving into virtual machines 
and such, so it would eventually be a VM for both in and out of 
the browser. Robert said it was a really nice interface.



Bastiaan said he was still working on SARC's D translation. Now 
and then he encountered a problem that was difficult to solve or 
difficult to understand. That was his life, but there was nothing 
major to bring up here.



Mathis said that for the first time ever Funkwerk was using a 
patched version of the compiler because the rebindable range 
`destroy` bug was so horrible. He said that wasn't a new thing, 
though, because it was mostly his fault. He thought the `destroy` 
function should just be deprecated. It just did so much harm, but 
he didn't feel it was debate-worthy.

Dennis asked if he meant the general core `destroy` function. 
Mathis clarified that he meant the `Object` version. He said it 
had this issue where when it was dealing with a value type it 
would do something to the value, but when dealing with a class it 
actually destroyed the class value, not the reference but the 
actual object itself, in a way that was very hard to notice. 
Sometime later you'd notice that your vtable pointer had become 
zero, so you had to know what that meant and find out where it 
happened.

He thought it was almost never the function you wanted to call in 
the generic case. He couldn't think of a single case for it. He 
found it bewildering.

Walter thought the purpose of `destroy` was so you didn't have to 
wait for the GC to collect an object. You could just say you were 
done with it. Mathis said no, it didn't even deallocate.

Walter asked why it mattered if it set the vtable to zero if you 
weren't going to use it anymore. Mathis said the problem was that 
he was using it in a generic context and wanted to call the 
semantically appropriate destruction operation for a value. For a 
struct, that meant calling the destructor because the value's 
lifetime was ending. But when the lifetime of a class reference 
ended, nothing should happen because there might be other 
references to that class instance. But what actually happened was 
that the class instance was destroyed no matter how many 
references remained.

Walter said that was the point of `destroy`. Mathis said it 
didn't do that for any other type. If he had a struct lying 
around somewhere and passed a copy to `destroy`, the original 
version wouldn't be affected. Dennis said that was true, but if 
you had a pointer to that struct, then the pointer would be 
dangling. Mathis said he didn't actually know what `destroy` did 
with pointers. He thought it did nothing.

Walter said if you were to destroy something, then there should 
be no more references to it. It was up to you as the programmer 
to ensure there were no more references to it. Mathis said in 
this case he was using it to compensate for lifetime management 
of [a data object in 
rebindable](https://code.dlang.org/packages/rebindable) where he 
had to take charge of the lifetime. He thought he'd call 
`destroy` to end its lifetime.

Walter said, no, you called `destroy` when you as the programmer 
know that was the end of the targeted value, which was dependent 
on the specific type. So if you were using it in a generic 
function, if it was a struct, then it was going to be a copied 
value so it made sense to say you wanted to end the lifetime of 
that value. But if it was a class, the copy constructor was 
literally just making a copy of the reference. If you called 
`destroy` on that, you were saying that there were no more 
references to it.

Mathis said that was his point. The behavior was different 
semantically. He wasn't calling it on a class specifically. He 
was calling it on a `T`, an arbitrary template parameter. Walter 
said that by doing that he was saying there were no more 
references to that `T` instance. But here in the meeting he was 
saying he had more references and they were going to go bad, but 
that was not the point of `destroy`. The point was that the 
programmer was saying there were no more references.

Mathis said the behavior made sense for classes and made sense 
for structs, but it didn't make sense for both classes and 
structs. It was different. Walter said that was the way class 
objects worked. Calling `destroy` was unsafe.

Mathis said that basically, it didn't make sense to be 
overloaded. There should be a `destroy` and a `destroyClass`. 
Walter again repeated that this was the point of the function: 
calling it meant you were indicating there were no more 
references.

Martin said the problem with classes was that you could never be 
sure that the reference you were destroying was actually the 
final reference. He suggested we should have a separate finalizer 
for classes. It would mean breaking changes, but we could add a 
finalizer for class objects and then in an edition, we could 
change the semantics of `destroy`.

Walter thought it was a good idea, but said the trouble with 
having a separate `finalize` and `destroy` was that people would 
mix them up, wouldn't understand the difference, would use the 
wrong one, and then be unhappy. It was inevitable.

He said one thing Mathis could do was to wrap the call to 
`destroy` with "is this a class". Mathis said he'd been doing 
that. He couldn't ever remember calling `destroy` without 
wrapping it like that. Walter said okay, it was working the way 
it was designed to work, and he didn't think we could change that 
behavior.

Luís thought one of the problems here was special cases for 
classes. Not only `destroy`, but a lot of stuff was special-cased 
for classes because they were just pointers to hidden objects 
plus a vtable. Another thing was that classes implied the 
presence of the GC, but you could also allocate them without the 
GC. The existence of the special cases was why Weka didn't use 
classes. Most of the cases could be solved with structs.

Walter said Luís was right that classes and structs were 
different from each other. Algorithms that ignored those 
differences were going to lead to trouble. Luís understood that 
but felt the design could have been more similar to structs 
without the differences that always need special cases in generic 
programming.

Walter said that in C++ you had to special-case for references. 
When you had value types and reference types, they were going to 
be different. He didn't think there was any magic way to fix 
that. Luís said at this point he didn't think so either.

Mathis agreed. He said he really liked the class design in D. The 
standard range algorithms worked fine with classes as well as 
with structs when written in a straightforward way. The only 
function he had a problem with was destroy. He felt that if he 
had a generic function that required him to use a `static if` to 
call a function, then in fact it was two functions that happened 
to be named the same.

Walter said that was a good point, but if you were using value 
types, you should be relying on RAII to do the destruction, not 
an actual `destroy` function. And RAII didn't happen with classes.

Mathis noted that his case was a special case. He had this magic 
rebindable thing going on where he had to take manual control of 
lifetime. He supposed it was something that didn't come up often. 
Walter said when you were manually doing lifetime as a special 
case, then it was a special case and you had to put an `if` in 
there.

I noted that `Object.finalize` in Java had been deprecated 
because it was so easy to misuse. I remembered that Sun used to 
always tell people not to do this or that in `finalize`, because 
it wasn't a destructor, yet people would still do this and that. 
We had kind of the opposite problem in D in that our destructors 
were also finalizers.

Walter said you were never going to get fire and water to mix. 
Reference types and value types were just intractably different 
from each other.

Mathis said this had come up because he had to add that 
rebindable alternative to support `immutable` in `std.algorithm`, 
[which all went back to his DConf '22 
talk](https://youtu.be/eGX_fxlig8I).

He then wrapped up by reporting that Funkwerk were on DMD 2.108 
and LDC 1.38 everywhere and it was working pretty well. Their 
code was internally managed with no major external dependencies. 
They were happy to be off of vibe.d and no longer dealing with 
its issues from compiler updates. And they were happy with 2.108.



Luís said he had nothing new to bring, but he wanted to 
understand the status of the AST refactoring project. Weka still 
had linkage issues resulting from the incorrect inference of 
templates and attributes. He thought it was mostly because the 
way we queried the AST was kind of a mess. If we had a way to 
make that better, then it would make other things better.

I said that Razvan was the one who knew all about that. I knew 
that it was mostly Razvan working on it right now, though others, 
including Bastiaan, had contributed. It was also an officially 
sanctioned idea for a SAOC project. So it was in progress, and 
Luís should ping Razvan if he wanted an accurate picture.

Luís closed by saying he'd seen some good features come into the 
language lately that he'd been waiting a long time to have, like 
string interpolation and named arguments. He thought that was 
really cool to see.

(UPDATE: One of the SAOC 2024 participants is working on the AST 
refactoring project right now, and Razvan intends to enlist some 
of his students at the [Politechnica University of 
Bucharest](https://upb.ro/en/) to contribute. He could always use 
more help on this. It's not difficult work, there's just a lot of 
it. But it can be done in small chunks which makes it really 
amenable to contributions from multiple people. This is a 
high-impact project. If you'd like to find out how to contribute, 
please read [Razvan's call to arms on the D 
blog](https://dlang.org/blog/2024/02/22/dmd-compiler-as-a-library-a-call-to-arms/).)



Mario had no programming issues to report but said that three 
Funkwerk staff would be attending DConf this year.

Mathis said that Luís mentioning named arguments had just 
reminded him that Funkwerk wanted to use them, but currently 
couldn't because they weren't supported in dfmt. They used to 
allow one of their employees some time to spend on dfmt, but that 
employee was no longer working for them and they were now in a 
gap. He wasn't sure what to do about that. Maybe he could take a 
few days to look at it, but they used dfmt in all their projects, 
so that made named arguments a non-starter for them.

Dennis said he had started using dfmt recently for his own code 
and noticed a few bugs. He'd opened some issues, but it seemed no 
one was actively monitoring it. He said he might take some time 
to figure out how it worked so he could fix these issues. It was 
really annoying when the formatter squashed things in attributes, 
got confused by the colon in named arguments, and completely 
ruined the argument list.

Mario said that he hadn't assigned Mathis to fix dfmt because he 
wasn't sure if it would be a waste of time and money. He knew 
that there was also sdfmt from SDC, and he also knew that 
something had been done with dfmt with regards to integrating 
DMD-as-a-library, but he didn't know what the progress was. He 
didn't want to task Mathis to fix dfmt if the fixes would become 
irrelevant when it was replaced with something else.

Dennis said one of Razvan's students had worked on the project to 
replace dfmt's use of libdparse with DMD-as-a-library, but he 
didn't think it was enabled by default. The last he'd heard there 
was just a switch to enable it and it was still kind of early. He 
didn't think the change would affect the formatting logic, but 
we'd have to see.

I noted that in the past we had discussed shipping a formatter 
with the compiler. We had agreed it would be dfmt because it was 
going to use DMD-as-a-library, which made sense if we were going 
to ship it with DMD. As such, any fixes to the formatting logic 
shouldn't be wasted time.

Luís said that Weka hadn't been able to test the dfmt changes yet 
because they were a few compiler releases behind, but he hoped 
they'd be able to soon. He'd report any issues they found with it.



Johan said there were probably a few issues from Weka to talk 
about, but he hadn't collected them before the meeting, so he'd 
bring them up next time.

He did have some news for us. He said that Weka had been 
interested in linking executables with musl libc. He'd fixed the 
last parts that were required to make it happen. He'd upstreamed 
almost all of it to DRuntime. He said that was a nice success 
story. You could now create statically linked executables that 
didn't depend on any libc implementation, and that had been the 
goal.

Next, he requested that we include the language spec in the 
compiler repository to prevent the kind of parallel pull requests 
where you ended up having to revert one if you had to revert the 
other. He was sure it had been debated before, but he would like 
to see it.

Robert said it would be even more awesome if the spec were unit 
tests, i.e., docs that were actually testable. That would 
probably be more work, but it would be really cool. Even with the 
spec in the compiler repository, you'd still have to remember to 
update it. But if you had a spec that failed to compile and the 
documentation was generated from that, it would be a bigger win.

Walter said that was a great idea.

Dennis noted that examples in the spec were currently run if they 
had the proper macro. He said that Nick had been working on 
transforming raw, untested code into runnable examples.

Robert said that was awesome and asked if it included other test 
cases for the language. Sometimes when he read the spec and 
something wasn't clear, he'd go to the tests and see what 
actually came out at the end. If they were included, that would 
tighten up the spec quite considerably.

Dennis asked if he meant linking the DMD test suite with the 
specification, and Robert said yes.

Walter said the test suite was really not meant for public 
consumption. It was not designed to be that way. It was designed 
to make the compiler easy to debug.

Robert agreed but reiterated that sometimes when he read the 
spec, there was some nuance missing, or the wording was such that 
he misunderstood. Reading some obscure source code that might be 
hitting his specific need helped him in that regard. He 
understood where Walter was coming from, but it was just an idea 
to float.

Walter said Robert was right, but he pointed out that every time 
he read a computer software specification, including language 
specifications, the specs on how the function call ABI worked 
always confused him. So he would write little test cases, compile 
them, and see what happened. Robert said he was a lot lazier than 
Walter and was looking for somebody who had already written the 
thing he was interested in.

Walter said that once he had written the code, compiled it, and 
seen what happened, then he'd go back and read the spec again and 
it would make sense. He wished he knew a way to make a better 
correspondence between the specification and understanding it.

Luís said his experience in relation to Walter's had been the 
opposite. For example, reading the D spec, assuming the ABI 
worked as described, and then experimenting with DMD and finding 
the ABI didn't work as specified. For example, arguments were 
getting reversed. In the calling convention, the arguments were 
supposed to be one way, but in the compiler, they were the other.

He said we had two different kinds of tests on the compiler. We 
had all sorts of weird tests for specific compiler bugs. He 
thought Robert was describing tests that served as examples but 
that also confirmed the spec was conformant with what we wanted 
to say.

Walter said if the compiler and the spec didn't match, that was a 
bug and should be reported. They happened, but if they were 
reported we could knock them down one by one. Luís said he had 
tried to fix the calling convention bug, but it was a very hard 
problem because it was everywhere in the DMD backend.

Walter agreed that the calling convention was a large source of 
complexity, especially in the backend because it supported 
multiple calling conventions. It was a large tangle of code.

Luís said one of the problems he saw was with DMD's math 
intrinsics. They were implemented based on the calling 
convention, but because the argument order was actually reversed, 
we now needed to change all of those intrinsics. He'd submitted 
some PRs to try to fix them, but the tests failed. From talking 
to Iain, he thought GDC was the most ABI-compliant D compiler.

Johan brought us back to his original point: if we had the 
compiler and the spec in the same repository, it would be easier 
to know which language spec matched the version of the compiler 
you had.

As for testing the spec, he said there were companies out there 
that made test suites for C. This was tough work. He thought it 
was a completely separate issue from having the spec and the 
compiler in the same repository. It would be a huge amount of 
work to write all the lines of test code that followed from a 
single line of the spec. It would be great, but it was a huge 
project for sure.

As for the ABI, he felt that was outside of the language spec. To 
him, the spec was at a higher level. We implemented a C ABI 
because we had to, but otherwise, the ABI was quite open. That 
was on a lower level. The more interesting thing for programmers 
was on the higher spec level, and that was linked with your 
specific compiler version. When they were in separate 
repositories, then you had to figure out which dates matched 
which and it got quite tricky quite quickly.

Walter agreed that the language spec and the ABI spec were two 
distinct things. He noted that after the C language was 
standardized, a company made a test suite out of every piece of 
code in the C spec and then released it. Every C compiler fell 
flat on its face. It took years for all the C compilers to 
successfully run the tests extracted from the spec. This was the 
whole problem.

Mathis suggested that when you're looking at the language spec 
and something doesn't make sense to you, but then looking at a 
test causes it to make sense, then that was a test that should go 
into the spec. You didn't have to put it in at that moment, but 
you could file an issue for it. Walter agreed.

Luís gave an example of a situation Weka had encountered where 
having the spec and the compiler in the same repository would 
have been a help.

Walter said he had no objections to it. He didn't think it would 
be a big problem to merge them.

Finally, Johan reported that Weka were still on LDC 1.30, but 
they were close to upgrading to 1.38, which was D 2.108. He had 
already seen some changes in 2.109 to which he thought it would 
take them some time to adjust, so the plan was to upgrade first 
to 2.108 and continue from there.

Luís said he was very excited to use some DIP 1000 features. The 
DIP 1000 changes were what had been keeping them on an older 
version because of breakage, but that had been fixed.



Mathias wanted to reiterate the importance of tooling, and he 
thanked Dennis in advance if he would take a look at dfmt. 
Symmetry were using a formatter as well, though they were using 
sdfmt since Amaury maintained it. But a lot more could be done 
with the tooling and he thought it would integrate with their 
projects quite well. DMD-as-a-library would enable a lot of good 
things, and that would be enabled by the AST refactoring project. 
If we had to choose between an ARM backend for DMD or an 
immutable AST, his vote would go for the immutable AST.



Dennis had been working with COM lately. It had a special calling 
convention with named arguments, and D had named arguments, so he 
thought it would be nice to try to combine them. But `opDispatch` 
and `opCall` didn't support named arguments, and the DIP didn't 
provide any mechanism for it.

He had an idea to add something like `opNamedDispatch` that would 
push the named arguments as a template argument as a string 
array. That would make it work. Walter thought that sounded fun.



Walter said that he'd been posting updates to X about his daily 
progress on the AAarch64 code generator. He was currently working 
on the function call return sequence. Having spent some time with 
it, he had slowly begun to understand the ARM instruction set. 
Some parts of it were still baffling. For a supposedly simple 
instruction set, it was extremely complicated. He had to write 
little snippets of code and try them out on godbolt to see what 
they actually did.

He'd gotten to the point where he thought it was going to work, 
but getting the details done would take a bit of time. He 
expected to have the basics running fairly soon.

Johan asked if Walter had a machine to run it on. Walter said 
he'd just been using godbolt. He'd write a function that was two 
lines or so and wanted to see what instructions were emitted for 
it. How were they doing pushes and pops? How were they doing 
function calls? Godbolt was perfect for that.

He said he also had a Raspberry Pi. He expected that Raspberry Pi 
users would be a potential user base for a simple AArch64 DMD 
backend. That's what he planned to use as a target machine. The 
code the compiler currently emitted didn't handle fixups in the 
elf object files, so actually trying to run the generated code 
wouldn't work.

Unfortunately, the elf generator code was a rat's nest. He'd been 
refactoring it to make it more tractable. With the refactoring, 
it should be easier to implement the AArch64 fixups, which were 
completely different from the x86 fixups.

He'd already written an object file dumper and a disassembler for 
it, so the pieces were slowly coming together. Once he had it 
working on the Raspberry Pi, he'd get a recent Mac with an ARM 
chip in it and make it work there.

Johan said he'd thought Walter was a Windows user. He'd learned 
there were some good Windows ARM laptops these days. But at some 
point, it would be good if Walter had a machine to run it on.

Walter said the Windows backend would probably be the last step, 
primarily because he found the Windows ABI poorly documented and 
much more high-effort to get things working. He also didn't like 
working with the Microsoft SDK. It was excessively massive and 
complicated, and it was hard to find anything in it. It had too 
many directories and files, and he just didn't like messing 
around with it. That was also the reason Windows support was the 
last to get implemented for ImportC.

He said the Linux development tools were just so much better. 
They were easier to understand and oriented toward a command 
line, not a GUI. He found them much simpler to develop code on 
and much easier to understand what was happening. So he was going 
to defer the Microsoft problems to last.

Martin noted that DRuntime most likely needed work for Windows 
AArch64. Johan said that, indeed, LDC probably would not run on a 
Windows ARM laptop. It would be nice if we had some developers 
that had one to work on it. It wouldn't necessarily have to be 
Walter. Maybe one of the core contributors, or someone with skin 
in the game and the motivation to fix the final bits and pieces.

Dennis asked what Walter planned to do with the PR. Was he going 
to keep adding to it and merge the whole thing once the test 
suite passed, or was he going to merge a minimal working version 
and build on it?

Walter was aware that it was getting larger and larger, and there 
was no end to that in sight. He was constantly rebasing it so it 
didn't become hopelessly divergent. It was so large now that it 
was frankly impossible to review. He asked if Dennis thought it 
reasonable to simply mainline it even if it wasn't a fully 
functional backend yet. That would make it easier to manage and 
avoid it becoming impossible to merge while making future 
additions easier to review.

Dennis thought in any case it would be nice to have the flag and 
the skeleton that the actual code generation could build off of. 
Walter said in that case, he'd be happy to merge it if it passed 
the test suite. Dennis asked if there were any ARM tests in the 
test suite that actually ran the generated code. Walter said 
there were not.

Dennis asked if it was just testing against expected assembly, 
and Walter said that's what he was doing. He was doing visual 
checks of the assembly. The `-vasm` switch had turned out to be 
really useful for that. He compiled with `-vasm`, looked at the 
disassembled code, and compared it with what godbolt put out. 
He'd even take what godbolt emitted and put it into the 
disassembler as part of the test suite.

Dennis said he could take a look at it some time. He wanted to 
look at the code, but it wasn't something he'd be able to do in a 
single evening. Walter said that was exactly the problem, so he 
was all for merging it and continuing on from there.


Our October Monthly meeting took place the following Friday, July 
12th. Our next quarterly was on Friday, October 5th.
Dec 07
parent reply monkyyy <crazymonkyyy gmail.com> writes:
On Saturday, 7 December 2024 at 15:16:10 UTC, Mike Parker wrote:
 He said one thing that had been annoying was that the WASM 
 interface was basically POSIX, but the compiler didn't treat it 
 as such for versioning. He'd had to implement a lot of 
 versioned dummy code to get it to work. He would like to see 
 the compiler recognize WASM as POSIX.
I imagine he's learned the hard way by now but no, it uses posix names but its all a lie and you need coordination between html js and your code to even consider reading a file "correctly" and I believe all the different places where wasm can be require slightly different hacks to make it work. Its probably a bad idea to turn on whatever features as they will just be broken or worse, pretending to work until you implement something that actually uses it then youll play wack a mole for a long time and lets be honest your not going to find a full time wasm to even attempt to keep up with w3c's bullshit, much less make it nice and worth using, the least responsible standards committy on earth may just drop a years worth of work every 3 months for some rust "feature" no other language even understands.
Dec 07
parent reply Paulo Pinto <pjmlp progtools.org> writes:
On Saturday, 7 December 2024 at 17:53:22 UTC, monkyyy wrote:
 On Saturday, 7 December 2024 at 15:16:10 UTC, Mike Parker wrote:
 He said one thing that had been annoying was that the WASM 
 interface was basically POSIX, but the compiler didn't treat 
 it as such for versioning. He'd had to implement a lot of 
 versioned dummy code to get it to work. He would like to see 
 the compiler recognize WASM as POSIX.
I imagine he's learned the hard way by now but no, it uses posix names but its all a lie and you need coordination between html js and your code to even consider reading a file "correctly" and I believe all the different places where wasm can be require slightly different hacks to make it work. Its probably a bad idea to turn on whatever features as they will just be broken or worse, pretending to work until you implement something that actually uses it then youll play wack a mole for a long time and lets be honest your not going to find a full time wasm to even attempt to keep up with w3c's bullshit, much less make it nice and worth using, the least responsible standards committy on earth may just drop a years worth of work every 3 months for some rust "feature" no other language even understands.
Additionally that is now kind of stuck in some political turf, as the WebAssembly folks are moving into a CORBA/COM kind of approach with WebAssembly Component Model, and not all parties agree with this way forward, https://component-model.bytecodealliance.org/
Dec 12
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 12/12/2024 11:47 PM, Paulo Pinto wrote:
 Additionally that is now kind of stuck in some political turf, as the 
 WebAssembly folks are moving into a CORBA/COM kind of approach with 
 WebAssembly Component Model, and not all parties agree with this way 
 forward,
 
 https://component-model.bytecodealliance.org/
Things I do not find joy in reading: https://component-model.bytecodealliance.org/design/wit.html#identifiers Wish they went with UAX31, otherwise we'll end up in the confusing realm of needing algorithms like boot string where every compiler does its own thing.
Dec 12