D Language Foundation April 2024 Monthly Meeting Summary
Mike Parker
aldacron at gmail.com
Tue Jul 30 11:50:50 UTC 2024
The D Language Foundation's monthly meeting for April 2024 was
held on Friday the 12th. It lasted an hour and 20 minutes.
## The Attendees
The following people attended:
* Paul Backus
* Walter Bright
* Jonathan M. Davis
* Timon Gehr
* Dennis Korpel
* Átila Neves
* Mike Parker
* Robert Schadek
## The Summary
### Item 1: Phobos v3 CI
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.
### Item 2: @live
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.
And if we had to do callbacks... Javascript, Flutter, and C#
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.
### Item 3: Tuple unpacking
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.
### Item 4: DConf '24 updates
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.
### Extra: Editions/safe-by-default
Á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).)
## Conclusion
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.
More information about the Digitalmars-d-announce
mailing list