digitalmars.dip.ideas - Make TLS explicit
- Dave P. (18/18) Apr 16 A long time ago, global variables and static variables in D were
- Mike Shah (16/34) Apr 17 I have found explicitly marking data that is meant to be shared
- Dave P. (10/27) Apr 17 The problem isn’t shared, it’s when you port C code to D, it is
- Guillaume Piolat (7/25) Apr 19 +1
- Jonathan M Davis (32/60) Apr 19 Not really. If anything, it gets rid of the default and then forces you ...
- ryuukk_ (6/24) Apr 19 +1
- Atila Neves (8/18) Apr 21 I most definitely want TLS by default and to only have sharing if
- Dom DiSc (2/3) Apr 22 +1
A long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception. - Not as safe as it looks: thread local variables still have many of the problems of global variables, such as having to worry about function re-entrancy. So I propose to make it an error to have it be unspecified if a static variable is shared, __gshared, immutable or thread local. Additionally, add a thread_local storage class so you can explicitly opt into TLS for when you actually want that. Changing this might require a new edition, but who knows.
Apr 16
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:A long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception. - Not as safe as it looks: thread local variables still have many of the problems of global variables, such as having to worry about function re-entrancy. So I propose to make it an error to have it be unspecified if a static variable is shared, __gshared, immutable or thread local. Additionally, add a thread_local storage class so you can explicitly opt into TLS for when you actually want that. Changing this might require a new edition, but who knows.I have found explicitly marking data that is meant to be shared is the right default for me (i.e., I like the thread-local default). I personally want life to be easier to write concurrent applications that are correct and avoid race conditions. I've for instance run into problems when passing data between threads -- in many cases D will prevent that if the data is not marked as shared, or otherwise global. I'm quite curious if you have a use case, perhaps a mixed codebase with C code that provides a counterexample? I understand there could otherwise probably be improvements to 'shared' qualifier otherwise. Reference on migration to shared: https://dlang.org/articles/migrate-to-shared.html Note: the -vtls switch is also quite useful for otherwise investigating code.
Apr 17
On Thursday, 17 April 2025 at 19:09:49 UTC, Mike Shah wrote:On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:The problem isn’t shared, it’s when you port C code to D, it is easy to forget that D has the thread local default for globals, which can be a performance issue and also just very confusing if you do ever decide to move things to threads. If it was a compile error to not specify it would be fine. You’d mark it `__gshared` while porting, with the `__gshared` acting as a FIXME list you can clean up later. Or you explicitly mark it as thread local to show you’ve actually decided one way or the other. Or you make it immutable, etc.[...]I have found explicitly marking data that is meant to be shared is the right default for me (i.e., I like the thread-local default). I personally want life to be easier to write concurrent applications that are correct and avoid race conditions. I've for instance run into problems when passing data between threads -- in many cases D will prevent that if the data is not marked as shared, or otherwise global. I'm quite curious if you have a use case, perhaps a mixed codebase with C code that provides a counterexample? I understand there could otherwise probably be improvements to 'shared' qualifier otherwise.Reference on migration to shared: https://dlang.org/articles/migrate-to-shared.html Note: the -vtls switch is also quite useful for otherwise investigating code.
Apr 17
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:A long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception. - Not as safe as it looks: thread local variables still have many of the problems of global variables, such as having to worry about function re-entrancy. So I propose to make it an error to have it be unspecified if a static variable is shared, __gshared, immutable or thread local. Additionally, add a thread_local storage class so you can explicitly opt into TLS for when you actually want that. Changing this might require a new edition, but who knows.+1 It really brings zero benefit to have it implicit (when did you really want that). We should finally admit to that being a mistake. If the goal was "no sharing by default", then explicit TLS keeps that goal.
Apr 19
On Saturday, April 19, 2025 6:47:31 AM MDT Guillaume Piolat via dip.ideas wrote:On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:Not really. If anything, it gets rid of the default and then forces you to add extra attributes to types all over the place in order to be explicit. The current situation largely works extremely well, because having variables not be shared across threads is almost always what you want, and it's required for memory safety, because you can't access variables which are shared across threads in thread-safe manner without extra machinery to ensure that those reads and writes are thread-safe. I can understand there being some frustration when porting code, because the type systems of other languages like C do not encode whether something is shared across threads or not, but the fact that D has that distinction helps localize threading issues and is required for the memory safety guarantees that the language is supposed to be providing. And because very little code in general is sharing anything across threads, the amount of code that needs to encode that distinction in the types is small. So, the number of explicit attributes required is small. But if we got rid of the default and required that it be explict, then that would literally mean adding an additional attribute onto almost every time everywhere, which would be incredibly verbose. And if the argument is that static variables or module-level variables should be treated differently and require an explicit attribute which is the opposite of shared, then that would create a pretty massive inconsistency in how types are dealt with for this one corner case that's really only an issue when porting code. And in my experience, static and module-level variables are almost always thread-local just like the rest of the objects in the program. It's just specific sections of multi-threaded code that needs to worry about shared, and __gshared is really only supposed to be used when binding to C globals anyway - and the fact that __gshared is shared but typed as thread-local is actually a hole in safe, though now that we have system variables, we could fix it so that all __gshared variables are system, which would fix that problem. - Jonathan M DavisA long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception. - Not as safe as it looks: thread local variables still have many of the problems of global variables, such as having to worry about function re-entrancy. So I propose to make it an error to have it be unspecified if a static variable is shared, __gshared, immutable or thread local. Additionally, add a thread_local storage class so you can explicitly opt into TLS for when you actually want that. Changing this might require a new edition, but who knows.+1 It really brings zero benefit to have it implicit (when did you really want that). We should finally admit to that being a mistake. If the goal was "no sharing by default", then explicit TLS keeps that goal.
Apr 19
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:A long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception. - Not as safe as it looks: thread local variables still have many of the problems of global variables, such as having to worry about function re-entrancy. So I propose to make it an error to have it be unspecified if a static variable is shared, __gshared, immutable or thread local. Additionally, add a thread_local storage class so you can explicitly opt into TLS for when you actually want that. Changing this might require a new edition, but who knows.+1 TLS usage should always be explicit, it comes with performance considerations so it should be used with care It's the rare case where i don't mind having an attribute to use, something like ` tls` (built in, no imports needed)
Apr 19
On Wednesday, 16 April 2025 at 22:46:32 UTC, Dave P. wrote:A long time ago, global variables and static variables in D were changed to be thread local by default. I think this has proven to mostly be a bad idea, for a few reasons: - Violates the “looks like C principle”: Code that looks like C should either behave the same as C or not compile. - Unexpected: No other language defaults to TLS. - Unwanted: Most of the time you don’t actually want thread local variables. If you want global state you either want immutability or synchronized access (mutexes) through something like shared. TLS is the exception.I most definitely want TLS by default and to only have sharing if I explicitly say otherwise. If you end up having something that looks shared and isn't, you'll find out quickly (unless you ever only have one thread) and it'll be easily reproducible. If you neglect to prevent data races you're in for a "fun" time figuring out what's going on. TLS by default is in my opinion one of D's many wins.
Apr 21
On Monday, 21 April 2025 at 14:00:21 UTC, Atila Neves wrote:TLS by default is in my opinion one of D's many wins.+1
Apr 22