www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - What are (were) the most difficult parts of D?

reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
What are you stuck at? What was the most difficult features to 
understand? etc.

To make it more meaningful, what is your experience with other languages?

Ali
May 10 2022
next sibling parent reply bauss <jj_1337 live.dk> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
dip1000
May 11 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 May 2022 at 09:06:52 UTC, bauss wrote:
 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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
dip1000
Ha, I just mentioned this on another thread... https://dlang.org/spec/function.html#ref-return-scope-parameters
May 11 2022
prev sibling next sibling parent reply matheus <matheus gmail.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
I don't know if this will be helpful but here it goes, my user case is different since I use D as C on steroids. My first language was C and I have projects in this language which I still maintain and my brain is used to it, but depending the project I'll use D instead of C to use features like: GC, AA, Strings, Modules and maybe Classes if I feel like it, but I don't go to far from these and one reason is sometimes in a rich language with lots of features like D It gets hard to stay up to date. Now I know they must be useful to many others, but one thing that I don't like are the Attributes part, for me there are so many and this is a bit overwhelming (Again to me), for example need to think about: " safe, trusted, system" while still prototyping may be a cumbersome, and if it's giving me trouble I'll just get rid of it. :) Again I should sit and read the documentation or your book again but it's hard to keep up-to-date sometimes with work and so on. whatever was the version that runs with .Net 4.6, again this is another case of language changing or adding so many features that I decided not to go on with it, since it's not required where I work (Occasionally I write a few batch programs here and there), and I'm current doing more database business at the company these days, Sorry for any English mistakes, Matheus.
May 11 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, May 11, 2022 at 01:37:21PM +0000, matheus via Digitalmars-d-learn wrote:
 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.
 
 To make it more meaningful, what is your experience with other
 languages?
[...]
 Now I know they must be useful to many others, but one thing that I
 don't like are the Attributes part, for me there are so many and this
 is a bit overwhelming (Again to me), for example need to think about:
 " safe,  trusted,  system" while still prototyping may be a
 cumbersome, and if it's giving me trouble I'll just get rid of it. :)
[...] My suggestion is: when prototyping, don't even think about attributes. Just templatize your functions and let the compiler infer the attributes for you. I myself rarely bother with attributes; I only write them when I want to be 100% sure that a particular piece of code has that attribute. Otherwise I just templatize it and let the compiler figure it out for me. Auto-inference is the way to go; life is too short to be fiddling with attributes in every single declaration manually. T -- People walk. Computers run.
May 11 2022
parent reply Tejas <notrealemail gmail.com> writes:
On Wednesday, 11 May 2022 at 14:20:07 UTC, H. S. Teoh wrote:
 On Wed, May 11, 2022 at 01:37:21PM +0000, matheus via 
 Digitalmars-d-learn wrote:
 [...]
[...]
 [...]
[...] My suggestion is: when prototyping, don't even think about attributes. Just templatize your functions and let the compiler infer the attributes for you. I myself rarely bother with attributes; I only write them when I want to be 100% sure that a particular piece of code has that attribute. Otherwise I just templatize it and let the compiler figure it out for me. Auto-inference is the way to go; life is too short to be fiddling with attributes in every single declaration manually. T
That'll be true the day when ` safe` becomes the default... Until then, I'll atleast do ` safe:` on top of every module :)
May 11 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 11 May 2022 at 15:10:28 UTC, Tejas wrote:
 That'll be true the day when ` safe` becomes the default... 
 Until then, I'll atleast do ` safe:` on top of every module :)
` safe:` is actually a bad idea if you're writing templated code, because it turns inference of ` system` into a compile-time error: ```d safe: auto map(alias fun, T)(T[] arr) { auto result = arr.dup; foreach (ref e; result) e = fun(e); return result; } int safeDouble(int n) safe { return 2*n; } int systemDouble(int n) system { return 2*n; } void main() system { int[] a = [1, 2, 3]; // ok auto b = a.map!safeDouble; // Error: ` safe` function `map!systemDouble` cannot call ` system` function `systemDouble` auto c = a.map!systemDouble; } ``` Without ` safe:` at the top, `map!systemDouble` would have been inferred as ` system`, and calling it from a ` system` `main` function would have been allowed.
May 11 2022
parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, May 11, 2022 at 03:34:12PM +0000, Paul Backus via Digitalmars-d-learn
wrote:
 On Wednesday, 11 May 2022 at 15:10:28 UTC, Tejas wrote:
 That'll be true the day when ` safe` becomes the default... Until
 then, I'll atleast do ` safe:` on top of every module :)
` safe:` is actually a bad idea if you're writing templated code, because it turns inference of ` system` into a compile-time error:
Yeah, for templated code, what you want is a safe unittest that ensures that the code is safe when whatever you instantiate it with is safe: auto myTemplateFunc(Args...)(Args args) /* N.B.: no attributes */ { return ...; } safe unittest { // This ensures that myTemplateFunc is callable from // safe when instantiated with safe arguments. auto result = myTemplateFunc(... /* safe arguments */); } This way, it's possible to instantiate myTemplateFunc with system arguments (you get a system instantiation). T -- Life is unfair. Ask too much from it, and it may decide you don't deserve what you have now either.
May 11 2022
prev sibling next sibling parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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.
No singular feature, but the overall cognitive load if you use the language sporadic. Which could be most users that don't use it for work or have it as their main hobby. As with all languages, cognitive load increases when things do not work as one would intuitively expect or if a feature is incomplete in some specific case. D has some of the same issues as C++, you either deal with details or you can choose to go more minimalistic in your usage. If you read other people's D code you can easily (IMO) see that there is no unified style or usage of features, so it seems like people stick to their own understanding of «good code», which can make it tiresome to read D code by others (e.g. standard library). I guess some good coherent educational material is missing, people are finding their own way. There are no obvious codebases that highlight «best practice». I suspect meta-programming is pushed too much and that this has a negative effect on legibility of code bases. You basically increase the cognitive load further if you choose to be slightly different from other languages, and focus on special cases. Examples: the proposal for interpolated strings, dip1000, certain aspects of D's generics syntax etc. When you already have high cognitive load you should be very careful about not adding more "slightly unusual/unexpected" semantics/syntax.
 To make it more meaningful, what is your experience with other 
 languages?
I believe what makes Python a favoured language by many is that you can use it sporadically without relearning. Spending less time reading documentation is always a win. To do things right in C++ you have to look things up all the time, this is only ok for people who use it many hours every week. In general I think the ergonomics would be much better if the historical baggage from C/C++ had been pushed aside in favour of a more intuitive clean approach. I am not sure if many new users have a good understanding of C/C++ anyway. Of course, this perspective is highly irrelevant as it is clear now that the current direction of language evolution is to continue to absorb C and not really be provide a clean improvement over C, but more like an extension. (More like C++ and Objective-C than Rust). I think it will be difficult to attract young programmers with this approach as they are less likely to be comfortable with the peculiarities of C.
May 11 2022
prev sibling next sibling parent reply templatedperson <templated person.com> writes:
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.
I don't know if this counts as a feature, but reading the standard library documentation was especially difficult. There are a ton of `auto`s everywhere and function signatures are hard to read because of that. I got used to confusing function signatures in a week or two, but it made me consider not using D.
 To make it more meaningful, what is your experience with other 
 languages?
Rust does a better job at this. Generics are strongly-typed with `trait`s. In D, we have to type-check `struct`s ourselves by adding `if (is(T == SomeType))` etc. after the function declaration. In Rust, you can create a `trait` and use that as the parameter type in a function. In D we can have this with `interface`s when we're using `class`es but we can't have this for `struct`s. Actually, I'd appreciate if we could get `static interface`s or something, so that people won't need to type-check manually.
May 11 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 11:27, templatedperson wrote:

 I don't know if this counts as a feature, but reading the standard
 library documentation was especially difficult. There are a ton of
 `auto`s everywhere and function signatures are hard to read because of
 that. I got used to confusing function signatures in a week or two, but
 it made me consider not using D.
I agree with readability problems. And although you likely know why there are 'auto's everywhere in the standard library, I want to touch on that for others who may not know. Although templates are great, they bring naming problems: - Some names are overly complex and expose implementation details. - Some names are unmentionable because the implementation chose to make the return type a nested struct. import std.range; import std.algorithm; struct MyStruct { } void main() { auto arr = [ MyStruct() ]; auto r = arr.map!(o => o).cycle; pragma(msg, typeof(r)); } The type of the range object 'r' happens to be the scary Cycle!(MapResult!(__lambda2, MyStruct[])). But make a change e.g. by adding .enumerate to the expression auto r = arr.map!(o => o).enumerate.cycle; and now the type is very different (and deceptively simpler!): Cycle!(Result) So, there is nothing else to do in current D but to have 'auto' return types. Ali
May 11 2022
prev sibling next sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
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.
- How to do deterministic destruction with programs that use everything (struct / class / dynamic dispatch / GC / manual / etc). This requires to understand what the runtime does, what the gc does. Interesting nonetheless. - Some traps. Accidental TLS is a thing, top-level should probably not be silently TLS. People will loose hours on this completely preventable thing. What was the idea, optimize code without people knowing? - `shared static this()` vs `static this()` is another trap. Honestly would have preferred `__threadlocal`. It's not like being thread-local is something completely normal or without consequence for platform support. - Some features lack an escape hatch, notably `pure`. pure leaks into identifiers, like `pureMalloc`. Trying to add `pure` fails on a large codebase. - ` safe`/` trusted`/` system` is good but the definition of what ` trusted` means has to be remembered from the programmer. For example `Mutex.lock()` is ` trusted`, it could have been ` system` to let user review their usage of locks. You have to wonder "can a lock()/unlock() corrupt memory?". People can use that to mean " reviewed" instead. Because it is up to us, the exact meaning will float in the D subcultures. A function which has been marked ` trusted` does not receive any review whan changed later. It will not mean the same as ` trusted` in another codebase. - Generic code typically has bad names (domain-less) and worse usability. It's often not pretty to look at. Mostly cultural, since D has powerful templates so they had to be everywhere. UFCS chains are not that convincing when you are worried about maintenance. Phobos take short names for itself, this leads to pretty complicated operations having a small screen estate. - `assert(false)` being different and not removed by `-release`. Keyword reuse seems entrenched but honestly a "crash here" keyword would be more readable. It is really 3 different things: assert, crash, and unreachable. Otherwise D is glorious and get syntax and usability right, which puts it ahead of almost every other language.
May 11 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Wed, May 11, 2022 at 06:43:39PM +0000, Guillaume Piolat via
Digitalmars-d-learn wrote:
 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.
- How to do deterministic destruction with programs that use everything (struct / class / dynamic dispatch / GC / manual / etc). This requires to understand what the runtime does, what the gc does.
I'm not sure I fully understand what you're trying to say here. How does GC mix with deterministic destruction? I thought by the very nature of GC, destruction is non-deterministic. If you want deterministic destruction, don't use the GC...?
       Interesting nonetheless.
 
     - Some traps. Accidental TLS is a thing, top-level should probably
     not be silently TLS.
       People will loose hours on this completely preventable thing.
       What was the idea, optimize code without people knowing?
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.
     - `shared static this()` vs `static this()` is another trap.
One is per-process, one is per-thread. Why is this a trap? [...]
     - Some features lack an escape hatch, notably `pure`. pure leaks
     into identifiers, like `pureMalloc`. Trying to add `pure` fails on
     a large codebase.
IMNSHO, pureMalloc is a code smell. It should not have been added in the first place. But more to the point: pure is of limited utility. Perhaps the most useful application is the initialization of immutable data structures constructed by a mutable factory method. But other than that, I don't find very much use for it in practice. I wouldn't sweat it if I couldn't easily add `pure` to an entire codebase -- it hardly makes any difference anyway.
     - ` safe`/` trusted`/` system` is good but the definition of what
     ` trusted` means has to be remembered from the programmer.
But isn't that the nature of all escape hatches? An escape hatch by definition means you're operating outside of the abstractions provided by the compiler; IOW you're on your own and you take responsibility for any problems that you may inadvertently introduce by using the escape hatch.
       For example `Mutex.lock()` is ` trusted`, it could have been
       ` system` to let user review their usage of locks. You have to
       wonder "can a lock()/unlock() corrupt memory?". People can use
       that to mean " reviewed" instead. Because it is up to us, the
       exact meaning will float in the D subcultures. A function which
       has been marked ` trusted` does not receive any review whan
       changed later. It will not mean the same as ` trusted` in
       another codebase.
IMNSHO, trusted should never be used in public-facing APIs. It's really an implementation detail -- "this code does something using potentially dangerous operations, but we reviewed it carefully to make sure it's safe to call from safe code". The caller does NOT need to know this; as far as the caller is concerned, it's calling a safe function. That's all it knows and all that it should care about. How this safe function is implemented -- using completely safe operations or potentially dangerous operations ( trusted) isn't something the user should care about. That's something the author of the module needs to care about, but it's none of the users' business. IOW, public APIs should always be safe or system. trusted should only appear on internal APIs.
     - Generic code typically has bad names (domain-less) and worse
     usability. It's often not pretty to look at. Mostly cultural,
     since D has powerful templates so they had to be everywhere. UFCS
     chains are not that convincing when you are worried about
     maintenance.
I'm puzzled by this. I use (and write!) generic code all the time and they have been great. UFCS chains are awesome; they allow me to express a series of data transformations in a very concise way, so that I can keep the high-level logic of the function readable, without having to break it into separate functions. This, plus `auto` type inference, makes the code *more* maintainable, IME, because I can shuffle components of the UFCS chain around without needing to rewrite the types of a bunch of helper functions. So I'm curious, what exactly is it about UFCS chains that make it less maintainable?
       Phobos take short names for itself, this leads to pretty
       complicated operations having a small screen estate.
I'm also puzzled by this. Why is this a problem?
     - `assert(false)` being different and not removed by `-release`.
     Keyword reuse seems entrenched but honestly a "crash here" keyword
     would be more readable.
noreturn crashHere() { assert(false); } void main() { ... crashHere; // ;-) } [...]
 Otherwise D is glorious and get syntax and usability right, which puts
 it ahead of almost every other language.
Can't argue with that. T -- MACINTOSH: Most Applications Crash, If Not, The Operating System Hangs
May 12 2022
parent reply Guillaume Piolat <first.last gmail.com> writes:
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 12 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
parent reply Adam D Ruppe <destructionator gmail.com> writes:
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
next sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
prev sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
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
next sibling parent reply Christopher Katko <ckatko gmail.com> writes:
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
parent reply max haughton <maxhaton gmail.com> writes:
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 ```d 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 13 2022
next sibling parent zjh <fqbqrr 163.com> writes:
On Friday, 13 May 2022 at 21:54:04 UTC, max haughton wrote:

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

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

 This is an example of an error message which could be 
 counterintuitive to a new D programmer,
Can `D` support error messages in `multiple languages`? Such as `Chinese/German/Russian/Turkey`.
May 13 2022
prev sibling parent reply zjh <fqbqrr 163.com> writes:
On Friday, 13 May 2022 at 21:54:04 UTC, max haughton wrote:

Can `D` support error messages in `multiple languages`?
Such as `Chinese/German/Russian/Turkey`.
May 13 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/13/22 21:07, zjh wrote:
 On Friday, 13 May 2022 at 21:54:04 UTC, max haughton wrote:
 
 Can `D` support error messages in `multiple languages`?
 Such as `Chinese/German/Russian/Turkey`.
 
OT: It is unlikely but possible that posts are sometimes stopped by a spam filter. That must be why zjh tried to post this a second time. Ali
May 13 2022
parent reply zjh <fqbqrr 163.com> writes:
On Saturday, 14 May 2022 at 04:09:00 UTC, Ali Çehreli wrote:
 stopped by a spam filter.
Right. D forum should add a "`author delete`" function. Likewise, each post could add something like `votes` , good posts will naturally `come out` and be collected together. It's really convenient for beginners of `d`. This way, the similar answer does not have to be repeated.
May 13 2022
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Saturday, 14 May 2022 at 04:31:48 UTC, zjh wrote:

 Likewise, each post could add something like `votes` ,
Or something like all kinds of `tags` such as `range/fiber/commandline/auto ref/in/...`. Making `good use` of the `existing answers` in the forum will be very beneficial for `D` beginners. Moreover, `excellent d expert` do not have to repeat `previous answers`, and just provide a link.
May 13 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Sat, May 14, 2022 at 04:39:33AM +0000, zjh via Digitalmars-d-learn wrote:
 On Saturday, 14 May 2022 at 04:31:48 UTC, zjh wrote:
 
 Likewise, each post could add something like `votes` ,
Or something like all kinds of `tags` such as `range/fiber/commandline/auto ref/in/...`. Making `good use` of the `existing answers` in the forum will be very beneficial for `D` beginners. Moreover, `excellent d expert` do not have to repeat `previous answers`, and just provide a link.
[...] The D wiki could be used for this purpose. Whenever something in the forum is deemed worthy of long-term reference, somebody should copy it into an article on the wiki and link to it. T -- Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. -- Brian W. Kernighan
May 14 2022
parent zjh <fqbqrr 163.com> writes:
On Saturday, 14 May 2022 at 08:51:24 UTC, H. S. Teoh wrote:

 The D wiki could be used for this purpose.
Many of your posts are very good. I like them very much. Thank you. I haven't played with `wiki`. However, Maybe we can `organize and display` good posts according to `"author/category/label"` and put them in the `documents`. In this way, "d" novices can also use it offline to learn from them quickly.Because many posts are practical examples.It's very good. Moreover,`d` officials should reward `excellent posters` like submitting PR and encourage excellent answers. In this way, `D users/D expert(with good posts)/D language` all win!
May 14 2022
prev sibling parent reply frame <frame86 live.com> writes:
On Saturday, 14 May 2022 at 04:31:48 UTC, zjh wrote:

 D forum should add a "`author delete`" function.
 Likewise, each post could add something like `votes` , good 
 posts will naturally `come out` and be collected together.
 It's really convenient for beginners of `d`.

 This way, the similar answer does not have to be repeated.
My thoughts - I also mentioned this in another thread. I think the main problem is that this forum is linked as news group too with custom client software and not everyone is using the web interface, so there is less interest to bring this up. But I really wish the online forum would show newbies more activity by implementing topic specific categories or tags, so you could find them easier and feel more like "home". Every larger app with a news feed also has possibility to categorize/filter it.
May 14 2022
parent zjh <fqbqrr 163.com> writes:
On Saturday, 14 May 2022 at 12:46:45 UTC, frame wrote:
  Every
 larger app with a news feed also has possibility to 
 categorize/filter it.
I think we can set up a special `web page` to collect `good posts` and classify them according to `'author/category/label'`, and its content can be extracted directly from the forum. `Web pages` are just used to `organize` them. It can also be placed `offline` in the document. This is very good if there is enough content ,It will greatly reduce the `threshold` of D . Avoid others saying that no one can understand `d`.
May 14 2022
prev sibling parent Guillaume Piolat <first.last gmail.com> writes:
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 }
May 13 2022
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
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.
Also, if you intend to use the responses for planning purposes, keep in mind that people who read the forums regularly are more informed about pitfalls than other users. Forum-dwellers have a richer understanding of the landscape and probably view the feature set in a different light.
May 11 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 12:20, Ola Fosheim Grøstad wrote:
 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.
Also, if you intend to use the responses for planning purposes
No. :) I was hoping to get responses like "I come from Python and have no idea what templates are", "I come from C and have no idea what reference types are." Or exceptions, ranges, etc. Ali
May 11 2022
prev sibling next sibling parent reply Christopher Katko <ckatko gmail.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Every time I think I understand D, I don't. Cool useful library functions like sumElement that magically don't work on static arrays. 'private' is per module, not per class, making it pretty much useless for preventing incorrect access and using . completely different semantics for a class vs a struct. Is it a reference? Is it a value? Look up the entire declaration and have the entire Dlang manual open to find out. As far as I remember, no automatic RAII support, even though it's insanely useful. You have to manually write scope(end) stuff which means any person forgetting one is now leaking memory. Writing output in a deconstuctor (for learning) works. But then you accidentally combine two strings inside it and the garbage collecter crashes without a stack trace. Documentation. Documentation. Documentation. I just realized foreach copies by value by default. Maybe. Sometimes. When? I don't even know anymore. Because I "thought" I had to use foreach(ref) to be able to affect the original data structure (because by value means its a copy, right?). Except somehow everything has been working just fine, mutating the original structure/array from inside foreach and adding foreach(ref) makes no changes. Will it be faster? Maybe... who knows. And I really like D! But there's lots of "WTF" moments. There's so much I have to Google for a single forum post with dead links from 2014 which is only 30% like my use-case that describes my error or problem.
May 11 2022
next sibling parent Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 12 May 2022 at 01:06:02 UTC, Christopher Katko wrote:
 completely different semantics for a class vs a struct. Is it a 
 reference? Is it a value? Look up the entire declaration and 
 have the entire Dlang manual open to find out.

 As far as I remember, no automatic RAII support, even though 
 it's insanely useful.
class = virtual functions struct = RAII
May 11 2022
prev sibling next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/11/22 9:06 PM, Christopher Katko wrote:

 I just realized foreach copies by value by default. Maybe. Sometimes. 
 When? I don't even know anymore. Because I "thought" I had to use 
 foreach(ref) to be able to affect the original data structure (because 
 by value means its a copy, right?). Except somehow everything has been 
 working just fine, mutating the original structure/array from inside 
 foreach and adding foreach(ref) makes no changes. Will it be faster? 
 Maybe... who knows.
ref can be confusing depending on the type. foreach indeed does everything by value unless you specify ref. But some types "act like" a ref. Remember, the copy is a *shallow* copy. So a "copy" of an array slice, for example, still refers to the original elements. -Steve
May 11 2022
prev sibling next sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 18:06, Christopher Katko wrote:

 Cool useful library functions like sumElement that magically don't work
 on static arrays.
Yeah, that sometimes gets me as well. Although it is trivial to deal with, the programmer may be surprised by the strange error messages: int[3] arr = [ 1, 2, 3 ]; assert(sum(arr) == 6); Error: template `std.algorithm.iteration.sum` cannot deduce function from argument types `!()(int[3])` /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: `sum(R)(R r)` with `R = int[3]` must satisfy the following constraint: ` isInputRange!R` WHAT? :) But the clue is on the last line above. For completeness and for people who may not know the reason, D's static arrays and dynamic arrays are different in a number of ways but what matters here is that static arrays are not ranges because they cannot shrink. (Arguably, static arrays could be RandomAccessRanges but D's range hierarchy does not allow RandomAccessRanges that are not also InputRanges and ForwardRanges.) So, the commented-out assert below cannot be compiled but the two following lines do compile by simply adding the two characters [] to get a range to all elements: import std.algorithm; void main() { int[3] arr = [ 1, 2, 3 ]; // assert(sum(arr) == 6); assert(sum(arr[]) == 6); assert(arr[].sum == 6); }
 'private' is per module, not per class, making it pretty much useless
 for preventing incorrect access and using .
My view on private has changed over the years. I need to be convinced that there is usage that needs to be protected. :) I don't see people using types freely especially the ones that are in the same module. The only argument for private is to allow changing the implementation of published libraries in the future. Still, private could have been a convention like naming variables with an underscore (which Go chose) and it could have been as effective. People who went around the convention and accessed the private members would either be happy or deserved what they got. I really don't see any problem on this matter for a programming language to go out of their way to protect people from themselves. I started wondering as I wrote those: Perhaps IDEs make this a bigger issue? If they do respect private/public, perhaps they include member names in menus to pick from and the programmer does not want to see the private members there?
 I just realized foreach copies by value by default. Maybe. Sometimes.
 When?
It is always by-value when passing parameters and in foreach (which can be defined by opApply) and everywhere else. As Steve said, the confusion is when the copied thing is a reference itself. You end up getting another reference to data. Ali
May 12 2022
next sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, May 12, 2022 at 09:04:09AM -0700, Ali ehreli via Digitalmars-d-learn
wrote:
 On 5/11/22 18:06, Christopher Katko wrote:
 
 Cool useful library functions like sumElement that magically don't
 work on static arrays.
Yeah, that sometimes gets me as well. Although it is trivial to deal with, the programmer may be surprised by the strange error messages: int[3] arr = [ 1, 2, 3 ]; assert(sum(arr) == 6); Error: template `std.algorithm.iteration.sum` cannot deduce function from argument types `!()(int[3])` /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): Candidates are: `sum(R)(R r)` with `R = int[3]` must satisfy the following constraint: ` isInputRange!R` WHAT? :) But the clue is on the last line above.
[...] Seriously though, that error message is horrendously ugly. I mean I've seen it thousands of times by now, so I know what it means and where to look for the actual problem. But it's eminently unfriendly to someone who doesn't already know the language very well. T -- A mathematician learns more and more about less and less, until he knows everything about nothing; whereas a philospher learns less and less about more and more, until he knows nothing about everything.
May 12 2022
parent reply Paul Backus <snarwin gmail.com> writes:
On Thursday, 12 May 2022 at 18:07:05 UTC, H. S. Teoh wrote:
 On Thu, May 12, 2022 at 09:04:09AM -0700, Ali Çehreli via 
 Digitalmars-d-learn wrote:
 Error: template `std.algorithm.iteration.sum` cannot deduce 
 function from
 argument types `!()(int[3])`
 /usr/include/dlang/dmd/std/algorithm/iteration.d(7234): 
 Candidates are:
 `sum(R)(R r)`
   with `R = int[3]`
   must satisfy the following constraint:
 `       isInputRange!R`
 
 WHAT? :) But the clue is on the last line above.
[...] Seriously though, that error message is horrendously ugly. I mean I've seen it thousands of times by now, so I know what it means and where to look for the actual problem. But it's eminently unfriendly to someone who doesn't already know the language very well.
Good news: starting from DMD 2.099, this error message has been reworded. Instead of "cannot deduce function...". it now says: Error: none of the overloads of template `std.algorithm.iteration.sum` are callable using argument types `!()(int[3])`
May 12 2022
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/12/22 12:00, Paul Backus wrote:

 Good news: starting from DMD 2.099, this error message has been
 reworded. Instead of "cannot deduce function...". it now says:

 Error: none of the overloads of template `std.algorithm.iteration.sum`
 are callable using argument types `!()(int[3])`
Much better. An idea: The compiler should be able to detect static arrays and also suggest slicing with something like "slicing as in `arr[]` might work". Ali
May 12 2022
prev sibling parent reply Chris Katko <ckatko gmail.com> writes:
On Thursday, 12 May 2022 at 16:04:09 UTC, Ali Çehreli wrote:
 My view on private has changed over the years. I need to be 
 convinced that there is usage that needs to be protected. :) I 
 don't see people using types freely especially the ones that 
 are in the same module. The only argument for private is to 
 allow changing the implementation of published libraries in the 
 future.
I use private as part of my rapid dev process. You write code, you get things working with no real worry for correctness or careful interfaces. You cannot make an interface until you actually know what you're making. So you make things, with "bad" connections. Then you remove those connections. 1. Get system working with lots of direct access to class variables. 2. Make those variables forbidden (through private in C++). 3. The compiler now shows you every instance of your new interface encapsulation violations. No human decision to opt-in. No remembering to search. You have an automatically generated list of violations to fix. I do the same thing with a module called "g" (for globals). I write new code into g, get it working. I can see how "dirty" a file is by simply searching for how many references to the module g there are. Then if I move the code into a proper new module, all references to g magically fail. It is impossible for me to leave dangling old code touching naughty internals, and I get a nice error view of all areas that need attention. If the uses are all over the place and not in only a few areas (instead of just in logic() and draw(), but all over the place) then I know I need to rewrite and introduce a system so everything is mostly in one place. 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.
May 12 2022
parent zjh <fqbqrr 163.com> writes:
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 12 2022
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, May 12, 2022 at 01:06:02AM +0000, Christopher Katko via
Digitalmars-d-learn wrote:
[...]
 Cool useful library functions like sumElement that magically don't
 work on static arrays.
Just slice it with []: int[5] data = [ 1, 2, 3, 4, 5 ]; auto sum = data[].sumElement; The main reason is that static arrays cannot shrink (their length is constant), so they don't qualify as ranges. No problem, [] takes a slice of them that *can* shrink.
 'private' is per module, not per class, making it pretty much useless
 for preventing incorrect access and using .
This is a common complaint. But IME, I haven't really run into problems with it. Accessing private members really only becomes a problem when you have multiple separate modules interacting with each other. If a module has grown large enough that this starts becoming a problem, it's usually a sign that it's time to refactor the module into two (or more) smaller ones.
 completely different semantics for a class vs a struct. Is it a
 reference?  Is it a value? Look up the entire declaration and have the
 entire Dlang manual open to find out.
class == by reference struct == by value Very straightforward.
 As far as I remember, no automatic RAII support, even though it's
 insanely useful. You have to manually write scope(end) stuff which
 means any person forgetting one is now leaking memory.
??? Structs with dtors have RAII. You only need scope(exit) if you're manually managing resources. What exactly are you referring to here?
 Writing output in a deconstuctor (for learning) works. But then you
 accidentally combine two strings inside it and the garbage collecter
 crashes without a stack trace.
Yeah, class dtors and GC don't mix, in general. There was a proposal to remove class dtors from the language some years ago. But it didn't happen, probably because more people complained about that than about dtors not being allowed to allocate memory or access GC'd resources. :-D
 Documentation. Documentation. Documentation.
[...] What exactly is wrong with the docs? A concrete list of actionable items would be nice. (I admit the docs could use some improvements, btw.) T -- "I'm not childish; I'm just in touch with the child within!" - RL
May 12 2022
prev sibling next sibling parent reply zjh <fqbqrr 163.com> writes:
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.
I don't know the progress of `interface to C++`. I want to use my C++ functions in `d`. `C++`'s `concept` and `...` is very convenient.
May 11 2022
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Thursday, 12 May 2022 at 02:35:50 UTC, zjh wrote:

 `C++`'s `concept` and `...` is very convenient.
And C++'s `stackless coroutine`.
May 11 2022
parent zjh <fqbqrr 163.com> writes:
On Thursday, 12 May 2022 at 02:40:09 UTC, zjh wrote:

 And C++'s `stackless coroutine`.
Another one, I hope the `error message` can be adapted to different languages like `chinese/german/russion/turkish` etc.
May 11 2022
prev sibling parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/11/22 19:35, zjh wrote:
 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.
I don't know the progress of `interface to C++`. I want to use my C++ functions in `d`.
That direction is easier: https://dlang.org/spec/cpp_interface.html#calling_global_d_functions_from_cpp (Also see "Using D Classes From C++" on the same page.) The problem is calling into C++ where C++ templates are involved. As D does not include a C++ compiler, it cannot instantiate C++ templates automatically. (The programmer must instantiate explicitly as needed on the C++ side.) Ali
May 12 2022
prev sibling next sibling parent Siemargl <inqnone gmail.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
When i take old library from a dub or github and cannot compile it with latest compiler because of small and subtle language changes. For example https://github.com/buggins/dlangide/pull/410/commits/43a82ed2f45143270482aa94c447e577174f0108#diff-375ecd44ef501b93adc6106fe404f55d353e667c21681c1c13a9e2008510ab42L937 I dont know even now, which D's features changes here.
May 11 2022
prev sibling next sibling parent reply Basile B. <b2.temp gmx.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Overhall I think that D was not hard to learn because well designed (i.e intuitive). A few specific points however that I remember - Certain variant forms of the `is` Expression are not obvious (not intuitive), I'm pretty sure I still cant use them without a quick look to the specs. - Operator overloading in certain cases was confusing, I remember that for one particular form once I had to use your book instead of the official specs (when opSlice and opIndex are combined) The main difficulty I had is actually not specific to D. It was to accept that a GC is OK.
May 12 2022
next sibling parent reply Alain De Vos <devosalain ymail.com> writes:
Some keywords are overloaded and have different meaning when used 
in a different place.
Also some syntactic-sugar is way to much meaning too many 
different ways to do the same thing. I would prefer one way which 
is advised.
May 12 2022
parent reply Basile B. <b2.temp gmx.com> writes:
On Thursday, 12 May 2022 at 11:50:59 UTC, Alain De Vos wrote:
 Some keywords are overloaded and have different meaning when 
 used in a different place.
 Also some syntactic-sugar is way to much meaning too many 
 different ways to do the same thing. I would prefer one way 
 which is advised.
`ptr1 is ptr2` VS `is(T==U)` is ok even if the keyword is reused for two different things. Problem is more (from https://dlang.org/spec/expression.html#is_expression) ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it.
May 12 2022
next sibling parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:
 On Thursday, 12 May 2022 at 11:50:59 UTC, Alain De Vos wrote:
 Some keywords are overloaded and have different meaning when 
 used in a different place.
 Also some syntactic-sugar is way to much meaning too many 
 different ways to do the same thing. I would prefer one way 
 which is advised.
`ptr1 is ptr2` VS `is(T==U)` is ok even if the keyword is reused for two different things. Problem is more (from https://dlang.org/spec/expression.html#is_expression) ``` is ( Type : TypeSpecialization , TemplateParameterList ) is ( Type == TypeSpecialization , TemplateParameterList ) is ( Type Identifier : TypeSpecialization , TemplateParameterList ) is ( Type Identifier == TypeSpecialization , TemplateParameterList ) ``` I never remember those variants, because basically you never need them... They were required for std.traits and that's it.
Perfect example of reuse that is never a problem : `final`. what statically does `is` should have been several `__traits` I think.
May 12 2022
prev sibling next sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:
 [snip]
 ```
 is ( Type : TypeSpecialization , TemplateParameterList )
 is ( Type == TypeSpecialization , TemplateParameterList )
 is ( Type Identifier : TypeSpecialization , 
 TemplateParameterList )
 is ( Type Identifier == TypeSpecialization , 
 TemplateParameterList )
 ```

 I never remember those variants, because basically you never 
 need them...
 They were required for std.traits and that's it.
What's the difference between a Type and Type Identifier?
May 12 2022
next sibling parent Tejas <notrealemail gmail.com> writes:
On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:
 On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:
 [snip]
 ```
 is ( Type : TypeSpecialization , TemplateParameterList )
 is ( Type == TypeSpecialization , TemplateParameterList )
 is ( Type Identifier : TypeSpecialization , 
 TemplateParameterList )
 is ( Type Identifier == TypeSpecialization , 
 TemplateParameterList )
 ```

 I never remember those variants, because basically you never 
 need them...
 They were required for std.traits and that's it.
What's the difference between a Type and Type Identifier?
`int`, `char` and friends are `Type` In `int a`, `string c`, `a` and `c` are `Identifier`s
May 12 2022
prev sibling next sibling parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 5/12/22 11:18 AM, jmh530 wrote:
 On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:
 [snip]
 ```
 is ( Type : TypeSpecialization , TemplateParameterList )
 is ( Type == TypeSpecialization , TemplateParameterList )
 is ( Type Identifier : TypeSpecialization , TemplateParameterList )
 is ( Type Identifier == TypeSpecialization , TemplateParameterList )
 ```

 I never remember those variants, because basically you never need them...
 They were required for std.traits and that's it.
What's the difference between a Type and Type Identifier?
Type is a type, Identifier is an identifier. In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type. So e.g.: ```d static if(is(Foo Bar == struct)) { // inside here, it was determined that `Foo` was a type, and it is a // struct, and now, `Bar` is aliased to `Foo` } ``` It's very confusing syntax though. -Steve
May 12 2022
parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 12 May 2022 at 15:31:03 UTC, Steven Schveighoffer 
wrote:
 On 5/12/22 11:18 AM, jmh530 wrote:
 On Thursday, 12 May 2022 at 12:13:32 UTC, Basile B. wrote:
 [snip]
 ```
 is ( Type : TypeSpecialization , TemplateParameterList )
 is ( Type == TypeSpecialization , TemplateParameterList )
 is ( Type Identifier : TypeSpecialization , 
 TemplateParameterList )
 is ( Type Identifier == TypeSpecialization , 
 TemplateParameterList )
 ```

 I never remember those variants, because basically you never 
 need them...
 They were required for std.traits and that's it.
What's the difference between a Type and Type Identifier?
Type is a type, Identifier is an identifier. In general, after such expressions, Identifier is now declared as an alias to the type, if the is expression was true. But in special forms, it might be a portion of the type. So e.g.: ```d static if(is(Foo Bar == struct)) { // inside here, it was determined that `Foo` was a type, and it is a // struct, and now, `Bar` is aliased to `Foo` } ``` It's very confusing syntax though. -Steve
yess that kind of stuff
May 12 2022
prev sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:
 What's the difference between a Type and Type Identifier?
The is expression roughly follows variable declaration style. You write int a; to declare a new symbol named `a` of type `int`. Similarly, static if(is(T a)) declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.) The Identifier is optional.
May 12 2022
parent jmh530 <john.michael.hall gmail.com> writes:
On Thursday, 12 May 2022 at 15:32:24 UTC, Adam D Ruppe wrote:
 On Thursday, 12 May 2022 at 15:18:34 UTC, jmh530 wrote:
 What's the difference between a Type and Type Identifier?
The is expression roughly follows variable declaration style. You write int a; to declare a new symbol named `a` of type `int`. Similarly, static if(is(T a)) declares a new symbol of type `a` if `T` is a valid type. (Of course, in this case, a and T are aliases of each other, so it isn't super useful, but in the more complex matches using the == and : operators, it might be different.) The Identifier is optional.
Ah, yeah I know about that.
May 12 2022
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, May 12, 2022 at 12:13:32PM +0000, Basile B. via Digitalmars-d-learn
wrote:
[...]
 Problem is more (from https://dlang.org/spec/expression.html#is_expression)
 
 ```
 is ( Type : TypeSpecialization , TemplateParameterList )
 is ( Type == TypeSpecialization , TemplateParameterList )
 is ( Type Identifier : TypeSpecialization , TemplateParameterList )
 is ( Type Identifier == TypeSpecialization , TemplateParameterList )
 ```
 
 I never remember those variants, because basically you never need
 them...  They were required for std.traits and that's it.
Not true. I use these all the time in generic code. Basically, they allow you to do IFTI-like template pattern-matching using static-if's. This is eminently useful for inspecting incoming types in template functions. For example, in serialization code, I would do something like: auto serialize(T)(T data) { static if (is(T == string)) { ... // straightforward string encoding } else static if (is(T : U[], U)) // this means: "T matches the pattern `U[]`, // where U is some arbitrary type" { ... // non-string array encoding // note that in this block, `U` is defined to be // the array element; very convenient for // further type dissection } else static if (is(T : U[V], U, V)) // this means: "T matches the pattern `U[V]`, // where U and V are arbitrary types" { ... // AA encoding // similarly, in this block U is the value type // and V is the key type, very convenient for // further type dissection } else static if (is(T : MyType!(U), string U)) // this means: "T matches the pattern // `MyType!(U)` where U is some string" { ... // special handling for instantiations of // MyType with string argument // in this block, U == string } ... // and so on } I concede that the documentation isn't exactly easy to understand on a first read; it took me many tries before it "clicked". But once you understand the general pattern, most of the cases make sense and is pretty predictable. There *are* one or two special cases, granted, but those are exceptional and there are already std.traits wrappers that expose a friendlier API. The worst offender in this category is __parameters, about which I wrote years ago here: https://forum.dlang.org/thread/vpjpqfiqxkmeavtxhyla forum.dlang.org Still, putting this ugly special case aside, the rest of is(...) syntax mostly conforms to the above pattern, and is readily understandable once you learn the pattern. T -- Written on the window of a clothing store: No shirt, no shoes, no service.
May 12 2022
prev sibling next sibling parent reply Arjan <arjan ask.me.to> writes:
On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote:
 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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Overhall I think that D was not hard to learn because well designed (i.e intuitive).
I concur..
 A few specific points however that I remember

 - Certain variant forms of the `is` Expression are not obvious 
 (not intuitive), I'm pretty sure I still cant use them without 
 a quick look to the specs.
Yes indeed, had to read through the then excellent pdf()https://github.com/PhilippeSigaud/D-templates-tutorial by Philippe Sigaud (of PEG) to grasp the whole idea first, and still have to look it up when the need to use it arises...
 - Operator overloading in certain cases was confusing, I 
 remember that for one particular form once I had to use your 
 book instead of the official specs (when opSlice and opIndex 
 are combined)
Indeed same experience. Also opCmp and opEquals caused some confusion. D's [][] !== C's [][], Range peculiarities w.r.t some algo's (algo want's fwdRange but got inputRange but did not have the constraint ea) lazy vs eager algorithms (the need to call .array)
 The main difficulty I had is actually not specific to D. It was 
 to accept that a GC is OK.
Nice one. I recon I have to think much harder sometimes to know where the data is and 'who' has access: stack heap tls mutexed or not whatever, but find myself almost never asking this question anymore in D, which I use(d) to do almost all the time in c++ land. The need for it is almost removed by D.
May 12 2022
parent Basile B. <b2.temp gmx.com> writes:
On Thursday, 12 May 2022 at 14:06:13 UTC, Arjan wrote:
 On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote:
 On Wednesday, 11 May 2022 at 05:41:35 UTC, Ali Çehreli wrote:

 - Operator overloading in certain cases was confusing, I 
 remember that for one particular form once I had to use your 
 book instead of the official specs (when opSlice and opIndex 
 are combined)
I still have the thing : ```d /** * CharMap is an helper struct that allows to test * if a char is within a set of characters. */ struct CharMap { private bool[] _map; private dchar _min, _max; private void setMinMax(dchar value) pure nothrow safe { if (value <= _min) _min = value; else if (value >= _max) _max = value; _map.length = _max + 1 - _min; } /** * Used in the construction process. * * Params: * lo = The dchar that defines the range lower bound. * hi = The dchar that defines the range upper bound (inclusive). * * Examples: * --- * CharMap cm = CharMap['0'..'9']; * --- */ static CharRange opSlice(int index)(dchar lo, dchar hi) pure nothrow safe nogc { return CharRange(lo, hi); } /** * Used in the construction process. * * Params: * a = A list made of character slices, of single characters or * * any other values whose type is implicitly convertible to dchar. * * Examples: * --- * CharMap cm = CharMap['0'..'9', '.', 'f', 'd', 38, 39]; * --- */ static CharMap opIndex(A...)(A a) pure nothrow safe { CharMap result; // bounds foreach(elem; a) { alias T = typeof(elem); static if (isSomeChar!T || isImplicitlyConvertible!(T, dchar)) { result.setMinMax(elem); } else static if (is(T == CharRange)) { result.setMinMax(elem._min); result.setMinMax(elem._max); } else static assert(0, "unsupported opIndex argument type: " ~ T.stringof); } result._map[] = false; foreach(elem; a) { alias T = typeof(elem); static if (isSomeChar!T || isImplicitlyConvertible!(T, dchar)) result._map[elem - result._min] = true; else static if (is(T == CharRange)) { foreach(size_t i; elem._min - result._min .. elem._max - result._min + 1) result._map[i] = true; } } return result; } /** * Returns true if a character is within the map. * * Params: * c = A character or any value convertible to a dchar. */ bool opBinaryRight(string op = "in", C)(C c) const pure nothrow safe nogc if (op == "in") { static if (isSomeChar!C || isImplicitlyConvertible!(C, dchar)) { if (_min > c || c > _max) return false; else return _map[c - _min]; } else static assert(0, `invalid argument type for CharMap.opBinaryRight!"in"(): ` ~ C.stringof); } } /// pure safe unittest { CharMap cm = CharMap['a'..'f', '0'..'9' , 'A'..'F', '_', 9]; assert('a' in cm); assert('b' in cm); assert('c' in cm); assert('d' in cm); assert('e' in cm); assert('f' in cm); assert('g' !in cm); assert('A' in cm); assert('B' in cm); assert('C' in cm); assert('D' in cm); assert('E' in cm); assert('F' in cm); assert('G' !in cm); assert('0' in cm); assert('4' in cm); assert('9' in cm); assert('_' in cm); assert('%' !in cm); assert('\t' in cm); } ```
May 12 2022
prev sibling parent reply Guillaume Piolat <first.last gmail.com> writes:
On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote:
 - Certain variant forms of the `is` Expression are not obvious 
 (not intuitive), I'm pretty sure I still cant use them without 
 a quick look to the specs.
That one was a trouble to hear about => http://p0nce.github.io/d-idioms/#Get-parent-class-of-a-class-at-compile-time
May 12 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 5/12/22 07:28, Guillaume Piolat wrote:
 On Thursday, 12 May 2022 at 11:05:08 UTC, Basile B. wrote:
 - Certain variant forms of the `is` Expression are not obvious (not
 intuitive), I'm pretty sure I still cant use them without a quick look
 to the specs.
That one was a trouble to hear about =>
http://p0nce.github.io/d-idioms/#Get-parent-class-of-a-class-at-compile-time Cool trick but "parent" confused me there. I think you mean "base". :) It looks like there is an alternative now: https://dlang.org/phobos/std_traits.html#BaseTypeTuple Ali
May 12 2022
parent Guillaume Piolat <first.last gmail.com> writes:
On Thursday, 12 May 2022 at 16:24:26 UTC, Ali Çehreli wrote:
 Cool trick but "parent" confused me there. I think you mean 
 "base". :)
https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming mentions "base class" as much as "parent class"
May 12 2022
prev sibling next sibling parent reply Anonymouse <zorael gmail.com> writes:
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.
I came from shell scripts. They grew too large and overly complex when I wanted to do non-trivial things in a neat way, so I looked to proper programming languages and arbitrarily settled on D over python and similar. So for me the norm is D, and everything else is "other languages". That said, one thing I cannot seem to firmly wrap my head around is `is` expressions. `is` does so many things. There's probably more intricate examples of how it's confusing, but I don't know it well enough to construe one: ``` alias AA = long*[string]; static if (is(AA whatEvenGoesHere : VP[K], VP, K)) { static if(is(VP : V*, V)) { assert(is(V)); } } ``` The one thing that has caused me most anguish and woe is hands-down https://issues.dlang.org/show_bug.cgi?id=18026 though. It hasn't bit me for a while now, but the feeling of uncertainty, that the compiler might just suddenly after an innocent change no longer compile your project, seemingly outside of your control, is just... disheartening when it happens.
May 12 2022
next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 12 May 2022 at 14:42:43 UTC, Anonymouse wrote:
 That said, one thing I cannot seem to firmly wrap my head 
 around is `is` expressions. `is` does so many things.
It is simpler than it looks, I wrote about it in my book and in a post here: https://forum.dlang.org/post/xklcgjaqggihvhctczxx forum.dlang.org
 ```
 alias AA = long*[string];
 static if (is(AA whatEvenGoesHere : VP[K], VP, K))
You don't have to put anything there. The is expression kinda parallels declarations, so that thing would be the name for the newly declared symbol. But you don't need to declare a new symbol there so you can leave it blank; most the pieces are optional.
 The one thing that has caused me most anguish and woe is 
 hands-down https://issues.dlang.org/show_bug.cgi?id=18026 
 though.
yeah bugs happen.
May 12 2022
parent Anonymouse <zorael gmail.com> writes:
On Thursday, 12 May 2022 at 15:17:10 UTC, Adam D Ruppe wrote:
 It is simpler than it looks, I wrote about it in my book and in 
 a post here:

 https://forum.dlang.org/post/xklcgjaqggihvhctczxx forum.dlang.org
"Then commas separate the definitions of each placeholder variable, just as if they were template argument definitions [...]" That... makes sense, I didn't think of them like that.
May 12 2022
prev sibling parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Thu, May 12, 2022 at 02:42:43PM +0000, Anonymouse via Digitalmars-d-learn
wrote:
[...]
 The one thing that has caused me most anguish and woe is hands-down
 https://issues.dlang.org/show_bug.cgi?id=18026 though. It hasn't bit
 me for a while now, but the feeling of uncertainty, that the compiler
 might just suddenly after an innocent change no longer compile your
 project, seemingly outside of your control, is just... disheartening
 when it happens.
static foreach isn't meant to handle large loops. Writing `static foreach (i; 0 .. 60000)` is generally a bad idea; my suspicion is that the compiler ran out of stack space). It's more for unfolding groups of statements or declarations like cases in a switch-statement. For complex loops, what you really want is to use CTFE, which has a proper interpreter that can execute real code, instead of static foreach. What I'd do in the case described in comment 20 is to use CTFE to generate an array of indices that satisfy the predicate (it can create this array however it wants), then static foreach over this array, instead of iterating from 0 to 60000 directly. Or, in certain cases, you might want to just try straight foreach instead of static foreach, just make a tuple of your indices first and it will auto-unroll. T -- Не дорог подарок, дорога любовь.
May 12 2022
parent Anonymouse <zorael gmail.com> writes:
On Thursday, 12 May 2022 at 16:48:05 UTC, H. S. Teoh wrote:
 static foreach isn't meant to handle large loops. Writing 
 `static foreach (i; 0 .. 60000)` is generally a bad idea; my 
 suspicion is that the compiler ran out of stack space).  It's 
 more for unfolding groups of statements or declarations like 
 cases in a switch-statement.
I understand, but I don't think I had any static foreaches in my
May 12 2022
prev sibling next sibling parent Salih Dincer <salihdb hotmail.com> writes:
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 12 2022
prev sibling next sibling parent reply eugene <dee0xeed gmail.com> writes:
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.
Garbage collection. I am not programming languages theorist at at, but my imression is: * GC came from purely functional languages where everything is immutable * GC in Haskel (for ex.) seems very natural and even absolutely necessary * GC is some kind of fashion and languages inventors try to put it to everywhere (golang)
 To make it more meaningful, what is your experience with other 
 languages?
GC looks very strange in C/C++ (done right, yeah) successor.
May 14 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 15/05/2022 2:51 AM, eugene wrote:
 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.
Garbage collection. I am not programming languages theorist at at, but my imression is: * GC came from purely functional languages where everything is immutable * GC in Haskel (for ex.) seems very natural and even absolutely necessary * GC is some kind of fashion and languages inventors try to put it to everywhere (golang)
Garbage Collectors solve some really hard problems in regards to memory management. Some high performance data structures require it for memory reclamation and there is no alternative to it. It is a very good base line for memory management when you do not care about its life time. The more I have studied memory allocators & management strategies the more I wish I could go back to just relying on the GC and being naive. They really are amazing for most programs. And in case anyone is interested, a book recommendation: https://www.amazon.com/Garbage-Collection-Handbook-Management-Algorithms/dp/1420082795
May 14 2022
parent reply eugene <dee0xeed gmail.com> writes:
On Saturday, 14 May 2022 at 15:04:55 UTC, rikki cattermole wrote:
 Garbage Collectors solve some really hard problems in regards 
 to memory management.
i've *never* encountered "really hard problems" with manual memory management in C.
 It is a very good base line for memory management when you do 
 not care about its life time.
I *do* care about its life-time
 The more I have studied memory allocators & management 
 strategies
memory allocators and GC are different things i've had at some point 'free list' based allocator and it worked ~3 times faster than malloc/free when used for classical linked list implementation.
 They really are amazing for most programs.
one-shot programs? ,)
May 14 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 15/05/2022 4:00 AM, eugene wrote:
 The more I have studied memory allocators & management strategies
memory allocators and GC are different things i've had at some point 'free list' based allocator and it worked ~3 times faster than malloc/free when used for classical linked list implementation.
GC's are deeply entwined with their memory allocators. They have their own dedicated one tuned to their characteristics (say thread handling). Even if they still call out to malloc to map blocks.
May 14 2022
parent eugene <dee0xeed gmail.com> writes:
On Saturday, 14 May 2022 at 16:08:34 UTC, rikki cattermole wrote:
 On 15/05/2022 4:00 AM, eugene wrote:
 The more I have studied memory allocators & management 
 strategies
memory allocators and GC are different things i've had at some point 'free list' based allocator and it worked ~3 times faster than malloc/free when used for classical linked list implementation.
GC's are deeply entwined with their memory allocators.
this does not mean that GC and MA are not different thigs.
May 14 2022
prev sibling next sibling parent reply cc <cc nevernet.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Immutability. Ended up having to do so many hundreds of casts to and from immutable(whatever) the amount of mental strain greatly exceeded whatever benefits the entire concept is supposed to offer. Safety? Performance, in a future compiler version? I don't know where it's at right now. But you'd think I could do something like load some data from disk, craft a few objects, mark them as immutable, and shove them in an array or associative array without it being a nightmare, but it isn't. Or, having an otherwise mutable class with a member that references an immutable class, but can change which immutable instance it's referencing, without having to cast away the immutability of the thing I'm trying to protect in the first place. So I just stopped doing it, and simply rely on the "just don't make mistakes" practice to avoid writing to things that shouldn't be written to now. more like what I was hoping to get. It doesn't complain at me when I return something that's readonly and the receiving destination isn't expecting it to be readonly, and also I have more free reign over what I can do to it during the constructor phase before it becomes hands-off. Things look a lot cleaner without another set of parentheses around every variable too. On another topic, the lack of a good "delete" keyword doing what one would expect, when there's a perfectly good "new" without its matching existential companion. This, and the ways around it, have already been discussed to death though, but banging my head over trying to force deterministic memory management into the GC-controlled D universe did take its toll on a good year or two of productivity.
May 15 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Mon, May 16, 2022 at 04:00:12AM +0000, cc via Digitalmars-d-learn wrote:
 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.
 
 To make it more meaningful, what is your experience with other
 languages?
[...]
 Immutability.  Ended up having to do so many hundreds of casts to and
 from immutable(whatever) the amount of mental strain greatly exceeded
 whatever benefits the entire concept is supposed to offer.
If you find yourself having to cast to/from immutable, you're using it wrong. Most of my code doesn't have a single mention of immutable in it, and I don't care. It's there for when it's relevant, if it's not useful, don't use it.
 Safety?  Performance, in a future compiler version?  I don't know
 where it's at right now.
What about performance? For anything performance-related, I don't even look at dmd, I use LDC all the way. DMD is only useful for fast compile-run-debug cycle, I don't even look at performance numbers for DMD-produced executables, it doesn't mean anything to me.
 But you'd think I could do something like load some data from disk,
 craft a few objects, mark them as immutable, and shove them in an
 array or associative array without it being a nightmare, but it isn't.
An explicit example would be nice. I write D programs that process input files all the time, including stuffing data into AAs and what-not, and it Just Works(tm). But not once did I bother with immutable (why should I?). The most I'd do is to mark something const (you might want to read up on the difference between immutable and const -- maybe that's why you had so much trouble), but even that I don't bother with most of the time. Const in D has limited utility beyond leaf-node data structures and modules, just let it be mutable and call it a day.
 Or, having an otherwise mutable class with a member that references an
 immutable class, but can change which immutable instance it's
 referencing, without having to cast away the immutability of the thing
 I'm trying to protect in the first place.  So I just stopped doing it,
 and simply rely on the "just don't make mistakes" practice to avoid
 writing to things that shouldn't be written to now.
Just make things private and use getters/setters to control access. Like I said, if you find yourself writing lots of casts when using immutable/const, you're probably doing it wrong. [...]
 On another topic, the lack of a good "delete" keyword doing what one
 would expect, when there's a perfectly good "new" without its matching
 existential companion.  This, and the ways around it, have already
 been discussed to death though, but banging my head over trying to
 force deterministic memory management into the GC-controlled D
 universe did take its toll on a good year or two of productivity.
Why would you want to force deterministic memory management onto GC-allocated objects? Just use malloc/free (or whatever else you fancy). Slap nogc on main() and go from there, if that helps. IME, most programs don't actually need to care whether their memory is manually-managed or GC'd. Many of my programs use GC freely, except in inner loops where tigher control is needed, then I either preallocate or use malloc/free. But only where it actually makes a difference to performance. Outside of performance bottlenecks I don't bother with memory management, just let the GC do its job. T -- Latin's a dead language, as dead as can be; it killed off all the Romans, and now it's killing me! -- Schoolboy
May 16 2022
parent reply cc <cc nevernet.com> writes:
On Monday, 16 May 2022 at 15:08:15 UTC, H. S. Teoh wrote:
 If you find yourself having to cast to/from immutable, you're 
 using it wrong.
I clearly was, which is why I'm not using it anymore. The question was "What are you stuck at? What was the most difficult features to understand? etc.", so I listed the things that tripped me up in my early time with D. I assumed the context of this was collecting useful information for, say, understanding what newcomers' sticking points are and maybe thinking how to make D more accessible to them. Maybe this wasn't the intent, but this kind of comes across more as a lecture on how everything I was doing wrong is my own fault even when I've already stated I'm *not doing those things anymore*.
 I write D programs that process input files all the time, 
 including stuffing data into AAs and what-not, and it Just 
 Works(tm).
Of course it just works, why wouldn't it?
 But not once did I bother with immutable (why should I?).
Because the documentation crams it down your throat. Or at least it did, along with the early blog/wiki posts that were the only source of D information I could find back at the time. And yes, I pored over that page on the differences between const and immutable years ago, which sang immutable's praises at length, how it was D's greatest innovation to set it apart from C++, and implied it should be slapped on literally everything that never changes and how great this was for multithreading, hence why I (formerly) felt the need to try and define all my persistent definitions as immutable. Now I slap __gshared on everything and just let it go.
 For anything performance-related, I don't even look at dmd, I 
 use LDC all the way. DMD is only useful for fast 
 compile-run-debug cycle, I don't even look at performance 
 numbers for DMD-produced executables, it doesn't mean anything 
 to me.
According to the dlang.org wiki entry for LDC:
 druntime/Phobos support is most likely lacking (and probably 
 requires a new version predefined by the compiler).
So I'm not touching it for now. Don't have time to investigate a completely new compiler and track down incompatibilities when DMD works and I've been invested in it. The fact that LDC is more performant than DMD surely not does imply attempting to optimize DMD-compiled programs is futile. My use of immutable was based in part on a (mistaken) assumption that this was a recommended best practice for multithreading safety and performance.
 Just make things private and use getters/setters to control 
 access. Like I said, if you find yourself writing lots of casts
Equally irritating. Direct access is far less annoying to write. Yes, I could use mixins to automate some of this but it still uglifies the code even more to no great advantage for my purposes. Getters/setters have always felt relevant only to large team environments, when you can't count on another developer knowing certain things aren't meant to be touched. For said. Statement of opinion. I wish D had something similarly painless to use, but it doesn't, so I'm out of luck. I just direct access and try to not make mistakes instead.
 Why would you want to force deterministic memory management onto
 GC-allocated objects?  Just use malloc/free (or whatever else
Because when I first got into D this was *not made clear*. The GC was sold so heavily and every single non-GC approach to memory management was made to look like, at best, a crude circumvention, and at worst a pariah. In C++ I could new/delete, in ObjC I had alloc/autorelease, D had new, and also delete at the time, which was not adequately explained that it pretty much did nothing, and even then it (and its hacky replacement __delete) were bugged anyway. Perhaps this was my own ignorance, fair enough. NOW I already use malloc/free for everything important. But is this helpful to future newcomers? Wait till they screw up, don't understand why, then tell them after the fact they were doing it wrong, if they're still around by that point? To this day, as your post demonstrates, the GC is still extolled as the correct solution to 99% of problems, with alternatives only grudgingly admitted to after a person reports running into problems. On top of this, at the time I got into D, the GC just plain DIDN'T work for arbitrary chunks of data unless you carefully zeroed them out. I could easily write trivial programs to read a binary file's raw data into an array of ubyte[], let it go out of scope without any escaped pointers, and crash with out of memory as the loop cheerfully ate up 8+ GB. The move to 64-bit and whatever bugfixes may have happened in the past years helped and fortunately everything "Just Works" NOW. But back then, it didn't. So when on top of this my programs started having disastrous performance issues due to GC collections because the delete I was mistakenly counting on actually did nothing, I scrambled for a solution and was shown GC.free, because the concept of looking up and importing std.core.etc.c.whoever and just using malloc/free was still treated with distaste, like there was just absolutely no time to spend on anyone who didn't fully embrace D's GC ethos. "Oh, you don't like GCs? You just don't get them, go use C instead" wasn't helpful. When a new programmer walks up and says "How do I create an object?", what do you tell them? Do you say "Oh, that's easy, you just type:" ```d import core.memory; import core.stdc.stdlib : malloc, free; import core.lifetime : emplace; T NEW(T, Args...)(auto ref Args args) if (is(T == class)) { enum size = __traits(classInstanceSize, T); void* mem = malloc(size); scope(failure) free(mem); return mem !is null ? emplace!T(mem[0..size], args) : null; } void FREE(T)(ref T obj) if (is(T == class)) { auto mem = cast(void*) obj; destroy(obj); obj = null; free(mem); } auto foo = NEW!Foo; ``` "Simple as that!" No, of course not. You say `auto foo = new Foo;` and that's the end of the discussion. And then they write a little program that runs for 5ms and everything is fine. And then they write a bigger program that runs for 6 hours and come back and say "Hey, this is running really poorly, how do I manually delete objects?" and the answer is "Oh, *you've been doing it wrong.* Why are you trying to do it that way?"
 Slap  nogc on main() and go from there, if that helps.
No, it doesn't. If I'm going to slap nogc on main there's no reason to use D anymore because ~60% of the features I like about D are dependant on the GC, even if they don't end up partaking in it. Among many other things, countless lines of writef that aren't nogc. Neither is calling formattedWrite into a std.container.array, or sformat with a preallocated buffer. I don't know if there's yet another solution but at this point I stop caring. I'm not going to spend days rewriting my own implementation of format. Slapping nogc on main doesn't solve problems, it creates them. Some of the features I like may require the GC to exist, but if they don't actually NEED to use it, I'm not going to be shy about using them in a way such that they don't, even if they can't be made nogc. If writef throws an exception, I probably have bigger problems to worry about than that allocation.
 IME, most programs don't actually need to care whether their 
 memory is manually-managed or GC'd.
Mine do.
 then I either preallocate or use malloc/free.
Which I do now. Years after making the mistake that blindly trusting D's holy GC was meant to solve every problem. So, having had this leave a pretty bad taste in my mouth, I now avoid the GC whenever possible, even when I don't have to. Maybe a run-and-done program can get along just fine allocating everything to the GC. But maybe I'll need to modularize it some day in the future and call it from another program with far more intensive requirements that doesn't want superfluous data being added to the GC every frame. Far better to just keep your house clean every day than let the trash pile up and wait for the maid to come, IMO. Inevitably it's going to be her day off when you have guests coming over.
May 16 2022
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote:

 Far better to just keep your house clean every day than let the 
 trash pile up and wait for the maid to come, IMO.
Right,GC is a bad idea!
May 17 2022
next sibling parent reply zjh <fqbqrr 163.com> writes:
On Tuesday, 17 May 2022 at 11:50:30 UTC, zjh wrote:

 Right,GC is a bad idea!
Endless use of memory without freeing. It's totally unreasonable waste.
May 17 2022
parent reply bauss <jj_1337 live.dk> writes:
On Tuesday, 17 May 2022 at 11:53:40 UTC, zjh wrote:
 On Tuesday, 17 May 2022 at 11:50:30 UTC, zjh wrote:

 Right,GC is a bad idea!
Endless use of memory without freeing. It's totally unreasonable waste.
It's not really endless use of memory and it does free. Depending on the strategy then it does so at different times, such as when allocating, but not enough memory has been allocated already. The problem with GC is that the lifetime sometimes exceed what's expected. Personally I don't have a problem with the GC.
May 17 2022
parent eugene <dee0xeed gmail.com> writes:
On Tuesday, 17 May 2022 at 11:59:10 UTC, bauss wrote:
 The problem with GC is that the lifetime sometimes exceed 
 what's expected.
I am not sure if I get the sentence right, but I've had program crash because GC in some circumstances collects objects which where supposed to have 'infinite' lifetime, but were collected soon after program start. (There was a thread in this forum started by me where this was discussed). And due to this I (just in case) had to write things like this: ```d foreach (k; 0 .. nConnections) { auto sm = new WrkMachine(md, rxPool, txPool, host, port); wrkMachines ~= sm; // <<<<<<< sm.run(); } ``` wrkMachines array is not needed by the program itself, it's purpose is just to keep pointers in heap as the warranty that GC will not collect corresponding objects.
May 21 2022
prev sibling parent eugene <dee0xeed gmail.com> writes:
On Tuesday, 17 May 2022 at 11:50:30 UTC, zjh wrote:
 On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote:

 Far better to just keep your house clean every day than let 
 the trash pile up and wait for the maid to come, IMO.
Right,GC is a bad idea!
As I've already mentioned I think the origin of GC is functional langs, and the reason to have GC as essential part of a language is *immutability*, immutability as a main principle. Say, we have an array of 10 floats and we want to change 3rd element. In truly functional language we can not do that - we must produce new array in which 3rd element is changed. Old array is now garbage, i.e. we *naturally* have A LOT of garbage in functional langs. But D as 'C/C++ with GC' still puzzles me. Of course I know about BetterC, just have not had much time to try this option.
May 21 2022
prev sibling next sibling parent Dom Disc <dominikus scherkl.de> writes:
On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote:
 having had this leave a pretty bad taste in my mouth, I now 
 avoid the GC whenever possible, even when I don't have to.
Bad idea. You should only avoid GC if your profiling shows that it is bad in a specific piece of code (e.g. some inner loop that's called millions of times - the real bottlenecks). This frees you from the mental load of thinking about memory allocation at all unless it becomes necessary, which it will actually be only in very, very few places. Better invest your precious time to really DO profiling and find out where the bottlenecks are!
 Maybe a run-and-done program can get along just fine allocating 
 everything to the GC.  But maybe I'll need to modularize it 
 some day in the future and call it from another program with 
 far more intensive requirements that doesn't want superfluous 
 data being added to the GC every frame.
Yes - and when you modularize your program, keep in mind that a module should avoid allocating anything large or often on its own at all. It should better work on memory given to it. So you remain able to decide on the calling side if you allocate by GC (default) or (if something turns out to be a bottleneck) manually allocate memory.
 Far better to just keep your house clean every day than let the 
 trash pile up and wait for the maid to come, IMO.  Inevitably 
 it's going to be her day off when you have guests coming over.
There's always gc.collect, which calls the maid to do her job, even if she is on vacation. Do so whenever you think you may have piled on a lot of trash and are out of house (have the time available that a collection may take). This way you can be sure there is never too much trash, so the GC is very unlikely to ever disturb you when there is no time for long collection cycles.
May 17 2022
prev sibling parent reply Johan <j j.nl> writes:
On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote:
 On Monday, 16 May 2022 at 15:08:15 UTC, H. S. Teoh wrote:
 For anything performance-related, I don't even look at dmd, I 
 use LDC all the way. DMD is only useful for fast 
 compile-run-debug cycle, I don't even look at performance 
 numbers for DMD-produced executables, it doesn't mean anything 
 to me.
According to the dlang.org wiki entry for LDC:
 druntime/Phobos support is most likely lacking (and probably 
 requires a new version predefined by the compiler).
So I'm not touching it for now.
Lol, what? Don't misquote the wiki about LDC. If you can run DMD on your architecture, LDC has full support too. The "lacking druntime/phobos support" is about architectures that are _not_ x86, x86_64, ARM, AArch64, PowerPC, MIPS, WebAssembly. DMD supports only a subset of what LDC (and GDC) support. -Johan
May 21 2022
parent max haughton <maxhaton gmail.com> writes:
On Saturday, 21 May 2022 at 19:00:04 UTC, Johan wrote:
 On Tuesday, 17 May 2022 at 06:28:10 UTC, cc wrote:
 On Monday, 16 May 2022 at 15:08:15 UTC, H. S. Teoh wrote:
 [...]
According to the dlang.org wiki entry for LDC:
 [...]
So I'm not touching it for now.
Lol, what? Don't misquote the wiki about LDC. If you can run DMD on your architecture, LDC has full support too. The "lacking druntime/phobos support" is about architectures that are _not_ x86, x86_64, ARM, AArch64, PowerPC, MIPS, WebAssembly. DMD supports only a subset of what LDC (and GDC) support. -Johan
Forget target support, ldc *runs* on more architectures than dmd because it doesn't insist on using x87 all the time.
May 21 2022
prev sibling next sibling parent max haughton <maxhaton gmail.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Learning D is almost a complete blur in my memory but I distinctly remember not really understanding is expressions well into even fiddling around with them inside the compiler.
May 15 2022
prev sibling parent reply Chris Piker <chris hoopjump.com> writes:
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.

 To make it more meaningful, what is your experience with other 
 languages?

 Ali
Hi Ali, thanks for asking. Coming from C background I had problems with voldemort types. I kept wanting to know the storage type for items so that I could use it in interfaces, but that's not as big a deal anymore. Currently my problem is integration into common tool chains in a Linux environment. On Linux the common development tools are built around gcc & gdb. The common package managers are apt and dnf. Right now I can't compile vibe.d using gdc, and I can't `apt install vibe-d` So I'd say lack of Linux integration is my most difficult problem using D. I'd certainly contribute to a fund that focused on D Linux usability, namely: 1. Supporting gdc development and distribution. 2. Testing common packages against gdc 3. Updating dub so that it could assist with creating deb and yum packages 4. Having a standard GUI library (maybe). These days the language itself is not so much of a concern. The development days for D2 are long over. What exists is excellent. I think the central focus should on libraries and integration with larger ecosystems.
May 22 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 23/05/2022 6:06 AM, Chris Piker wrote:
    1. Supporting gdc development and distribution.
Iain's workload should be decreasing now that it is using the up to date frontend. Rather than the older C++ version with backports that he has been maintaining. My understanding is that he is fine as-is, and there isn't anything pressing on that front he needs help with.
    2. Testing common packages against gdc
Why? The few things specific to GDC is stuff like inline assembly or targets that are either unsupported or not well supported.
    3. Updating dub so that it could assist with creating deb and yum 
 packages
Packaging is something dub doesn't do right now, it is something that would be very nice to have.
    4. Having a standard GUI library (maybe).
If you have the many tens of millions to build it, sure. There is a big difference between acceptable as third-party and good enough for standard library.
May 22 2022
parent reply Chris Piker <chris hoopjump.com> writes:
On Sunday, 22 May 2022 at 19:01:41 UTC, rikki cattermole wrote:
 On 23/05/2022 6:06 AM, Chris Piker wrote:
 Iain's workload should be decreasing now that it is using the 
 up to date frontend. Rather than the older C++ version with 
 backports that he has been maintaining.
Hats off to Iain for sure. Wish I had the resources to pay for his work, would certainly do so.
    2. Testing common packages against gdc
Why?
Mostly because I've put in about 15 hours effort so far trying to get a vibe.d based project to build using gdc, with no success. I'm about to give up and declare either gdc or vibe.d unsuitable for use in a large upcoming project. That's too bad really because D only has any credibility at all in my work group due to the existence of gdc, and vibe.d is a nice platform to build on.
    3. Updating dub so that it could assist with creating deb 
 and yum packages
Packaging is something dub doesn't do right now, it is something that would be very nice to have.
For this item, if there was just a "dub install --prefix=" type command it would be good enough. Let the packaging tools take over from there and scoop-up the output.
    4. Having a standard GUI library (maybe).
If you have the many tens of millions to build it, sure.
Ah, if only. Let me check the couch cushions, should be a trust fund hiding in there somewhere ;)
May 22 2022
parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 23/05/2022 7:24 AM, Chris Piker wrote:
    2. Testing common packages against gdc
Why?
Mostly because I've put in about 15 hours effort so far trying to get a vibe.d based project to build using gdc, with no success. I'm about to give up and declare either gdc or vibe.d unsuitable for use in a large upcoming project.  That's too bad really because D only has any credibility at all in my work group due to the existence of gdc, and vibe.d is a nice platform to build on.
If going by your other post, there was nothing wrong with GDC. DMD and LDC would have produced the same set of issues, because its the same frontend. Vibe.d is well tested against the frontend. Its part of dmd's test suite. See: https://buildkite.com/dlang/dmd/builds/26775
May 22 2022
parent reply Chris Piker <chris hoopjump.com> writes:
On Sunday, 22 May 2022 at 19:33:21 UTC, rikki cattermole wrote:

I should probably jump back to another thread, but maybe one more 
reply isn't too much off topic discussion...

 DMD and LDC would have produced the same set of issues, because 
 its the same frontend.
Oh, the compile stage works okay (after building a custom gcc), its linking that's the problem now. ``` env LD_RUN_PATH=/usr/local/gcc12/lib64 DFLAGS="-Wno-deprecated" errors. ``` An example link error is: ``` /usr/bin/ld: libvibe_core.a: in function `_D3std6format8internal5write__T8getWidthTAwZQnFNaNbNiNfQoZl': args.d:(.text+0x657e): undefined reference to `_D3std9algorithm9searching__T3allSQBg6format8internal5write__T8getWidthTAwZQnFQgZ9__lambda2Z__TQCoTQBbZQCwMFNaNbNiNfQBsZb' ``` I've made sure libgphobos.so is in the LD_RUN_PATH above. Since there's no substitute for end-to-end testing, a CI that weekly grabbed packages off of code.dlang.org and tried them with gdc would be handy. Now that gdc-12 is out, it might be something to consider. I know that it's the package provider's job, but a automated friendly nudge wouldn't hurt.
 Vibe.d is well tested against the frontend.

 Its part of dmd's test suite.

 See: https://buildkite.com/dlang/dmd/builds/26775
Thanks, that's handy. Do you know where the equivalent test suite is for gdc?
May 22 2022
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 23/05/2022 8:05 AM, Chris Piker wrote:
 Vibe.d is well tested against the frontend.

 Its part of dmd's test suite.

 See: https://buildkite.com/dlang/dmd/builds/26775
Thanks, that's handy.  Do you know where the equivalent test suite is for gdc?
No idea. I've pinged Iain, because you are certainly at that point that is well past my knowledge of GDC. Not something I use, as it isn't exactly easy to use on Windows, plus LDC has some pretty awesome features.
May 22 2022
parent reply Chris Piker <chris hoopjump.com> writes:
On Sunday, 22 May 2022 at 20:11:12 UTC, rikki cattermole wrote:
 On 23/05/2022 8:05 AM, Chris Piker wrote:
 Vibe.d is well tested against the frontend.

 Its part of dmd's test suite.

 See: https://buildkite.com/dlang/dmd/builds/26775
Thanks, that's handy.  Do you know where the equivalent test suite is for gdc?
No idea. I've pinged Iain, because you are certainly at that point that is well past my knowledge of GDC. Not something I use, as it isn't exactly easy to use on Windows, plus LDC has some pretty awesome features.
Hey thanks! I bet LDC is pretty cool, have to look into it sometime. For now at my site just introducing D is a bit radical, don't want to capsize the boat by leaving the gcc toolchain altogether. I'm willing to help out with GDC work were I can, at least by being a bleeding-edge tester if nothing else.
May 22 2022
parent rikki cattermole <rikki cattermole.co.nz> writes:
On 23/05/2022 8:22 AM, Chris Piker wrote:
 Hey thanks!  I bet LDC is pretty cool, have to look into it sometime.  
 For now at my site just introducing D is a bit radical, don't want to 
 capsize the boat by leaving the gcc toolchain altogether.  I'm willing 
 to help out with GDC work were I can, at least by being a bleeding-edge 
 tester if nothing else.
Iain is usually pretty talkative, but right now he isn't. Right now my list of things I want to talk to him at next BeerConf (the next will start at the end of this week roughly) that we are both at is LTS releases, and I'll see where he is at with testing. I know he has got a lot of test hardware for all the different targets. He is in Germany, so if you are able to get on during his timezone you might catch him.
May 22 2022
prev sibling parent max haughton <maxhaton gmail.com> writes:
On Sunday, 22 May 2022 at 20:05:33 UTC, Chris Piker wrote:
 On Sunday, 22 May 2022 at 19:33:21 UTC, rikki cattermole wrote:

 I should probably jump back to another thread, but maybe one 
 more reply isn't too much off topic discussion...

 [...]
https://github.com/gcc-mirror/gcc/tree/master/gcc/testsuite Look for folders starting with gdc. There is no analogue for buildkite as per se.
May 22 2022