digitalmars.D.learn - Why are globals set to tls by default? and why is fast code ugly by
- ryuukk_ (23/23) Mar 26 2023 Hi,
- ryuukk_ (2/2) Mar 26 2023 Perhaps in ``-betterC`` tls vars should be annotated with
- ryuukk_ (2/2) Mar 26 2023 With -betterC it's broken for 3 years btw:
- Richard (Rikki) Andrew Cattermole (10/10) Mar 26 2023 Having TLS by default is actually quite desirable if you like your code
- ryuukk_ (11/22) Mar 26 2023 It's never desirable to have it by default, the consensus should
- Nick Treleaven (8/12) Mar 31 2023 Go doesn't have a solution to preventing data races at compile
- ryuukk_ (5/17) Mar 31 2023 If you want TLS in GO, you specify that you need a TLS variable,
- IGotD- (17/28) Apr 01 2023 I think "safe" BS is going too far. Normally you don't use global
- IGotD- (17/28) Apr 01 2023 I think "safe" BS is going too far. Normally you don't use global
- Guillaume Piolat (3/6) Apr 01 2023 It looks like a mistake if we consider none of the D-inspired
- Nick Treleaven (6/12) Mar 26 2023 Because it should be rare that __gshared is used. And if you need
- ryuukk_ (4/16) Mar 26 2023 I don't understand this argument, if my code doesn't do threads,
- Nick Treleaven (11/14) Mar 31 2023 I don't think writing __gshared is a huge burden. You can use
- Nick Treleaven (12/15) Mar 31 2023 I don't think writing __gshared is much of a burden. You can use
- ryuukk_ (11/29) Mar 31 2023 It is a burden to type things you don't need, and to type things
- Dennis (4/6) Mar 31 2023 Good code shouldn't look ugly, but global mutable variables are
- ryuukk_ (6/13) Mar 31 2023 I disagree, global mutables are not bad
- Dennis (3/7) Mar 31 2023 I agree that singletons aren't any better than global variables.
- bachmeier (5/10) Mar 31 2023 Those of us that have been scarred by reading FORTRAN 77 code
- Guillaume Piolat (7/11) Apr 01 2023 But you kind of get into the same things with "accidental TLS".
- Adam D Ruppe (6/7) Apr 01 2023 Yeah, I think what we should do is make each thing be explicitly
- Steven Schveighoffer (9/16) Mar 26 2023 If you know a variable is not `shared`, then you know it can only be
- ryuukk_ (6/22) Mar 26 2023 I haven't explored this use case, that must explain why i find it
- z (13/15) Mar 27 2023 The limitations of `shared` can be bypassed with a "function"
- Steven Schveighoffer (19/44) Mar 27 2023 If you want to have the type system tell you when a variable is readable...
- =?UTF-8?Q?Ali_=c3=87ehreli?= (34/37) Apr 01 2023 C doesn't do because there was no such concept when it was conceived.
- Timon Gehr (2/5) Apr 01 2023 Rust just does not do mutable globals except in unsafe code.
- IGotD- (27/54) Apr 01 2023 I think that would hard to get documentation on the rationale for
- z (13/15) Mar 27 2023 The limitations of `shared` can be bypassed with a "function"
- wjoe (15/18) Mar 27 2023 What's fast today may not be fast tomorrow but the language might
- Nick Treleaven (8/17) Mar 31 2023 Good to know, thanks.
- z (13/15) Mar 27 2023 The limitations of `shared` can be bypassed with a "function"
- z (13/15) Mar 27 2023 The limitations of `shared` can be bypassed with a "function"
- Jacob Shtokolov (17/19) Mar 27 2023 Because the language maintainers decided that they want to
- Guillaume Piolat (4/6) Mar 27 2023 Honestly I find TLS-by-default to be a bad idea, it has become a
Hi, It's common knowledge that accessing tls global is slow http://david-grs.github.io/tls_performance_overhead_cost_linux/ What i do not understand is the reasoning behind choosing tls global by default in D What i find even more weird is writing fast code is ugly in D Look at this ugly code ```D __gshared int fast_code_ugly; ``` It should be the opposite Slow code ugly Fast code beautiful What can be done about it? Renaming ``__gshared`` ``shared`` is even more ugly since everything must be shared afterwards I would have prefered if i had to manually set things to tls ```D tls int slow_code_ugly; ``` Even C does it better: https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.html
Mar 26 2023
Perhaps in ``-betterC`` tls vars should be annotated with `` tls``, and the default is not tls just like in C?
Mar 26 2023
With -betterC it's broken for 3 years btw: https://issues.dlang.org/show_bug.cgi?id=20737
Mar 26 2023
Having TLS by default is actually quite desirable if you like your code to be safe without having to do anything extra. As soon as you go into global to the process memory, you are responsible for synchronization. Ensuring that the state is what you want it to be. Keep in mind that threads didn't exist when C was created. They could not change their approach without breaking everyone's code. So what they do is totally irrelevant unless its 1980. I think its the correct way around. You can't accidentally cause memory safety issues. You must explicitly opt-into the ability to mess up your programs state.
Mar 26 2023
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew Cattermole wrote:Having TLS by default is actually quite desirable if you like your code to be safe without having to do anything extra. As soon as you go into global to the process memory, you are responsible for synchronization. Ensuring that the state is what you want it to be. Keep in mind that threads didn't exist when C was created. They could not change their approach without breaking everyone's code. So what they do is totally irrelevant unless its 1980. I think its the correct way around. You can't accidentally cause memory safety issues. You must explicitly opt-into the ability to mess up your programs state.It's never desirable to have it by default, the consensus should be: let the developer make the choice, currently the consensus is to punish the developer who want to make the choice Golang doesn't even have thread local storage, yet they do very well D doesn't have coroutines, D doesn't do anything special, it just forces you to uglyfy your code to opt out ``__gshared`` is ugly to write, ugly to read, there must be a better solution
Mar 26 2023
On Sunday, 26 March 2023 at 20:36:37 UTC, ryuukk_ wrote:Golang doesn't even have thread local storage, yet they do very wellGo doesn't have a solution to preventing data races at compile time, they just say don't share memory. But what if you accidentally share memory? That is *very* easy to do in Go. You and your users are out of luck. All you can do is run the race detector and pray that you happen to test all the code paths with it that might have data races:The race detector only finds races that happen at runtime, so it can't find races in code paths that are not executedhttps://go.dev/doc/articles/race_detector
Mar 31 2023
On Friday, 31 March 2023 at 10:32:53 UTC, Nick Treleaven wrote:On Sunday, 26 March 2023 at 20:36:37 UTC, ryuukk_ wrote:If you want TLS in GO, you specify that you need a TLS variable, just like every sane languages Go went the smart route on top of having goroutines, making it superior to what ever D offerGolang doesn't even have thread local storage, yet they do very wellGo doesn't have a solution to preventing data races at compile time, they just say don't share memory. But what if you accidentally share memory? That is *very* easy to do in Go. You and your users are out of luck. All you can do is run the race detector and pray that you happen to test all the code paths with it that might have data races:The race detector only finds races that happen at runtime, so it can't find races in code paths that are not executedhttps://go.dev/doc/articles/race_detector
Mar 31 2023
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew Cattermole wrote:Having TLS by default is actually quite desirable if you like your code to be safe without having to do anything extra. As soon as you go into global to the process memory, you are responsible for synchronization. Ensuring that the state is what you want it to be. Keep in mind that threads didn't exist when C was created. They could not change their approach without breaking everyone's code. So what they do is totally irrelevant unless its 1980. I think its the correct way around. You can't accidentally cause memory safety issues. You must explicitly opt-into the ability to mess up your programs state.I think "safe" BS is going too far. Normally you don't use global variables at all but if you do the most usual is to use normal global variables with perhaps some kind of synchronization primitive. TLS is quite unusual and having TLS by default might even introduce bugs as the programmer believes that the value can be set by all threads while they are independent. Regardless, __gshared in front of the variable isn't a huge deal but it shows that the memory model in D is a leaking bucket. Some compilers enforce synchronization primitives for global variables and are "safe" that way. However, sometimes you don't need them like in small systems that only has one thread and it just gets in the way. TLS by default is mistake in my opinion and it doesn't really help. TLS should be discouraged as much as possible as it is complicated and slows down thread creation.
Apr 01 2023
On Sunday, 26 March 2023 at 18:25:54 UTC, Richard (Rikki) Andrew Cattermole wrote:Having TLS by default is actually quite desirable if you like your code to be safe without having to do anything extra. As soon as you go into global to the process memory, you are responsible for synchronization. Ensuring that the state is what you want it to be. Keep in mind that threads didn't exist when C was created. They could not change their approach without breaking everyone's code. So what they do is totally irrelevant unless its 1980. I think its the correct way around. You can't accidentally cause memory safety issues. You must explicitly opt-into the ability to mess up your programs state.I think "safe" BS is going too far. Normally you don't use global variables at all but if you do the most usual is to use normal global variables with perhaps some kind of synchronization primitive. TLS is quite unusual and having TLS by default might even introduce bugs as the programmer believes that the value can be set by all threads while they are independent. Regardless, __gshared in front of the variable isn't a huge deal but it shows that the memory model in D is a leaking bucket. Some compilers enforce synchronization primitives for global variables and are "safe" that way. However, sometimes you don't need them like in small systems that only has one thread and it just gets in the way. TLS by default is mistake in my opinion and it doesn't really help. TLS should be discouraged as much as possible as it is complicated and slows down thread creation.
Apr 01 2023
On Saturday, 1 April 2023 at 08:47:54 UTC, IGotD- wrote:TLS by default is mistake in my opinion and it doesn't really help. TLS should be discouraged as much as possible as it is complicated and slows down thread creation.It looks like a mistake if we consider none of the D-inspired languages have stolen TLS-by-default.
Apr 01 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:What i find even more weird is writing fast code is ugly in D Look at this ugly code ```D __gshared int fast_code_ugly; ```Because it should be rare that __gshared is used. And if you need it, you won't be worried about how the storage class looks because you'll be concentrating on if your design is thread-safe.It should be the oppositeThen by default, safe code can not access global variables and there can easily be accidental races between threads.
Mar 26 2023
On Sunday, 26 March 2023 at 18:29:17 UTC, Nick Treleaven wrote:On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:I don't understand this argument, if my code doesn't do threads, why should i put my variable into TLS? If i want fast code, why should i make use of ugly syntax?What i find even more weird is writing fast code is ugly in D Look at this ugly code ```D __gshared int fast_code_ugly; ```Because it should be rare that __gshared is used. And if you need it, you won't be worried about how the storage class looks because you'll be concentrating on if your design is thread-safe.
Mar 26 2023
On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:if my code doesn't do threads, why should i put my variable into TLS?I don't think writing __gshared is a huge burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good option for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.If i want fast code, why should i make use of ugly syntax?By default D supports threads and accidental data races are far worse than ugly syntax.
Mar 31 2023
On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:if my code doesn't do threads, why should i put my variable into TLS?I don't think writing __gshared is much of a burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good enhancement for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.If i want fast code, why should i make use of ugly syntax?1. If you want fast code, why aren't you using threads? 2. By default D supports threads and accidental data races are far worse than ugly syntax.
Mar 31 2023
On Friday, 31 March 2023 at 10:26:32 UTC, Nick Treleaven wrote:On Sunday, 26 March 2023 at 20:39:21 UTC, ryuukk_ wrote:It is a burden to type things you don't need, and to type things that are ugly on purpose I recently discovered -vtls and indeed is very nice to have, managed to clear out all my TLS usage, but made my code even more ugly ``__gshared`` everywhere..if my code doesn't do threads, why should i put my variable into TLS?I don't think writing __gshared is much of a burden. You can use -vtls to print out all variables that are TLS, and add that to an automated test to check you don't have any accidentally. I have thought before that a --no-threads compiler switch that does not link the key thread functions but makes __gshared the default might be a good enhancement for your use case. Then if you accidentally call some code that uses std.parallelism internally you would get a link error.If i want fast code, why should i make use of ugly syntax?1. If you want fast code, why aren't you using threads? 2. By default D supports threads and accidental data races are far worse than ugly syntax.If you want fast code, why aren't you using threads?threads is not synonymous of fast code and if i were to use thread, i'd not rely on globals to begin withBy default D supports threads and accidental data races are far worse than ugly syntax.Debatable, but that's a good point, but that's not the point i bring, the point i bring is ``__gshared`` is ugly, so we want an ugly language?
Mar 31 2023
On Friday, 31 March 2023 at 15:52:21 UTC, ryuukk_ wrote:the point i bring is ``__gshared`` is ugly, so we want an ugly language?Good code shouldn't look ugly, but global mutable variables are bad, so it's appropriate that they look ugly. You can still put a single `__gshared:` at the top of your module.
Mar 31 2023
On Friday, 31 March 2023 at 16:02:35 UTC, Dennis wrote:On Friday, 31 March 2023 at 15:52:21 UTC, ryuukk_ wrote:I disagree, global mutables are not bad That the same bad advice as telling people to "embrace OOP and multiple inheritance" and all the Java BS "just put your variable into a class and make it static, and then have your singleton to access your static variables"the point i bring is ``__gshared`` is ugly, so we want an ugly language?Good code shouldn't look ugly, but global mutable variables are bad, so it's appropriate that they look ugly. You can still put a single `__gshared:` at the top of your module.
Mar 31 2023
On Friday, 31 March 2023 at 16:26:36 UTC, ryuukk_ wrote:That the same bad advice as telling people to "embrace OOP and multiple inheritance" and all the Java BS "just put your variable into a class and make it static, and then have your singleton to access your static variables"I agree that singletons aren't any better than global variables. The better way is to pass state through function parameters.
Mar 31 2023
On Friday, 31 March 2023 at 16:26:36 UTC, ryuukk_ wrote:I disagree, global mutables are not bad That the same bad advice as telling people to "embrace OOP and multiple inheritance" and all the Java BS "just put your variable into a class and make it static, and then have your singleton to access your static variables"Those of us that have been scarred by reading FORTRAN 77 code would disagree. I use global mutables myself (and even the occasional goto), but if anything, it should be `__GLOBAL_MUTABLE_VARIABLE` to increase the pain of using them.
Mar 31 2023
On Friday, 31 March 2023 at 19:43:42 UTC, bachmeier wrote:Those of us that have been scarred by reading FORTRAN 77 code would disagree. I use global mutables myself (and even the occasional goto), but if anything, it should be `__GLOBAL_MUTABLE_VARIABLE` to increase the pain of using them.But you kind of get into the same things with "accidental TLS". It doesn't race, but now the variable is different for every thread, which is a different kind of race. TLS could be explicit and we wouldn't need a -vtls flag. There is no flag to warn for every use of trusted, so in the grand scheme of things TLS is more dangerous than trusted.
Apr 01 2023
On Saturday, 1 April 2023 at 13:11:46 UTC, Guillaume Piolat wrote:TLS could be explicit and we wouldn't need a -vtls flag.Yeah, I think what we should do is make each thing be explicitly marked. When I want tls, I tend to comment that it was intentional anyway to make it clear I didn't just forget to put a shared note on the static.
Apr 01 2023
On 3/26/23 2:07 PM, ryuukk_ wrote:Hi, It's common knowledge that accessing tls global is slow http://david-grs.github.io/tls_performance_overhead_cost_linux/ What i do not understand is the reasoning behind choosing tls global by default in DIf you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data". -Steve
Mar 26 2023
On Sunday, 26 March 2023 at 19:08:32 UTC, Steven Schveighoffer wrote:On 3/26/23 2:07 PM, ryuukk_ wrote:I haven't explored this use case, that must explain why i find it surprising, however, i read about other languages too, and they seem to be explicit whenever they make use of TLS C, C++, Rust, Zig, Go doesn't do TLS by default for exampleHi, It's common knowledge that accessing tls global is slow http://david-grs.github.io/tls_performance_overhead_cost_linux/ What i do not understand is the reasoning behind choosing tls global by default in DIf you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data". -Steve
Mar 26 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:``shared`` is even more ugly since everything must be shared afterwardsThe limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
On 3/26/23 4:41 PM, ryuukk_ wrote:On Sunday, 26 March 2023 at 19:08:32 UTC, Steven Schveighoffer wrote:If you want to have the type system tell you when a variable is readable from other threads or not, you need to have *something* to distinguish them. 99% of all variables are not readable from other threads, so making that the default seems the right call to me. I don't know if you have thought through the implications. Start with the requirement that I need to know by examining the type whether the value is viewable from multiple threads. Is there a better mechanism with better defaults? C/C++ is precisely the wrong answer -- just let the programmer fend for himself. I haven't used the others to know what their story is. One possibility is to REQUIRE you to mark module-level and static variables as one of `__gshared`, `shared`, `immutable`, or ` tls`. I would be OK with such a change. I've run into a situation where I want to make a thread local pointer to shared data, and it's not easy. The only solution I could come up with is to put it inside a dummy struct with a shared member. Having a ` tls` storage class would help solve that. -SteveOn 3/26/23 2:07 PM, ryuukk_ wrote:I haven't explored this use case, that must explain why i find it surprising, however, i read about other languages too, and they seem to be explicit whenever they make use of TLS C, C++, Rust, Zig, Go doesn't do TLS by default for exampleHi, It's common knowledge that accessing tls global is slow http://david-grs.github.io/tls_performance_overhead_cost_linux/ What i do not understand is the reasoning behind choosing tls global by default in DIf you know a variable is not `shared`, then you know it can only be accessed from the current thread. This has huge implications for thread access. However, one problem that D has no good solution is passing thread-local data to another thread (to be owned by the new thread, and no access in the current thread). That's typically the most common use case for "shared data".
Mar 27 2023
On 3/26/23 13:41, ryuukk_ wrote:C, C++, Rust, Zig, Go doesn't do TLS by default for exampleC doesn't do because there was no such concept when it was conceived. C++ doesn't do because they built on top of C. (D does because it has always been innovative.) Go doesn't do because it had no innovations anyway. Does anyone have documentation on why Rust and Zip does not do thread local by default? I wonder what experience it was based on. Speaking of experience, I used to be a C++ programmer. We made use of thread-local storage precisely zero times. I think it's because the luminaries of the time did not even talk about it. With D, I take good advantage of thread-local storage. Interestingly, I do that *only* for fast code. void foo(int arg) { static int[] workArea; if (workArea.length < nededFor(arg)) { // increase length } // Use workArea } Now I can use any number of threads using foo and they will have their independent work areas. Work area grows in amortized fashion for each thread. I find the code above to be clean and beautiful. It is very fast because there are no synchronization primitives needed because no work area is shared between threads. Finding one example to the contrary does not make TLS a bad idea. Engineering is full of compromises. I agree with D's TLS by-default idea. Since I am here, I want to touch on something that may give the wrong idea to newer D programmers: D does not have globals. Every symbol belongs to a module. And copying an earlier comment of yours:It's common knowledge that accessing tls global is slow http://david-grs.github.io/tls_performance_overhead_cost_linux/"TLS global is slow" would be misleading because even the article you linked explains right at the top, in the TL;DR are that "TLS may be slow". Ali
Apr 01 2023
On 4/1/23 17:02, Ali Çehreli wrote:Does anyone have documentation on why Rust and Zip does not do thread local by default?Rust just does not do mutable globals except in unsafe code.
Apr 01 2023
On Saturday, 1 April 2023 at 15:02:12 UTC, Ali Çehreli wrote:Does anyone have documentation on why Rust and Zip does not do thread local by default? I wonder what experience it was based on.I think that would hard to get documentation on the rationale for that decision. Maybe you can get an answer in their forums but I doubt it. For Rust I think they based it on that globals should have some kind of synchronization which is enforced at compile time. Therefore TLS becomes second citizen.Speaking of experience, I used to be a C++ programmer. We made use of thread-local storage precisely zero times. I think it's because the luminaries of the time did not even talk about it.Yes, that's "normal" programming that you more or less never use TLS.With D, I take good advantage of thread-local storage. Interestingly, I do that *only* for fast code. void foo(int arg) { static int[] workArea; if (workArea.length < nededFor(arg)) { // increase length } // Use workArea } Now I can use any number of threads using foo and they will have their independent work areas. Work area grows in amortized fashion for each thread. I find the code above to be clean and beautiful. It is very fast because there are no synchronization primitives needed because no work area is shared between threads.There is nothing beautiful with it other than the clean syntax. Why not just use a stack variable which is thread local as well. TLS is often allocated on the stack in many systems anyway. Accessing TLS variables can slower compared to stack variables. The complexity of TLS doesn't pay for its usefulness.This depends how it is implemented. TLS is really a forest and can be implemented in many ways and it also depends where it is being accessed (shared libraries, executable etc.). In general TLS on x86 is accessed by fs:[-offset_to_variable] this isn't that slow but the complexity to get there is high. Keep in mind the TLS area must be initialized for every thread creation which isn't ideal. fs:[] isn't always possible and a function call is required similar to a DLL symbol look up. TLS is a turd which shouldn't have been created. They should have stopped with key/value pair which languages then could build on if they wanted. Now TLS are in the executable standards and it is a mess. x86 has now two ways of TLS (normal and TLS_DESC) just to make things even more complicated. A programmer never see this mess but as systems programmer I see this and it is horrible.It's common knowledge that accessing tls global is slowhttp://david-grs.github.io/tls_performance_overhead_cost_linux/ "TLS global is slow" would be misleading because even the article you linked explains right at the top, in the TL;DR are that "TLS may be slow".
Apr 01 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:``shared`` is even more ugly since everything must be shared afterwardsThe limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:It should be the opposite Slow code ugly Fast code beautifulWhat's fast today may not be fast tomorrow but the language might still be relevant. e.g.: It used to be faster to ... - pre-calculate sin/cos tables, now the memory look up cost more cycles than the calculation itself - use fixed point integer math, now every CPU has what used to be a floating point co-processor integrated - only redraw the parts of the screen that changed, now the branching is slower than to redraw everything another example is sorting - Alexei wrote a blog post about how a stupid and slow sorting algorithm now performs better in multi threading. Maybe someone remembers the title/url of the post ? And finally, beauty is in the eye of the beholder - meaning it's purely subjective.
Mar 27 2023
On Monday, 27 March 2023 at 08:44:41 UTC, wjoe wrote:e.g.: It used to be faster to ... - pre-calculate sin/cos tables, now the memory look up cost more cycles than the calculation itself...- only redraw the parts of the screen that changed, now the branching is slower than to redraw everythingGood to know, thanks.another example is sorting - Alexei wrote a blog post about how a stupid and slow sorting algorithm now performs better in multi threading. Maybe someone remembers the title/url of the post ?Not sure, but that reminds me of Andrei's blog on partitioning (for quicksort): https://dlang.org/blog/2020/05/14/lomutos-comeback/ The algorithm traditionally considered slower can be faster because it can be optimized to work better with branch prediction.
Mar 31 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:``shared`` is even more ugly since everything must be shared afterwardsThe limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:``shared`` is even more ugly since everything must be shared afterwardsThe limitations of `shared` can be bypassed with a "function" that removes type qualifiers. `return *cast(Unqual!T*) &foo`(example, doesn't work as is for arrays.) This way `shared` symbols can be used with functions that *cannot* be made compatible with both shared and non-shared.(by cannot the exact reasons seem obscure, it may be that a called function *would* support `shared` parameters but calls a function with the parameter that does not, ime this is painfully apparent with `struct`s' member functions) Naturally there's the risk of concurrency issues because this isn't the language documentation-recommended way of doing things, but D's library has these problems covered.
Mar 27 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:What i do not understand is the reasoning behind choosing tls global by default in DBecause the language maintainers decided that they want to emphasize the actor model with no default shared state in the language. This is quite beneficial, BTW, as multiprocessor programming is by no means an easy problem, so the language just pushes you towards the error-free code by default. As for `__gshared`, this is intended only for interfacing with C and other languages where global variables is the default way of doing things. This may seem ugly, but if you write your program completely in D and want to avoid TLS, why don't you avoid globals at all? Just allocate some state on the stack and pass it to your functions as `ref`. This way it will actually be much cleaner and easy to understand and test, because global variables are tempting to be mutated, which makes the program control flow much less transparent.
Mar 27 2023
On Sunday, 26 March 2023 at 18:07:03 UTC, ryuukk_ wrote:Even C does it better: https://gcc.gnu.org/onlinedocs/gcc/Thread-Local.htmlHonestly I find TLS-by-default to be a bad idea, it has become a trap to be avoided, and TLS does occasionally speed up things but it should be opt-in.
Mar 27 2023