www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - D Language Foundation April 2024 Monthly Meeting Summary

reply Mike Parker <aldacron gmail.com> writes:
The D Language Foundation's monthly meeting for April 2024 was 
held on Friday the 12th. It lasted an hour and 20 minutes.



The following people attended:

* Paul Backus
* Walter Bright
* Jonathan M. Davis
* Timon Gehr
* Dennis Korpel
* Átila Neves
* Mike Parker
* Robert Schadek





Jonathan said Adam Wilson had set up [the Phobos v3 
repository](https://github.com/LightBender/phobos) to use dub. 
That wasn't a big deal since we weren't distributing it yet, but 
we hadn't yet agreed on how it would be built for distribution. 
Although there wasn't a lot of code there yet, it would be nice 
if the CI could run the tests on what was there so that we could 
catch breakage.

He'd tried to add the dub test stuff to the normal makefile 
targets to get it to run as part of the CI. It worked locally on 
his machine, but most of the test runners didn't have dub, so it 
didn't work in the repo. BuildKite did have dub, but it was 
failing there, too. He said that either the test runners needed 
to be updated to work with dub, and he didn't know how to do 
that, or the Phobos v3 build needed to be altered so it wasn't 
using dub.

Dennis said he had set up a `dub.sdl` to build DMD with dub and 
the CI had failed there, too. His solution was to make his own 
workflow, [a separate YAML file for GitHub 
Actions](https://github.com/dlang/dmd/blob/master/.github/workflows
build_with_dub.yml) which used the standard D community setup that installed
everything, including dub. He said he also didn't know the details of all the
CI workflows or how to integrate this neatly, so he was just kind of
improvising.

Jonathan said he'd tried to add the dub test stuff just to get it 
in there and building without mucking with all the makefile 
stuff. He expected that long term we wouldn't want to be using 
dub here, but he didn't know. He'd just wanted to get it working 
with minimal effort without spending time on building stuff he 
wasn't familiar with.

Dennis suggested it might be possible to just use `dmd -i -run` 
with a module that imported all the Phobos modules. That would 
probably work since it was just a collection of source files.

Jonathan said he would have to dig into that and figure it out.



Walter said that [the ownership/borrowing 
system](https://dlang.org/blog/2019/07/15/ownership-and-borrowing-in-d/),
` live`, was about two-thirds implemented. It had sat around for years with
little or zero interest. He'd set it aside because of all the DIP 1000 bugs.
DIP 1000 was required for it to work.

However, something had changed in the industry. The government 
had said that programs should be written in memory-safe 
languages. This was causing a shift away from C++ toward Rust. We 
didn't have a story there. We couldn't really say we were 
memory-safe, although we were 90 or 95% there with DIP 1000.

We had a preview switch that turned on the ` live` checks, but he 
felt that was preventing people from using it. It had taken him a 
while to figure out which switch it was, and as he was talking 
about it here he couldn't remember the name. Dennis said it was 
`-preview=dip1021`. Walter said that was it, and the issue was 
that DIP 1021 was a different DIP that wasn't about ` live`, but 
it was the switch that enabled it.

He said that ` live` didn't change any semantics. It only added 
an extra layer of checks on functions tagged with ` live`. So 
right now you could mark functions with ` live` all you wanted 
and nothing would happen until you turned the switch on. He felt 
the switch was a pointless barrier and should be made the default.

Historically, there had only been 15 or so bugs for ` live` and 
all but one had been fixed. In fixing a couple of them recently, 
he'd discovered a couple more gaps in what the ownership and 
borrowing system did. He was working on fixing them. He proposed 
that we turn on ` live` by default so people might be more 
inclined to try it and file bug reports on it.

In the long run, the point was that we needed D to be a 
memory-safe programming language. That was the most important 
thing. He noted that there had been repeated requests to do null 
tracking. There had been constant complaints about class 
references being default initialized to null, then someone would 
try to call a member function and get a segfault. Walter still 
believed that wasn't actually a problem, but the ` live` code 
could be enhanced to do null tracking. If it were on by default, 
then he'd be willing to make the enhancement. He'd implement it 
such that it would only trip if it were sure that a null 
reference was being made, and wouldn't trip in ambiguous cases.

He thought this was the last step to being able to say that D was 
a memory-safe language, and we'd be able to do it without the 
ugliness of Rust. He thought Rust was ugly to look at and that 
memory-safe code didn't need to be ugly.

Timon said that maybe we could enable it, but his issue was that 
` live` by itself didn't improve memory safety. Walter said he 
knew that was Timon's position, but he didn't understand it. He 
said that the cases it was supposed to work on, it *did* work on. 
No matter how convoluted your code, it correctly detected if 
you'd borrowed something or not and would give you errors if you 
didn't dispose of it before the end of the function. It did what 
it was supposed to do.

As Walter recalled, Timon wanted two kinds of 
pointers---ownership/borrowing pointers and GC pointers. Walter 
had objected to that based on how disruptive it would be to how 
the compiler worked internally.

He noted that Microsoft had created Managed C++, which had two 
kinds of pointers---GC pointers and non-GC pointers. Though they 
still maintained it, it had vanished from the conversation. He 
considered Managed C++ and their approach to be a failure because 
of it.

Timon said the general issue was that ` live` wasn't properly 
modular. It only added some checks. It didn't ensure invariants. 
To improve memory safety, you needed a type system to ensure 
invariants that improve memory safety. He thought we did have a 
memory-safe language and the best way to write memory-safe code 
today was to disable DIP 1000 and use the garbage collector. DIP 
1000 introduced additional cases of memory unsafety, so just 
disabling it and using the GC with ` safe` would enable memory 
safety.

Walter said it had been brought up before that DIP 1000 didn't 
work. Several bugs were filed. He and Dennis had fixed a long 
list of them and hadn't yet found one problem with DIP 1000 that 
couldn't be fixed.

Timon said that was a reflection of the current state. 
Eventually, maybe enabling DIP 1000 and using the GC when it 
didn't work would be the way forward. But ` live` didn't do 
anything in ` safe` code because ` safe` code was already memory 
safe.

Walter said ` safe` did not guarantee memory safety. What ` live` 
did was let you know if you malloced a pointer and never freed 
it. DIP 1000 couldn't help with that. Timon said you couldn't 
call `malloc` in ` safe` code, so that wasn't the context. Walter 
said he understood that D was memory-safe if you GC'ed 
everything, but we couldn't GC everything and have a systems 
programming language. To have memory safety and be a systems 
programming language, you had to track where the pointers came 
from and where they went. You couldn't free a pointer twice.

Timon said you needed to know those things, maybe, but ` live` 
didn't add this to ` safe`. It would do those checks, but it 
didn't ensure invariants. It wasn't because of bugs, but because 
it was a function attribute.

Walter said it worked within the function. Within the function, 
everything was checked by the ownership/borrowing rules and it 
worked. If you malloced a pointer twice, it would give you an 
error. If you malloced a pointer and didn't free it, it would 
give you an error. If you malloced a pointer and freed it twice, 
it would give you an error. If you malloced a pointer, freed it, 
and then used the pointer again, it would give you an error.

Timon said he agreed, but for example, C++ would give you a 
compiler error if you assigned an integer to a pointer. That 
didn't make it memory-safe. Walter said he didn't understand what 
was memory-unsafe about ` live`. Timon said it didn't improve 
safety guarantees. There was no sound checking. Walter said it 
guaranteed that you had to free anything you malloced.

Timon said you could use aliasing in some other part of the 
program. Walter said the more of your code you marked as ` live`, 
the more checking you would get. It was up to the programmer to 
decide which functions were checked. He noted that even Rust 
didn't have memory safety everywhere. Anything marked as unsafe 
wasn't checked.

Dennis said the premise of ` live` was that it added safety. That 
was just false. We already had a safe language per the spec if 
you ignored the implementation bugs, via ` safe` and the garbage 
collector, but you could do manual freeing. As the language was 
defined, manual freeing couldn't be annotated ` safe`.

So the argument that could be made for ` live` was that it made 
manual freeing possible in safe code. To do that, you had to 
properly prove that it satisfied the constraint that you couldn't 
call `free` in the wrong place and corrupt memory. With the 
current design, that wasn't the case. There were cases in ` safe 
 live` code where you could free a pointer allocated with a 
different allocator and have memory corruption that way, or in 
other cases where you called a non-` live` function from an 
` live` function and it would do something.

So with the current definition of ` safe  live`, it didn't add 
any safety. It only added checks to catch some mismatched 
`malloc` and `free` pairs. It didn't add to which code was safe 
code. We already had ` safe` for the garbage collected/stack 
allocated part of D, but not for the malloc/free part. There was 
a whole discussion to be had about how we could do that.

Walter said the malloc/free part was critical because that was 
part of what D was. If you couldn't do malloc/free, then...?

Dennis said it didn't have to be done by ` live`. It could be 
done by a container library or something. Walter said it 
couldn't. Dennis said that we should then explore ways to do it. 
He said Paul was working on that now, how to use allocator 
interfaces to create safe data structures.

Paul said that Walter had once written that C's biggest mistake 
was conflating arrays and pointers. When you passed an array to a 
function in C, the information about its length was discarded. 
Paul thought the fundamental issue with ` live` was a very 
similar mistake: if you passed a pointer from an ` live` function 
to a non-` live` function, then all of the information about its 
ownership status was discarded. That meant if you wanted a 
memory-safe program rather than just a single memory-safe 
function, then everything had to be ` live` or it wouldn't work. 
The consequence of that was that you'd then have to cut yourself 
off from the entire existing ecosystem of non-` live` code and 
start from scratch.

Walter said he didn't understand why. You could incrementally add 
ownership/borrowing checks to your code where and when you 
wanted. If you didn't add ` live`, you didn't get the checks. He 
didn't understand how you could get a memory-safe language just 
by fiddling with the allocators. You had to solve the problem.

Paul said it wasn't by fiddling with the allocators, but by 
having the containers do the ownership/borrowing checks. By using 
both `scope` (DIP 1000) and ` system` variables (DIP 1035) 
together, it was possible, ignoring implementation bugs, to write 
containers that manually allocated and freed memory and were safe 
because they used runtime checks to ensure that pointers could 
only be freed when they were not borrowed or aliased.

He had written code that did this. He had a work-in-progress 
implementation of a unique pointer in D that used these kinds of 
checks. There were some UX issues with it. You had to use 
callbacks in places. If you wanted to prevent references from 
escaping, you could pass a scope reference or pointer down the 
stack, but if you returned one up the stack, then it was game 
over. It could escape and there was nothing you could do about 
it, so you had to use callbacks to access the contents of the 
container, meaning either a function that you passed a lambda to 
or an `opApply`.

But it did work, modulo implementation bugs, and it worked using 
features that were already designed and partially implemented. 
And it worked in a way that was compatible with the entire 
existing ecosystem of D code, including existing ` safe` code, 
and did not require you to incrementally transition your entire 
program over to this new set of semantics to reap the benefits.

Walter said that was what C++ did. If you stuck with the C++ 
library, your memory was safe. But that wasn't acceptable. That 
just hadn't worked out in the real world.

Paul said that C++ had a unique pointer and a shared pointer, but 
it had no way to prevent you from holding onto a pointer to the 
memory managed by those objects and using them after that memory 
had been freed. With DIP 1000 and ` system` variables, it was 
possible to prevent ` safe` code from doing a use after free like 
that.

Walter asked, "How about failure to free?" Paul said that was the 
halting problem. Your program could enter an infinite loop and 
never call `free`. Walter brought up Rust, and Paul said Rust 
didn't do that. Rust allowed memory leaks, but they'd free memory 
in their destructors, so it was as reliable as their destructors 
were.

Walter said he took issue with that. When you reached the end of 
a function in Rust and had an owned pointer that hadn't been 
disposed of, you got an error. You got an error in ` live` 
functions, too, and he believed you got the same error in Rust. 
You couldn't just have an owner that ran off the end of the 
function. You had to do something with it.

Timon said that Rust had multiple pointer types. One was the 
standard pointer with the star. Those couldn't be accessed in 
safe Rust code at all. Those were the pointers that you malloced 
and freed. The safety of those operations was ensured by their 
library implementation. The users only got borrowed pointers out 
of that, and those pointers were returned before those library 
containers got destroyed. It wasn't clear-cut what was the 
library and what was the language, but that was what it did.

Walter thanked Timon for the explanation but said you still had 
to check that. He didn't think the language, by using RAII, was 
completely able to check that stuff. Timon said it had the borrow 
checker. It didn't check on plain pointers. ` live` checked on 
plain pointers. In Rust, plain pointers were unsafe territory.

Robert said everyone was wrong and were all talking past each 
other. Any academic arguments about this were irrelevant, and 
Walter's definition of a safe language didn't match the marketing 
hype of all the other safe languages. The biggest complaint Rust 
got as a memory-safe language was that it was too complicated. 

basically invented an async syntax to avoid callbacks because 
jQuery or JavaScript callbacks the way node.js did them was 
terrible.

We had to make it simple. If you had to know what a ` system` 
variable was, or a container, or had to write a callback, it was 
dead on arrival. And if it was so easy to get around the ` live` 
checking to call a function that wasn't marked ` live`, then we 
weren't adding anything. He thought the term "systems programming 
language" was also not what people wanted. There were always 
places where you had to do something unsafe to map a file to a 
CPU register or something, but 99.9999% of the time, nobody 
wanted to handle a pointer. At least, he would have never met 
anybody or hired anybody who wanted to shuffle pointers around. 
The world at this point was ruled by Python, and they didn't even 
have that concept.

He reiterated that we needed to make it simple. If he had to know 
` system` variables and functions annotated with ` live`, then 
no. He was just going to tell the person working on his project 
not to take the address of that thing, just pass a reference 
down, or make it a class, or a global array, and have a nice day.

Jonathan said that DIP 1000 alone already increased complexity 
considerably. That didn't mean we shouldn't have it, but he'd 
specifically avoided using it in anything he'd dealt with because 
it was too hard to understand as it was. So if we were worried 
about people being able to understand this so that they could 
easily use it, then DIP 1000 on its own was already too much.

For some people, the easiest was just going to be using the GC 
and not worrying about the rest of it. For a lot of stuff, that 
would be enough. He didn't know what we needed to do about 
`malloc` and `free`. He was fine just saying you'd have to use 
` trusted` with that stuff. He didn't know enough about all of 
this to say if we needed ` live` or not, but the complexity was 
already pretty high. He thought we'd have a problem getting 
people to actually use it no matter how good it was.

Walter said that having ` live` was a marketing point. His 
impression was that a lot of people who wrote Rust code didn't 
actually want to deal with the borrow checker, so they would just 
mark everything unsafe and then brag about their program being in 
Rust and everyone was happy with it. He thought that was a 
perfectly reasonable way to program: just don't worry about any 
of this stuff and write your code the way you want. But for the 
people who demanded this sort of protection, we needed to have a 
mechanism for it.

Átila thought ` live` had a few issues, but one of them was the 
focus on `malloc` and `free`. Nobody should be calling those 
anyway. Why would you be doing that? Just use a smart pointer, a 
container, or something. We needed to focus on whatever language 
changes were necessary to enable writing those types in a way 
that they couldn't be escaped, and not focus on whether they 
freed a thing or not.

Walter said he never understood smart pointers in C++. The layers 
and layers of templates with those things in C++ gave him a 
headache. So he was with Robert on that. He wasn't interested in 
the complexity.

Timon said he could accept the argument that Walter wanted to 
make a marketing point, but then we'd attract people who were 
fine with engaging in some sort of cargo cult. Walter said a 
cargo cult was chasing a false god. ` live` would actually work. 
Timon said it would do the checks, but it wouldn't give you the 
guarantees. He said Walter had started the conversation by 
talking about why the government wanted people to use memory-safe 
languages. Timon thought they were talking about the guarantees.

Robert said he'd bet Timon drinks forever that they weren't 
talking about guarantees. The word "should" was probably in there 
somewhere. If you had to build a drone and you didn't have the 
budget in your embedded CPU... There was always going to be that 
weird little thing that wasn't memory-safe because of reality.

Timon said that if you wanted to have ` live` as a linting tool 
for ` system` functions, that was fine. We could market it that 
way.

Robert thanked him. He said we should have safe by default. If 
you wanted a footgun, then maybe ` live` was a tool that would 
help you shoot off only one toe rather than the whole foot.

Timon said there was some wiggle room. Depending on how exactly 
we developed ` live`, either it didn't improve safe capabilities 
or it made it safe and sound.

Robert disagreed. If you could have more checks to give you more 
checks that were technically correct, then you had more. It 
wasn't removing anything at that point.

Timon said that was exactly right, you could have more checks. 
That was one of the options. But then that meant that less code 
was accepted. And the code that wasn't accepted was not 
memory-unsafe, because it was in an ` safe` function in the past.

Robert said it would still be theoretically possible to write 
unsafe code, but in practice, most things would be stopped by the 
hammer.

Paul said if the purpose of ` live` was to exist for marketing 
and box-ticking, then he couldn't make an argument against it. 
But he wanted to point out that there were a lot of things on our 
TODO list, a lot of ongoing projects, things we could be spending 
our time and effort on. Maybe a feature whose only purpose was to 
tick a box on a marketing checklist wasn't the best place to 
allocate our resources if we had to choose.

Walter said he'd set it aside for four years to work on other 
issues. He had thought ImportC was a much more important project, 
and he still believed it, but it was working now. There was also 
the long list of DIP 1000 problems, and he thought that was under 
control now. But with the government declaration, he believed we 
needed something to reassure people that they could write 
memory-safe code in D and that they didn't necessarily have to 
use the GC to do it.

Paul said he would question if DIP 1000 was really taken care of. 
He had been working on code that attempted to rely on it and had 
run into some serious issues with it. In its current state, he 
thought nobody should be using it for anything outside of 
experimental or toy code.

Walter asked if Paul had reported the issues he'd encountered. 
Paul said he had. He'd talked to Dennis about some of them, and 
Dennis had told him that DIP 1000 had been put on pause until 
editions were figured out.

Dennis said that fixing those issues was hard when some of the 
existing BuildKite projects were already relying on those DIP 
1000 quirks. It was hard to navigate around the breakage with 
those fixes. Editions would help, but that was kind of slowly 
trotting along.

Paul thought we should remove any BuildKite tests that relied on 
DIP 1000. It was an unstable feature. If you depended on an 
unstable feature, your code was going to break. We should not and 
could not guarantee that code would continue to build.

Dennis said we had encouraged people to use DIP 1000 for the new 
safety. If they had put in all that effort and then we just 
pulled the rug out from under them... He said it was used 
extensively in the Mir container types.

Paul said it had been a mistake to encourage people to use it. We 
should just say we're sorry. The longer we waited to bite the 
bullet, the worse it was going to be.

At this point, I suggested we table this topic for future 
discussion at a planning session or something. Átila was in 
Seattle, and he and Walter were going to talk about it that 
evening. He didn't expect they'd resolve anything, but he hoped 
to make progress. I asked them to let me know when they were 
ready to call a broader meeting about it.

__Addendum__

Walter said that Robert had previously pitched suggestions on 
several features to remove or block in ` safe` code and asked 
Robert to send him a list of all of them.

Átila recalled that he'd posted something about this in the 
forums and that Paul had replied with some issues about it, but 
he couldn't remember the details. Paul said that whether we ended 
up heading in Robert's desired direction of making ` safe` more 
restrictive, or the current direction with DIP 1000 and patching 
all the holes with it and ` safe` by adding new features, either 
way was going to be disruptive and break existing code.

He said that one of the things he liked about D was its power and 
expressiveness. If the decision were up to him, he'd choose the 
direction that made it more powerful and expressive rather than 
less. He emphasized that this was just his opinion and he didn't 
speak for everyone. Ultimately, the final decision would be with 
Walter and Átila.

He added that he could see the merit in Robert's position. In 
working on an ` safe` container library and implementing code for 
the callback API, he could see how ugly it was. It worked, but it 
wasn't pretty. He would love it if there were a way to make it 
pretty without a ton of complexity.

I reminded everyone that part of our vision statement was "to 
enable the realization of ideas by shifting the way programmers 
think." That was our yardstick. If any of this stuff aligned with 
that, then we should continue considering it. Otherwise, we 
should discuss if we really needed it. I asked everyone to keep 
that in mind since we'd all gone in on adhering to a vision 
statement.

Before we moved on, Walter let Timon know that although he was 
arguing with Timon on this, he appreciated Timon's perspective 
and insight, and valued his input. Timon said he wasn't arguing 
to be annoying, but because there was a difference of opinion. 
Walter just wanted to make sure Timon didn't get the wrong 
impression and think his opinion wasn't valued.



Timon said that since DConf Online, he'd gotten tuple unpacking 
to pass the compiler tests. Compilation tests now sometimes 
failed in different ways, but the others were passing. Tuple 
unpacking now worked inside functions and foreach statements.



I told everyone that I'd abandoned my hopes to find a sponsor for 
BeerConf at DConf this year. The per night cost for a pub hire 
was prohibitively expensive. Last year had been much more 
expensive than 2022, so it wasn't feasible to do it then. This 
year things were even higher. The cheapest we could find was 
£5500 for three nights. If I were going to ask any D shops for 
that kind of money, it would be much better spent if we put it 
into speaker/staff reimbursements. Especially since travel and 
lodging expenses were up significantly more this year over last 
year.

I explained that we had a minimum revenue target every year to 
cover at least 40% of the reimbursements. Symmetry covered the 
rest as part of their overall budget and typically expected to 
pay no more than 60%. Ideally, we'd be able to pay 100% of 
reimbursements from revenue, but that had never happened.

(__UPDATE__: Later, I was contacted by an anonymous donor looking 
to sponsor BeerConf this year. The donation was enough to cover 
one night, so on September 17th, we'll be able to have a few free 
rounds at [the Trinity Bell on Mitre 
Street](https://dconf.org/2024/index.html#beerconf), not too far 
from the venue. If you're there, please raise a glass to our 
anonymous donor!

Additionally, we received a significant amount of funding from 
Weka, with additional support from Decard. I'm also expecting to 
finalize some support from Funkwerk soon. With this support, we 
were able to significantly exceed our minimum revenue target, 
which in turn allowed us to set the General registration rate to 
the Early-Bird rate. Massive thanks to Weka, Decard, and Funkwerk 
for their support!)

Next, I noted that all expenses were up this year. The venue was 
more expensive because we were hosting the conference in 
September. That wasn't not part of peak travel season, but spring 
and fall were peak conference seasons. Other costs were up, too, 
due to general inflation. Even the cost of the swag was up.

Because of this, in a meeting with the Symmetry DConf liaison and 
our event planner, we discussed the idea of eliminating all the 
swag except the t-shirts. I'd heard from some people that they 
ended up losing or discarding their bags, and some regular 
attendees had asked me if we could do something other than coffee 
mugs.

I asked everyone what they thought: should we just go with 
t-shirts only? Walter said he had the impression that the 
t-shirts were all that most people cared about anyway. Jonathan 
said he used the mugs, but he had a ton of mugs in general so 
wouldn't miss them. Robert said his wife would be happy he wasn't 
adding another mug to the cupboard. He liked them, but if he 
wanted another D mug, he could just order it online. I noted that 
most of mine had been broken, but I didn't know if I even had any 
of the swag bags anymore. I might have thrown them out.

In the end, no one objected to having t-shirts only. So we'll 
give it a try this year and see what the feedback is.



Átila said he'd been reviewing feedback on an email thread about 
his editions proposal. The original idea had been that editions 
were to be opt-in to avoid breakage. The default would be to 
always compile old code and only switch to an edition when it was 
part of the module declaration. But the majority of the feedback 
was that the compiler should always use the new edition and old 
code should be compiled via a compiler switch.

He was stuck on how to proceed. If he abandoned the original plan 
and went with always using the latest as default, then why should 
we even have the edition attribute for the module declaration? At 
that point, since we'd require a compiler switch to compile old 
code, why not just rely on compiler switches for the editions? He 
also felt that if we went with the latest editon as the default, 
then we'd be defeating our goal of avoiding breakage, which was 
the whole point of editions in the first place.

Jonathan said that the advantage of the module declaration was 
that you could just look at the code and know which edition it 
was intended to work with. Then the purpose of the compiler 
switch would be just to set what the default edition was.

Átila noted that we relied on compiler switches for previews, and 
it turned out that people rarely used them and complained anyway.

Jonathan said he agreed with those who insisted we needed to 
default to the latest edition if we didn't want this to be a 
mess, and noted that was going to require some support in dub. If 
we didn't do that, then we'd just end up with people compiling 
with the default old edition and complaining that we didn't use 
the latest one by default.

Átila said they might do that, but they also might complain 
because their old code broke with the default edition and they 
had to use a switch to make it work. We just didn't know. 
Jonathan said if the latest wasn't the default, we'd be punishing 
people who were trying to do the right thing by shoving them into 
the old language by default.

Átila said he just wasn't sure what to think of this or what to 
propose to the community at this point. He understood the 
arguments on both sides, but he didn't know which was the best 
way forward. Jonathan noted that Adam liked to point out that no 
other language defaulted to the oldest version with this stuff. 
Átila countered with C++.

I suggested that a way to break the logjam might be to have a new 
module declaration. Then when the compiler saw the old `module 
foo`, it would use the old edition, but the new-stye declarations 
would trigger the latest edition.

Átila said that was the proposal he put forth. I clarified that I 
wasn't talking about an annotation. The problem with that was 
that you had to tell people that they couldn't get new features 
unless they annotated the module declaration. I was talking about 
a completely new keyword. Tutorials, docs and such would be 
updated to teach the new keyword instead of the old `module`. 
Then it would become "all new D code uses this module 
declaration" rather than "you have to use this annotation on your 
module declaration to get the newest features".

Dennis said he thought that only new features that introduced 
breaking changes would require editions. Non-breaking features 
wouldn't require you to have editions in your module. Átila said 
that was the case. Rust backported non-breaking features, too, so 
that was fine. But something like safe-by-default would have to 
be in an edition.

Átila noted that since he'd been stuck with the editions 
proposal, he'd written a safe-by-default DIP. He said he'd send 
it to us for some feedback. Basically, ` safe` was the default 
unless a function had no body. In that case, you had to have 
either ` safe`, ` system`, or ` trusted` on it or it wouldn't 
compile.

Jonathan asked if it was restricted to `extern(D)` functions. 
Átila said it wasn't. He said that `extern(D/C/C++)` only 
affected linkage and calling convention. People assumed that it 
meant the function was written in the respective language, but it 
didn't have to be. An `extern(C)` function could be a callback 
for C written in D, for example. If it was, then the compiler 
could verify if it was ` safe`. Linkage didn't enter into it. It 
was just a question of whether it had a body.

Dennis said that linkage kind of did come into it because ` safe` 
was mangled in the name of `extern(D)` functions to prevent you 
from linking to an ` system` function. Átila agreed but said 
that, just to make it simpler, if a function had no body it 
wouldn't compile without one of the three safety annotations.

Timon said that if you could add ` safe` to an `extern(C)` 
declaration with no body, then it would become ungreppable. Átila 
said he assumed they'd use ` trusted` in that case. But who knew 
what people would do? If they did use ` safe` there, it was on 
them because it was explicitly their declaration.

Timon said that the selling point of ` trusted` was that the 
language was defined such that when you got a memory safety 
issue, it was a compiler bug or an issue with something that was 
annotated as ` trusted`. If you allowed ` safe` on `extern(C)`...

Jonathan said that all we had to do was to disallow ` safe` on 
`extern(C)`. Timon agreed and said you could use ` trusted`. It 
had the same meaning in terms of the interface. The only 
difference between it and ` safe` was what it did to the function 
body.

Átila said that was a good point. That was the kind of thing that 
would come from feedback anyway.

Jonathan said that the fact that ` safe` and ` trusted` had 
different mangling was undesirable, though he didn't know if it 
was a big enough issue to change it. It didn't add any benefit, 
as it was the checking of the body that made the difference.

This led to a debate about whether it mattered if a function 
prototype was declared ` safe` or ` trusted`. A prototype was 
just an interface, and from that perspective, there was no 
difference. In both cases, the interface was safe.

Jonathan said that if he could suggest one thing, it would be to 
eliminate the mangling for ` safe` functions, then there would be 
no linking issues between ` safe` and ` trusted`. This mattered, 
for example, for delegates. If you used a delegate, you shouldn't 
have to care if it was ` safe` or ` trusted` because the 
interface was exactly the same, but you ended up having to care 
because of mangling.

Timon said what could be done was to allow ` trusted` function 
pointers and delegate types to decay to ` safe`. Walter said that 
sounded like a good idea on first blush.

Dennis brought up a compiler bug with mangling that existed 
because we had ` system` functions and default functions, which 
were ` system` by default. But if you called `getAttributes` on a 
function, whether you got ` system` or not depended on which one 
the compiler saw first, because ` system` functions were mangled 
with it and default functions were not.

Walter said that was a good point and was glad Dennis had brought 
it up, as he'd overlooked it. The entire type system relied on 
the concept that if they mangled the same, then they were the 
same.

Walter thought Timon's suggestion would help with Jonathan's 
issue. He suggested Jonathan try it out and see if it would work.

(Update: At the end of May, Átila posted threads in the DIP Ideas 
forum for [his Editions 
proposal](https://forum.dlang.org/thread/tskwospngntbnqiuxbag forum.dlang.org)
and [safe by default](https://forum.dlang.org/thread/uhmntnhqdwomdallfroo forum.dlang.org).)



At this point, the meeting was over, but we spent the next few 
minutes chatting about some interesting topics that came up 
through small talk as we were winding down. We held our next 
meeting on May 10.
Jul 30
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Tuesday, 30 July 2024 at 11:50:50 UTC, Mike Parker wrote:
 The D Language Foundation's monthly meeting for April 2024 was 
 held on Friday the 12th. It lasted an hour and 20 minutes.
 [snip]
Thanks for the detailed write-up!
Jul 30
prev sibling next sibling parent Abdulhaq <alynch4048 gmail.com> writes:
On Tuesday, 30 July 2024 at 11:50:50 UTC, Mike Parker wrote:
 The D Language Foundation's monthly meeting for April 2024 was 
 held on Friday the 12th. It lasted an hour and 20 minutes.
very interesting thanks
Jul 30
prev sibling next sibling parent An Pham <home home.com> writes:
 I suggested that a way to break the logjam might be to have a 
 new module declaration. Then when the compiler saw the old 
 `module foo`, it would use the old edition, but the new-stye 
 declarations would trigger the latest edition.

 [...]
Suggest to add setting to sc.ini for default edition (only affect module without edition attribute), DefaultEdition=Latest For old codes and failed to compile, add a bold suggestion to edit sc.ini and change it to DefaultEdition=
Jul 30
prev sibling next sibling parent reply Dukc <ajieskola gmail.com> writes:
Mike Parker kirjoitti 30.7.2024 klo 14.50:
 The D Language Foundation's monthly meeting for April 2024 was held on 
 Friday the 12th. It lasted an hour and 20 minutes.
 
Wow, this has a lot to comment on!
 Historically, there had only been 15 or so bugs for ` live` and all but 
 one had been fixed. In fixing a couple of them recently, he'd discovered 
 a couple more gaps in what the ownership and borrowing system did. He 
 was working on fixing them. He proposed that we turn on ` live` by 
 default so people might be more inclined to try it and file bug reports 
 on it.
Unfortunately, this is likely only the tip of an iceberg. I don't think many people currently use ` live` since it has so few use cases. Hence bugs likely remain under the surface.
 He noted that Microsoft had created Managed C++, which had two kinds of 
 pointers---GC pointers and non-GC pointers. Though they still maintained 
 it, it had vanished from the conversation. He considered Managed C++ and 
 their approach to be a failure because of it.
There's a much better study case for this than Managed C++. Namely, Nim, probably the closest competitor of D. It also has different types for GC-managed and manually allocated pointers, unless my memory completely betrays me.
 
 He thought we did have a memory-safe language and 
 the best way to write memory-safe code today was to disable DIP 1000 and 
 use the garbage collector. DIP 1000 introduced additional cases of 
 memory unsafety, so just disabling it and using the GC with ` safe` 
 would enable memory safety.
I though it was vice-versa - the language is unsafe *without* dip1000. Or does Timon mean implementation bugs in it? But I do agree that it's best to program mostly like DIP1000 didn't exists and just rely on the GC. DIP1000 is there to catch the case where you accidentally return a self-pointer from a member function or a slice of your static array on stack.
 
 Dennis said it didn't have to be done by ` live`. It could be done by a 
 container library or something. Walter said it couldn't. Dennis said 
 that we should then explore ways to do it. He said Paul was working on 
 that now, how to use allocator interfaces to create safe data structures.
Don't you remember? Timon [has already shown](https://forum.dlang.org/post/tr9j1h$1fvd$1 digitalmars.com) it can be done.
 
 Walter said he didn't understand why. You could incrementally add 
 ownership/borrowing checks to your code where and when you wanted. If 
 you didn't add ` live`, you didn't get the checks. He didn't understand 
 how you could get a memory-safe language just by fiddling with the 
 allocators. You had to solve the problem.
To see why, try to write an userspace function that manually mallocates and frees. You can write only general-purpose ` trusted` and ` system` functions - meaning, something that could potentially get accepted to Phobos. All code tailored to the use case of the user needs to be 100% ` safe`. You may freely use or not use ` live` on any function as you see fit. If I'm on the map here, this can only be accomplished with Timon's trick I linked to, and it doesn't use ` live` at all. ` live` doesn't provide any additional means to do this.
 Robert said everyone was wrong and were all talking past each other. Any 
 academic arguments about this were irrelevant, and Walter's definition 
 of a safe language didn't match the marketing hype of all the other safe 
 languages. The biggest complaint Rust got as a memory-safe language was 
 that it was too complicated. And if we had to do callbacks...
This is an important point, but I have a slightly different take. Any way these issues are going to be fixed (if they are to be) must stay out of the way of those who don't care. That is, if you happily let GC to do memory management for you, or are happy to manually review your mallocations and frees accepting the risks, your life must not get any more complicated. But if you want to have it all - both memory safety and no gc - that's a complex problem by definition. You can't expect to do that without a significant learning curve for your tool.
 Paul thought we should remove any BuildKite tests that relied on DIP 
 1000. It was an unstable feature. If you depended on an unstable 
 feature, your code was going to break. We should not and could not 
 guarantee that code would continue to build.
Please don't. What's wrong with keeping DIP1000 optional until we have editions, and making it the default in the next edition? That way no-one has to migrate if they can't.
 He said that one of the things he liked about D was its power and 
 expressiveness. If the decision were up to him, he'd choose the 
 direction that made it more powerful and expressive rather than less. He 
 emphasized that this was just his opinion and he didn't speak for 
 everyone. Ultimately, the final decision would be with Walter and Átila.
I also suggest this. Not because Robert's way would be worse than DIP1000 tricks, but because DIP1000 is a strict superset of Roberts proposal. You can totally keep DIP1000 as it exists enabled and program with no `scope` or `return` usage.
 Átila said they might do that, but they also might complain because 
 their old code broke with the default edition and they had to use a 
 switch to make it work.
That's the case with pretty much anything. If I leave some work aside for a few years, install newer versions of the compilers and libraries I was using and then open up my work again, it's pretty likely I will have to open the docs and see how I'll migrate my work, regardless of the language/libraries. If the docs say "just add edition declaration to top of your file, or use a compiler switch", I'm actually lucky. It isn't realistic to expect better from any language or library that is still being developed.
 Dennis brought up a compiler bug with mangling that existed because we 
 had ` system` functions and default functions, which were ` system` by 
 default. But if you called `getAttributes` on a function, whether you 
 got ` system` or not depended on which one the compiler saw first, 
 because ` system` functions were mangled with it and default functions 
 were not.
Maybe related to https://issues.dlang.org/show_bug.cgi?id=24003 ?
Jul 31
next sibling parent Dennis <dkorpel gmail.com> writes:
On Wednesday, 31 July 2024 at 08:15:22 UTC, Dukc wrote:
 Paul thought we should remove any BuildKite tests that relied 
 on DIP 1000. It was an unstable feature. If you depended on an 
 unstable feature, your code was going to break. We should not 
 and could not guarantee that code would continue to build.
Please don't. What's wrong with keeping DIP1000 optional until we have editions, and making it the default in the next edition? That way no-one has to migrate if they can't.
There's nothing wrong with that, it's even the current situation. But that doesn't change the Buildkite situation. To clarify, the problem is that some dub projects only compile with `dflags "-preview=dip1000"` and that any DMD pull request fixing DIP1000 bugs must ensure those dub projects continue to build with `-preview=dip1000`, even when they rely on those bugs.
 But if you called `getAttributes` on a function, whether you 
 got ` system` or not depended on which one the compiler saw 
 first, because ` system` functions were mangled with it and 
 default functions were not.
Maybe related to https://issues.dlang.org/show_bug.cgi?id=24003 ?
It's similar, but not related. Both issues are rooted in the type mangle not being a complete description of the type, but the mangle is still being used for equality. Therefore two types with slight differences may appear equal to the compiler. But in one case, the missing information is 'scope is inferred', and in the other situation, the missing information is ' system is explicit / default'. The summary is not entirely accurate by the way:
 because ` system` functions were mangled with it and default 
 functions were not.
It should be:
 because ` system` functions and default functions are mangled 
 exactly the same.
Jul 31
prev sibling parent reply Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, July 31, 2024 2:15:22 AM MDT Dukc via Digitalmars-d-announce 
wrote:
 Mike Parker kirjoitti 30.7.2024 klo 14.50:
 He thought we did have a memory-safe language and
 the best way to write memory-safe code today was to disable DIP 1000 and
 use the garbage collector. DIP 1000 introduced additional cases of
 memory unsafety, so just disabling it and using the GC with ` safe`
 would enable memory safety.
I though it was vice-versa - the language is unsafe *without* dip1000. Or does Timon mean implementation bugs in it? But I do agree that it's best to program mostly like DIP1000 didn't exists and just rely on the GC. DIP1000 is there to catch the case where you accidentally return a self-pointer from a member function or a slice of your static array on stack.
DIP 1000 is attempting to make more stuff safe than it is now - particularly with regards to getting pointers to non-GC-allocated memory and having the compiler verify that they don't escape. So, with DIP 1000, less code has to be trusted, but it's not at all necessary to have safe code. DIP 1000 is completely unnecessary if we take the stance that if you want safe, you use the GC, and any code that you have which can't do that for some reason, you vet and mark as trusted. The whole reason that DIP 1000 and live and the like come into play is basically because Walter wants to try to make dealing with malloc-ed memory safe, but the cost in terms of language complexity is enormous (and it doesn't really solve the problem anyway, much as it does reduce it). So, DIP 1000 helps, but some of us think that it's far too complex given what it costs, and it's definitely not required to have a memory safe language. It's just that we need it (or something which fulfills a similar role) in order to make more stuff safe (rather than trusted) than we can currently do. Some stuff is going to need to be vetted by programmers and marked with trusted no matter what we do. The problem with slicing static arrays does exist without DIP 1000, but that can be solved by actually treating it as system like it should be (since it's basically just a different syntax for taking the address of a local variable for a specific type of variable). Removing implicit slicing of static arrays also improves the situation since then you don't get surprises where you're doing something system without realizing it. DIP 1000 is not required to solve that problem. Similarly, if there are any other cases where safe code is not currently guaranteed to be memory safe, it's either a bug in the implementation or in the design. DIP 1000 is a way to add more to what can be automatically treated as safe. It's not a way to make a language that isn't memory safe be memory safe. And it's primarily of value for folks who are actively trying to avoid the GC. - Jonathan M Davis
Jul 31
next sibling parent reply Dukc <ajieskola gmail.com> writes:
Jonathan M Davis kirjoitti 31.7.2024 klo 19.00:
 The problem with slicing static arrays does exist without DIP 1000, but that
 can be solved by actually treating it as  system like it should be (since
 it's basically just a different syntax for taking the address of a local
 variable for a specific type of variable). Removing implicit slicing of
 static arrays also improves the situation since then you don't get surprises
 where you're doing something  system without realizing it. DIP 1000 is not
 required to solve that problem.
We also need to disable taking a pointer of a struct field, if that struct is local or `ref` (including the `this` `ref`). But adding that, yes, works. This is exactly what Robert proposed at last DConf. I'm going to call his proposal Simple Safe D as per the title of the talk. It would keep the language as simple as it's without DIP1000 and would be memory safe, but it would break existing code just as hard as DIP1000 does. Plus, nothing in DIP1000 forces you to use it's extra features compared to Simple Safe D. You can avoid the compiler complaining by simply using the GC either way.
Jul 31
parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
On Wednesday, July 31, 2024 12:50:39 PM MDT Dukc via Digitalmars-d-announce 
wrote:
 Jonathan M Davis kirjoitti 31.7.2024 klo 19.00:
 The problem with slicing static arrays does exist without DIP 1000, but
 that can be solved by actually treating it as  system like it should be
 (since it's basically just a different syntax for taking the address of a
 local variable for a specific type of variable). Removing implicit
 slicing of static arrays also improves the situation since then you don't
 get surprises where you're doing something  system without realizing it.
 DIP 1000 is not required to solve that problem.
We also need to disable taking a pointer of a struct field, if that struct is local or `ref` (including the `this` `ref`). But adding that, yes, works. This is exactly what Robert proposed at last DConf. I'm going to call his proposal Simple Safe D as per the title of the talk. It would keep the language as simple as it's without DIP1000 and would be memory safe, but it would break existing code just as hard as DIP1000 does. Plus, nothing in DIP1000 forces you to use it's extra features compared to Simple Safe D. You can avoid the compiler complaining by simply using the GC either way.
Not really, since with DIP 1000, the compiler infers scope in some cases, and then you're forced to deal with it whether you like it or not. Even though I don't normally use DIP 1000, I've found that in the cases where I've tried, I inevitably get cryptic complaints that I have to figure out how to fix with regards to scope (which is particularly annoying with templated code). Either way, my big problem with DIP 1000 is simply that it adds a ton of complexity to the language, and if that complexity is there, I'm going to have to deal with it at some point unless I'm only writing code for myself and never interact with anyone else's code (which obviously isn't realistic, especially if I use D professionally). I don't believe that that complexity pays for itself, and honestly, if it becomes the default, I'm going to be tempted to just slap system on everything and give up on safe entirely, because I simply don't want to deal with it - but even then, that won't work when dealing with code that I don't write. - Jonathan M Davis
Jul 31
prev sibling parent Sebastiaan Koppe <mail skoppe.eu> writes:
On Wednesday, 31 July 2024 at 16:00:21 UTC, Jonathan M Davis 
wrote:
 DIP 1000 is completely unnecessary if we take the stance that 
 if you want  safe, you use the GC, and any code that you have 
 which can't do that for some reason, you vet and mark as 
  trusted.
Unfortunately that leads to certain patterns that are safe using dip1000 to now be trusted. Which might cascade into surrounding code needing to be trusted as well. Overall it's a loss. I understand not everyone uses those patterns, which are mostly focused on ownership and lifetime, but I have found them to enable so called pit-of-success apis more than anything else. Contrast that with more 'prescriptive' apis that for instance require a certain ordering of calls or require certain functions to be called at certain points, which are far easier to use incorrectly. Plus they often fail/assert at runtime.
 The whole reason that DIP 1000 and  live and the like come into 
 play is basically because Walter wants to try to make dealing 
 with malloc-ed memory  safe
Don't forget the stack. Being able to safely use references to the stack brings at least as much value.
 but the cost in terms of language complexity is enormous (and 
 it doesn't really solve the problem anyway, much as it does 
 reduce it). So, DIP 1000 helps, but some of us think that it's 
 far too complex given what it costs
The only two issues I have with dip1000 is that it a) sometimes requires its attributes in seemingly unrelated code, and b) can require some workarounds for its imperfect (practical?) tracking. Overall though, I have found it is a natural conclusion when you combine lexical lifetimes and references/borrows.
Jul 31
prev sibling parent Anonymouse <zorael gmail.com> writes:
On Tuesday, 30 July 2024 at 11:50:50 UTC, Mike Parker wrote:
 [...]
Thanks!
Jul 31