May 12, 2022
On Thursday, 12 May 2022 at 17:34:30 UTC, H. S. Teoh wrote:
>
> Why is TLS by default a problem?
>
> It's not really for optimization, AIUI, it's more for thread safety: module-global state is TLS by default, so you don't accidentally introduce race conditions.

What you accidentally have instead is people expecting top-level to be global
and instead you get TLS, so it's a surprise.
I mean, a lot of things works like C and C++, but not that.

It's a problem because it goes from solving "no accidental race condition" and you get "people forget to add shared or __gshared and their shared library silently fail" situation. You could have none of that with explicit TLS.

>>     - `shared static this()` vs `static this()` is another trap.
>
> One is per-process, one is per-thread.  Why is this a trap?

Well because you can get that wrong.
You get to initialize "__gshared" variables in "shared static this".
It's not hard, but it's something more to explain.


> I wouldn't sweat it if I couldn't easily add `pure` to an entire codebase -- it hardly makes any difference anyway.

If it doesn't make a difference to the bottom-line then why keep it?


> you're on your own and you take responsibility for any problems that you may inadvertently introduce by using the escape hatch.

Well sizeable @afe code has heaps of @trusted code, so the escape hatch is very routine.


> it's none of the users' business.

I'm not disagreeing about @trusted in API.
But I was remarking in practice that @safe would mean different invariants.
it's not a big issue, I was probably ranting.

> IOW, public APIs should always be @safe or @system. @trusted should only appear on internal APIs.

Good rule to follow, TIL.


> So I'm curious, what exactly is it about UFCS chains that make it less maintainable?

Probably personal preference, I mostly write the pedestrian way, so that debugging/optimization goes faster (maybe wrong, dunno).

In the dlang.org example:

void main()
{
    stdin
        .byLineCopy
        .array
        .sort!((a, b) => a > b) // descending order
        .each!writeln;
}

This code has a number of prerequisites to be able to read: why is ".array" needed, why is it ".byLineCopy" vs ".byLine", is the sort stable, etc. It's just requires more time spent with the language.

May 13, 2022
On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote:
> What are you stuck at? What was the most difficult features to understand? etc.

The concept of traits (std.traits) confuses me enough. Actually the problem is that the interface is disorderly (disorganizedly). As if it was very difficult to establish a hierarchical system...

Also, multitasking is like that, it's disorganizedly: taskPool.parallel(std.parallelism), yield(std.concurrency), ThreadGroup(core.thread)...etc(pufff!)

SDB@79
May 13, 2022

On Thursday, 12 May 2022 at 20:49:08 UTC, Chris Katko wrote:

>

In D, I can do the module based method, but nothing short of renaming variables gives me a list of violations and, that also makes all the correct internal accesses wrong. Because private doesn't work.

Call it whatever keyword you want, I really want a 'private' specifier for classes. It's incredibly useful.

We can really add a keyword such as secret. Good idea.

May 13, 2022
On Thu, May 12, 2022 at 11:45:47PM +0000, Guillaume Piolat via Digitalmars-d-learn wrote:
> On Thursday, 12 May 2022 at 17:34:30 UTC, H. S. Teoh wrote:
> > 
> > Why is TLS by default a problem?
> > 
> > It's not really for optimization, AIUI, it's more for thread safety: module-global state is TLS by default, so you don't accidentally introduce race conditions.
> 
> What you accidentally have instead is people expecting top-level to be
> global and instead you get TLS, so it's a surprise.
> I mean, a lot of things works like C and C++, but not that.
> 
> It's a problem because it goes from solving "no accidental race condition" and you get "people forget to add shared or __gshared and their shared library silently fail" situation. You could have none of that with explicit TLS.

Valid point.


> > >     - `shared static this()` vs `static this()` is another trap.
> > 
> > One is per-process, one is per-thread.  Why is this a trap?
> 
> Well because you can get that wrong.
> You get to initialize "__gshared" variables in "shared static this".
> It's not hard, but it's something more to explain.

I see.


[...]
> > I wouldn't sweat it if I couldn't easily add `pure` to an entire codebase -- it hardly makes any difference anyway.
> 
> If it doesn't make a difference to the bottom-line then why keep it?

It's useful in smaller pockets of code. Like factory functions that
implicitly cast to immutable, or arithmetic functions whose return
values you want to compute only once in a complex expression.  It's also
useful for maintaining the cleanliness of code (make sure your function
doesn't have inadvertent access to global state where you didn't
intend it to).

But blanket-applying `pure` to an entire codebase?  Don't really see the value. For things like I/O it's inherently impure anyway.


> > you're on your own and you take responsibility for any problems that you may inadvertently introduce by using the escape hatch.
> 
> Well sizeable @afe code has heaps of @trusted code, so the escape hatch is very routine.

IMO, that's a code smell. @trusted should be used as little as possible, only where it's absolutely unavoidable.  If there's more than a handful of @trusted in your code, or if you have giant sections of code with `@trusted:` at the top, you're probably doing it wrong.


> > it's none of the users' business.
> 
> I'm not disagreeing about @trusted in API.
> But I was remarking in practice that @safe would mean different
> invariants.  it's not a big issue, I was probably ranting.

OK, we all rant sometimes. :-)


[...]
> > So I'm curious, what exactly is it about UFCS chains that make it less maintainable?
> 
> Probably personal preference, I mostly write the pedestrian way, so that debugging/optimization goes faster (maybe wrong, dunno).
> 
> In the dlang.org example:
> 
> void main()
> {
>     stdin
>         .byLineCopy
>         .array
>         .sort!((a, b) => a > b) // descending order
>         .each!writeln;
> }
> 
> This code has a number of prerequisites to be able to read: why is ".array" needed, why is it ".byLineCopy" vs ".byLine", is the sort stable, etc. It's just requires more time spent with the language.

But doesn't reading (and esp maintaining) *any* code require some time spent with the language anyway?

I've worked in enterprise environments long enough to be extremely fearful of coders who parachute into a project and make changes without actually understanding what they're doing ("the code reads that way, I assumed it worked that way"), and then airlift out afterwards leaving the resulting mess to long-time fools like myself to clean up.  Maybe it's a bias from working in a primarily C environment where the language is inherently fragile and doesn't protect you from many common human errors, but I'm extremely skeptical of people who expect to just read code and understand it without actually learning the language for real. But OK, I'm just ranting, I'll shut up now. :-D


T

-- 
Genius may have its limitations, but stupidity is not thus handicapped. -- Elbert Hubbard
May 13, 2022
On Friday, 13 May 2022 at 18:23:58 UTC, H. S. Teoh wrote:
> On Thu, May 12, 2022 at 11:45:47PM +0000, Guillaume Piolat via
>> It's a problem because it goes from solving "no accidental race condition" and you get "people forget to add shared or __gshared and their shared library silently fail" situation. You could have none of that with explicit TLS.
>
> Valid point.

Yeah, I used to be pro-TLS by default, then got bit by it several times and moved to the fence, and now I'm anti.

Data races aren't actually prevented by it (maybe forcing you to specify shared or tls would at least get you think about it though) and lots of things mysteriously fail if you forget about it.

You can lock the variable and everything and it still null cuz it was tls the whole time. Oops.

This a case where I think forcing explitness would be better than either default, but failing that, tls by default is the more-bad choice.
May 13, 2022
On Fri, May 13, 2022 at 06:29:54PM +0000, Adam D Ruppe via Digitalmars-d-learn wrote: [...]
> Yeah, I used to be pro-TLS by default, then got bit by it several times and moved to the fence, and now I'm anti.
> 
> Data races aren't actually prevented by it (maybe forcing you to specify shared or tls would at least get you think about it though) and lots of things mysteriously fail if you forget about it.
> 
> You can lock the variable and everything and it still null cuz it was tls the whole time. Oops.
> 
> This a case where I think forcing explitness would be better than either default, but failing that, tls by default is the more-bad choice.

Personally I prefer avoiding globals at all. :-P  But OK, sometimes you can't work around it (or it'd be too onerous).  I guess maybe that's why I haven't been bitten by TLS so far. Hardly ever use it. :-D


T

-- 
"Outlook not so good." That magic 8-ball knows everything! I'll ask about Exchange Server next. -- (Stolen from the net)
May 13, 2022

On 5/13/22 2:29 PM, Adam D Ruppe wrote:

>

On Friday, 13 May 2022 at 18:23:58 UTC, H. S. Teoh wrote:

>

On Thu, May 12, 2022 at 11:45:47PM +0000, Guillaume Piolat via

>

It's a problem because it goes from solving "no accidental race condition" and you get "people forget to add shared or __gshared and their shared library silently fail" situation. You could have none of that with explicit TLS.

Valid point.

Yeah, I used to be pro-TLS by default, then got bit by it several times and moved to the fence, and now I'm anti.

Data races aren't actually prevented by it (maybe forcing you to specify shared or tls would at least get you think about it though) and lots of things mysteriously fail if you forget about it.

I disagree. I'd rather have a program fail in a way that is predictable and explainable than one with memory corruption or race conditions. In fact, I'd rather have 100 TLS confusion failures than one memory corruption failure.

Either way you will have failures due to under-specification. Which failures do you choose to debug?

Note that with the no shared access update, this will be more obvious of a mistake.

>

This a case where I think forcing explitness would be better than either default

Perhaps this would be reasonable. But I find the default reasonable too.

But we also have this confusing dynamic:

scope no attribute shared static
module TLS global TLS (no-op)
function local local! TLS
class instance global TLS

Honestly, if we changed static storage class to @tls, and then required it whenever you wanted TLS data, it would be a huge improvement.

-Steve

May 13, 2022

Is there any way we can get numbered errors like C++ / Microsoft have?

E2040 Declaration terminated incorrectly

Because then we could easily have a wiki for common error cases with code snippets of it occurring, and a fix for it. Common triggers of this error vs the proper code.

And a neat feature that Allegro.cc does, it automatically scans forum posts for usages of Allegro functions (e.g. al_draw_bitmap() man page will include links to posts that ask about al_draw_bitmap and has a Yes/No question next to it "was this a helpful post" so you can remove bad matches). Here it would be even easier than matching random questions because error codes are specific string literals ("E2040") and not some sort of regex attempt to match someone asking a question about 'R[][][] datatypes' or something like that.

Here is an example:

https://www.allegro.cc/manual/5/al_draw_bitmap

and an C++ error page:

https://docwiki.embarcadero.com/RADStudio/Sydney/en/E2040_Declaration_terminated_incorrectly_(C%2B%2B)

May 13, 2022

On Friday, 13 May 2022 at 21:07:12 UTC, Christopher Katko wrote:

>

Is there any way we can get numbered errors like C++ / Microsoft have?

E2040 Declaration terminated incorrectly

Because then we could easily have a wiki for common error cases with code snippets of it occurring, and a fix for it. Common triggers of this error vs the proper code.

And a neat feature that Allegro.cc does, it automatically scans forum posts for usages of Allegro functions (e.g. al_draw_bitmap() man page will include links to posts that ask about al_draw_bitmap and has a Yes/No question next to it "was this a helpful post" so you can remove bad matches). Here it would be even easier than matching random questions because error codes are specific string literals ("E2040") and not some sort of regex attempt to match someone asking a question about 'R[][][] datatypes' or something like that.

Here is an example:

https://www.allegro.cc/manual/5/al_draw_bitmap

and an C++ error page:

https://docwiki.embarcadero.com/RADStudio/Sydney/en/E2040_Declaration_terminated_incorrectly_(C%2B%2B)

We discussed this a while ago in a foundation meeting. The details didn't really get hashed out but I think we can definitely try it.

I have a PR which alters the error message you get if you do

void main()
{
  func() == 43;
}

This is an example of an error message which could be counterintuitive to a new D programmer, e.g. maybe they thought it would act like an assert or whatever, so we can link to a some html somewhere on dlang.org

May 14, 2022

On Friday, 13 May 2022 at 19:16:59 UTC, Steven Schveighoffer wrote:

>

But we also have this confusing dynamic:

scope no attribute shared static
module TLS global TLS (no-op)
function local local! TLS
class instance global TLS

There is a typo in your array, a shared field is per-instance, not global.

class A
{
   shared int c; // Each A has its own c
}