DLF September 2023 Monthly Meeting Summary
matheus
matheus at gmail.com
Mon Nov 13 04:47:42 UTC 2023
On Monday, 13 November 2023 at 04:46:44 UTC, matheus wrote:
> ...
Part 3:
Átila
Átila said he'd asked Roy after DConf if he wanted to write a
spec for the new shared semantics but hadn't yet received a
reply. He thought we could go ahead with it anyway, as it's
probably going to be obvious in all the cases what we should do.
He'd also been thinking about Robert's suggestions regarding safe
code, and the more he'd done so, the more they made sense. He
didn't think we needed to wait for editions, because then we
could solve all the problems we've had with DIP 1000, possibly in
one fell swoop. The whole issue was we were making people have to
add scope everywhere because they use @safe, even if the
functions weren't doing anything "unscopey". They wouldn't have
to anymore because it would only apply to @trusted. He thought we
should go ahead with that, too.
Another thing: he'd been trying to play around with Timon's idea
of pointers that have a compile-time enum saying if they're
isolated or not. He wanted to do a proof of concept with a vector
type and some allocators to see what that looks like. That might
inform some decisions on how to add isolated to the language.
He'd also been thinking about how we could do editions.
I brought up an email Átila had sent recently about what features
should go in the next edition. I suggested that's not what we
need to be thinking about right now. We should first define
exactly how editions were going to be implemented. For example,
Walter had suggested the approach of attaching editions to module
declarations. There are other possibilities. So we need to define
what that looks like first. We should also be thinking about
which features we need to have stabilized in the current
language, which is going to be the default edition. What's broken
now that we're not going to fix now, but want to defer until the
first new edition?
Átila agreed. He said he'd wanted to know what we could maybe do
with the new edition so that it could inform what potential
issues could arise rather than dealing with it in the abstract.
It's more because of that. Not even, "that's what we're going to
do", but "what would we do if we could do anything" so that we
could think of what could go wrong.
I thought this should be a high priority for us. I proposed that
we put it on the agenda of our next planning session. Everyone
agreed.
(SPOILER: I'll post the September planning update a day or so
after this summary, but in that session, we agreed that Átila
would write up the proposal for editions by November 1st. We've
since extended that to December.)
Before yielding his time, Átila said he'd like to write a program
that fetches all of the dub packages and checks which ones still
built so he could get a list of stuff we need to test the kinds
of modifications like the shared and safe stuff, along with as
many future dub packages as possible, instead of the
hand-selected, curated list we have now.
Dennis thought even Phobos would break. He said that DIP 1000 was
not a breaking change. The breaking change was fixing the accepts
invalid bug that, so far, slicing a local static array has been
allowed. Robert's proposal was strictly more breakage than DIP
1000.
Átila said he understood that, but that code was obviously wrong
anyway. The code was broken. It's just that the compiler didn't
tell people. And the issue with DIP 1000 was adoption. The issue
with that was having to add scope everywhere.
I said that's the kind of thing I was talking about earlier. If
fixing shared or scope or anything was going to break a lot of
code, shouldn't we defer fixing them to a new edition and not do
it in the default language? Walter said DIP 1000 clearly had to
be in an edition.
Átila said, "Okay." But the shared thing is a no-brainer. The
code is completely wrong and we're not going to break anything by
lowering it to atomics. Walter agreed.
Timon asked if the idea is to do operations on shared variables
atomically. Walter said yes, for the ones where the CPU supports
an atomic operation. If the CPU doesn't support an atomic
operation on a variable, then it will not be allowed. It varies
by target.
Timon said yes, but an atomic operation is not the only way to
synchronize something. Átila said that's true, but the thing is,
there's always an opt-out by casting away shared yourself. If
you're going to do something to shared directly, you should
either pass it to a function that takes shared, or cast it away
and lock a mutex, or whatever you want.
Timon brought up Manu's push to just reject all of those
operations. Átila said that doesn't work. He'd been trying to fix
it this year and it's been one bug after another. Timon asked
what the issue with that was. Átila said there were many, but
gave one example: synchronized(mutex) doesn't compile with
-preview=nosharedaccess because you're accessing the mutex. The
runtime doesn't build with it and Phobos won't either. He'd been
trying to plug the holes and he realized at DConf that it's
better not to try to do that at all. Instead, just lower it to an
atomic in every one of those cases. If it doesn't compile, then
it doesn't compile. What are you trying to do with it anyway?
Walter told Timon that the problem was you couldn't pass a shared
value as an argument. If you've created a shared pointer to
something, you can't do anything with it because it's shared. If
you want to access the shared pointer, you have to pass it by
reference to std.atomic. However, there are instructions on the
CPU to atomically load a pointer type and other basic types. Why
not take advantage of that and allow shared operations when the
target CPU can support them directly?
Timon said it seems that we'll always synchronize. Átila said
that's better than the world right now. And again, if that's the
case and your profile shows that's your problem, cast shared away.
Walter said it's also less efficient to always be calling the
std.atomic functions when you can just use the CPU instructions
if it has them. Timon said it seems the solution to that should
be intrinsics. The proposal seems like intrinsics but with nicer
syntax. He thought there were some decisions about how to do the
synchronization exactly that you're kind of locking this default
syntax into when you do this.
Átila said the default is to do something sensible. If you want
to do something else, you can. Timon said what is sensible
semantics for your atomic load and store may depend on the
context. Átila agreed, but for most cases, it's going to be
sequential consistency. Again, if you want something else, then
you use something else. If you explicitly say, "atomic load with
something else", then that's fine. That's what happens. You
should still be able to write code that does explicit atomic
load, store, fetch, add, whatever, and it should just work. It
won't add to that, because then we would have failed.
Timon said it could just contribute to the confusion because the
code will do some synchronization stuff implicitly, but you have
to think about it from, like, both threads if they're
participating in it. If it's implicit, you kind of don't see it
in code anymore. To him, that's a less good solution than having
it fail compilation if you don't do it right.
Walter said it's the same issue we have with vector instructions.
If the instruction exists for the operation you requested in the
code, the compiler will generate the vector instruction for you.
If the instruction doesn't exist on the target CPU, the compiler
will fail to compile and you get to decide what alternate path
you want to take. So what it means is that if it compiles, it
will work. If it fails to compile on your target machine, you're
going to have to figure out a workaround for it.
Walter continued, saying that if the CPU has instructions to do
an atomic load of an integer, the compiler will support that and
it will give you atomic loads. If you're compiling for a CPU that
does not support atomic loads of an integer, it will fail to
compile. This is exactly the way vector instructions work. He
thought we'd been successful with that. He's happy with it.
He said that means that when you move to different platforms,
maybe your shared code will break, and maybe not. But that's kind
of how it should be, because shared is implicitly wrapped up with
how the CPU is constructed. So that's what he thought we should
do.
Timon asked what happens if you're in a heterogeneous system that
has different kinds of hardware operating on the same memory,
with different coherency guarantees and features. How does the
compiler know about this?
Walter and Átila both said that it doesn't. Átila said you cast
away shared and you do your weird stuff yourself because he
didn't know how we could support that. Walter agreed. Timon said
that was the point of saying that if it's shared, you have to do
something sensible on your own, the compiler will not assume that
doing certain things is sensible. Walter said the compiler
assumes what's sensible based on the CPU it's targeting.
Timon said yes, but in concurrent program, the compiler knows
what it's generating the code for now, but it doesn't know what
other devices are on the same system and accessing this memory.
Walter said Timon was suggesting that the lock instruction on a
CPU was completely useless. Timon said he wasn't saying that. You
should probably specify what you want. Átila said you can. Timon
said that definitely you can, it's just that to him, the
reasoning made sense that there is no sensible default. But of
course, they could disagree with that and say the sensible
default is sequential consistency, assuming that all the threads
are running on this CPU that you're compiling for. It's just a
different trade-off.
Walter said he's going to assume that the CPU maker hasn't
screwed up with the implementation of shared loads. Timon
emphasized he was just saying there is not a single way to
synchronize access. Átila reiterated that you can do your own
synchronization instead. And if you're somebody who cares about
this, that's what you're going to be doing anyway.
Given that we'd already gone over two hours and a few
participants had dropped out, Walter suggested we cut this
particular discussion here and consider putting a cap on long
discussions in the future.
Walter
Walter said he'd been able to fix a bunch of things that had come
up at DConf. He was very disappointed that he'd been forced to
adopt Microsoft assembly syntax for ImportC because they offered
no path through their header files that didn't end up using their
version of inline assembler. We'll see how that works out.
He'd spent a lot of time converting his DConf presentation into
an article.
He'd also been working on 'The Didacticus' for D, a set of
general design principles that would be congruent with our vision
of changing the way programmers think. We'd never really sat down
and made a list of the general principles that make D a unique
and useful language. He thought it was long past time. He'd
written up a draft form that he'd sent to a couple of people. He
hoped everyone was happy with that.
(UPDATE: Right now, Walter is currently working on what I think
is the fourth, or maybe fifth, draft of the principles. He
started with a list of the principles themselves and then refined
that list, and has since been expanding on defining and
describing them. Once he's finished, we'll publish this on the
website alongside the DLF's vision statement and that of each DLF
associate.)
Conclusion
This meeting was followed by a planning session on the 23rd. We
then had a quarterly meeting with industry reps on October 6th.
Our next monthly was on October 13th.
That's it!
Matheus.
More information about the Digitalmars-d-announce
mailing list