Re: Using ImportC to augment a big C project with D
On Tuesday, 20 February 2024 at 18:33:42 UTC, Carl Sturtivant wrote: 2. The C source calls exit() from C's stdlib, and D needs to terminate properly. What do you mean by "need"? You can call https://dlang.org/phobos/core_stdc_stdlib.html#.exit from D: ```d import std.stdio; void main() { scope(exit) writeln("Bye"); import core.stdc.stdlib : exit; exit(0); } shared static ~this() { writeln(__FUNCTION__); } ``` Output: ``` onlineapp._sharedStaticDtor_L11_C1 ``` So it does run module destructors, but not `scope(exit)` statements (which probably makes sense). I would expect `exit()` called from the C source to have similar results. --Bastiaan
Re: `static` function ... cannot access variable in frame of ...
On Monday, 15 January 2024 at 23:06:00 UTC, Steven Schveighoffer wrote: As a workaround, you can alias the outer function in the struct: ```d struct S { alias foo = S_foo; } ``` This might be less than ideal, but at least it works. It does! And it's good enough for me. Thanks a lot! -- Bastiaan.
Re: `static` function ... cannot access variable in frame of ...
On Monday, 15 January 2024 at 18:43:43 UTC, user1234 wrote: The two calls are not equivalent. so what is passed as alias need to be static too. Thanks all. I thought a static member function just isn't able to access the instance of the struct, but as I understand now it is static all the way. What I am looking for is a way to have different structs that have a member function that has the same name in all of them, that is callable without a this pointer, and able to take an alias argument. That is probably asking too much. -- Bastiaan.
`static` function ... cannot access variable in frame of ...
Hey people, I can use some help understanding why the last line produces a compile error. ```d import std.stdio; struct S { static void foo(alias len)() { writeln(len); } } void S_foo(alias len)() { writeln(len); } void main() { const five = 5; S_foo!five; // Fine S.foo!five; // Error } ``` The error is ``` onlineapp.d(7): Error: `static` function `onlineapp.main.foo!(5).foo` cannot access variable `five` in frame of function `D main` onlineapp.d(19):`five` declared here onlineapp.d(21): Error: template instance `onlineapp.main.foo!(5)` error instantiating ``` It seems to me this should just work. Thanks! --Bastiaan.
Re: Returning a reference to be manipulated
On Friday, 14 April 2023 at 00:50:31 UTC, kdevel wrote: ``` ref int foo (ref int i) { return i; } ref int bar () { int i; return foo (i); } void main () { import std.stdio; auto i = bar; i.writeln; } ``` Up to dmd v2.100.2 I am warned/get an error during compilation: ``` $ dmd returnref2.d returnref2.d(3): Deprecation: returning `i` escapes a reference to parameter `i` returnref2.d(1):perhaps annotate the parameter with `return` $ dmd -dip1000 returnref2.d returnref2.d(3): Error: returning `i` escapes a reference to parameter `i` returnref2.d(1):perhaps annotate the parameter with `return` ``` With later dmd versions (up to including v2.102.2) the code compiles without complaints. Is this intended? I think this is intended. Adding `@safe:` on top makes the complaint come back (in dmd 2.102 it is deprecated, in 2.103 it is an error). -- Bastiaan.
Re: Traverse a DList and insert / remove in place?
On Sunday, 19 March 2023 at 13:15:58 UTC, Armando wrote: I would like to do something like traversing a DList, operating on the current element, and potentially removing that element or inserting a new one before/after it - an easy operation if you code a DList yourself. Maybe I missed something? This is one way to do that: ```d import std; struct MyType { int id; // [...] other stuff } void main() { auto list = DList!MyType(); // Fill the list. foreach (i; 0 .. 10) list.insertBack(MyType(i)); // Traverse the list, conditionally remove one element. for (auto range = list[]; !range.empty;) if (range.front.id == 3) list.popFirstOf(range); else range.popFront(); // Traverse the list, conditionally insert one element. for (auto range = list[]; !range.empty;) { if (range.front.id == 6) list.insertBefore(range, MyType(66)); range.popFront(); } // Print modified list. foreach (e; list) writeln(e); } ``` Output: ``` MyType(0) MyType(1) MyType(2) MyType(4) MyType(5) MyType(66) MyType(6) MyType(7) MyType(8) MyType(9) ``` https://run.dlang.io/is/kk80FD -- Bastiaan.
Re: toString best practices
On Thursday, 9 February 2023 at 17:49:58 UTC, Paolo Invernizzi wrote: ``` import std.format, std.range.primitives; struct Point(T) { T x, y; void toString(W)(ref W writer, scope const ref FormatSpec!char f) const if (isOutputRange!(W, char)) { put(writer, "("); formatValue(writer, x, f); put(writer, ", "); formatValue(writer, y, f); put(writer, ")"); } } void main(){ import std.format : format; assert( format("%s", Point!int(1,2)) == "(1, 2)"); import std.experimental.logger; sharedLog.infof("%s", Point!int(1,2)); } ``` Pasting this into https://run.dlang.io/, it just works. That's for DMD 2.099, so it might be a regression -- or recent feature? -- Bastiaan.
Re: How do you work with lst files?
On Wednesday, 24 August 2022 at 22:29:51 UTC, Christian Köstlin wrote: I want to ask around how you from the dlang community work with .lst coverage files? No personal experience, but there are half a dozen options on https://code.dlang.org/search?q=Coverage — Bastiaan.
Re: How to escape control characters?
On Thursday, 31 March 2016 at 03:15:49 UTC, cy wrote: This might be a dumb question. How do I format a string so that all the newlines print as \n and all the tabs as \t and such? The easiest is this: ```d import std.conv; string str = `Hello "World" line 2`; writeln([str].text[2..$-2]); // Hello \"World\"\nline 2 ``` I know this is an old post, but I felt this trick needed to be shared. This takes advantage of the fact that `std.format` escapes the characters in an array of strings. So we create an array where `str` is the only element, and convert that to text. Without the `[2..$-2]` slicing the output would be `["Hello \"World\"\nline 2"]`. A slightly more efficient implementation is ```d string escape(string s) { import std.array : appender; import std.format : FormatSpec, formatValue; FormatSpec!char f; auto w = appender!string; w.reserve(s.length); formatValue(w, [s], f); return w[][2 .. $ - 2]; } ``` And the inverse: ```d string unescape(string s) { import std.format : FormatSpec, unformatValue; FormatSpec!char f; string str = `["` ~ s ~ `"]`; return unformatValue!(string[])(str, f)[0]; } ``` Perhaps `escape()` and `unescape()` should be part of `std.format` so that they can be refactored to use `std.format.internal.write.formatElement` directly, eliminating the conversion to array. -- Bastiaan.
Re: Null terminated character
On Thursday, 23 June 2022 at 16:16:26 UTC, vc wrote: I've try this '\0'*10 and didn't work, i want the results be \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ```d string nulls = '\0'.repeat(10).array; ``` — Bastiaan.
Re: Why allow initializers of non-static members that allocate?
On Saturday, 11 June 2022 at 10:52:58 UTC, Mike Parker wrote: I agree with your initial assessment that it should be an error. It really only makes sense to allow the dynamic allocation if the fields are immutable and, in the case of arrays, the initializer is a literal.
Re: Why allow initializers of non-static members that allocate?
On Saturday, 11 June 2022 at 01:52:58 UTC, Mike Parker wrote: People getting bit by `new` in field initialization often enough that I think a warning would be helpful. The problem is so much bigger because it is not just a case of being aware not to use `new` in member initialisers. As you see in my second example in https://forum.dlang.org/post/ogvubzgprghefclgl...@forum.dlang.org there is no `new` anywhere. In fact you could say an effort has been made to do the right thing in `struct A` where the allocation has been moved to the constructor (a strategy that is not always available because structs don’t have default constructors) yet we fell into the same trap. My point is that this problem can be buried deep down under multiple layers and you can’t really ever be sure that there isn’t a problem in your massive code base. But any such warnings need to be enabled by default to be useful, and must have an off switch for people who don't need them. So the question in each case would be, where's the line between helpful and annoying? So that’s why I used “why” in the title of this thread, which I haven’t seen an answer to yet. What is the practical case where that warning would be annoying? When would you actually want this behaviour? — Bastiaan.
Re: Why allow initializers of non-static members that allocate?
On Friday, 10 June 2022 at 14:56:24 UTC, Steven Schveighoffer wrote: On 6/10/22 3:46 AM, Mike Parker wrote: I think this is a case where having a warning that's on by default, and which can be explicitly disabled, is useful. "Blah blah .init blah blah. See link-to-something-in-docs. Is this what you intended?" Here the language is being extremely unsafe. Not only is the field shared between instances, it's shared across instances in *different threads*. Discovered circa 2009: https://issues.dlang.org/show_bug.cgi?id=2947 Thanks for the pointer. #dbugfix 2947 It should be illegal to declare a field this way that has mutable references without being `shared`. End of story.
Re: Why allow initializers of non-static members that allocate?
On Friday, 10 June 2022 at 07:49:43 UTC, Mike Parker wrote: And it *is* documented: Struct fields are by default initialized to whatever the Initializer for the field is, and if none is supplied, to the default initializer for the field's type. The default initializers are evaluated at compile time. https://dlang.org/spec/struct.html#default_struct_init Yes, that section I find open for interpretation, because I don't think pointer values can be determined at compiler time. I assume S.init is constructed at program initialization, which is then blitted into any new instance of S. -- Bastiaan.
Re: Why allow initializers of non-static members that allocate?
On Friday, 10 June 2022 at 07:46:36 UTC, Mike Parker wrote: On Friday, 10 June 2022 at 07:35:17 UTC, Bastiaan Veelo wrote: Is there a use case where this makes sense? I would have much appreciated the compiler slapping me on the fingers, but it doesn't. I understand that it is safe and that the compiler can allow this, but why would anyone want that? D-scanner does not check for this either. Any initialization of a member field is overriding the field's `.init` value for the type. If a dynamic allocation set a different value per instance, then you'd have inconsistent behavior with, e.g., `int a = 5`. Yes, I understand that the compiler can't do what I was expecting it to do, it was a mistake. I think a helpful error message would be: "Error: The initializer `A(5)` allocates memory that is shared among all instances of `S`. If you want that, make `S.a` `static`." I understand that it's not something that people expect, but making it an error can't be the answer. And making it a static field is not the same thing. It's not the same thing, therefore I was hoping to see a use case for it -- but just because I'm curious; Preventing the mistake is my main thing. I think this is a case where having a warning that's on by default, and which can be explicitly disabled, is useful. "Blah blah .init blah blah. See link-to-something-in-docs. Is this what you intended?" That would be fine too. By the way, if there is something-in-docs, I don't think it is prominent enough... -- Bastiaan.
Why allow initializers of non-static members that allocate?
I have been foolish enough to make a mistake like this: ```d struct S { int[] arr = new int[](5); } ``` This is terrible because ```d S s1; S s2; s2.arr[0] = 42; writeln(s1.arr[0]); // 42 Gotcha! ``` Of course there are less obvious variants of the same mistake: ```d import std; struct S { A a = A(5); } struct A { int[] arr; this (int l) { arr.length = l; } } void main() { S s1; S s2; s2.a.arr[0] = 42; writeln(s1.a.arr[0]); // 42 :-( } ``` Is there a use case where this makes sense? I would have much appreciated the compiler slapping me on the fingers, but it doesn't. I understand that it is safe and that the compiler can allow this, but why would anyone want that? D-scanner does not check for this either. I think a helpful error message would be: "Error: The initializer `A(5)` allocates memory that is shared among all instances of `S`. If you want that, make `S.a` `static`." -- Bastiaan.
Re: Library for image editing and text insertion
On Wednesday, 27 April 2022 at 09:27:24 UTC, Alexander Zhirov wrote: Now I would like to reduce the size of the executable file and it would be great at all! Try the `-release` option to `dmd`. Or use LDC. -- Bastiaan.
Re: Language server
On Tuesday, 26 April 2022 at 18:15:57 UTC, Alain De Vos wrote: In a perfect world there would be someone uploading a youtube video how to implement neovim with a dlang language-server. With function-completions-help where hints are given about the functions and libraries. If anyone could do this , this would be nice to have. I'm not a vim user, but there is this: https://wiki.dlang.org/D_in_Vim If that is what you needed to get what you want, maybe make a YouTube video about it ;-) -- Bastiaan.
Re: How to use Vector Extensions in an opBinary
On Thursday, 21 April 2022 at 15:31:04 UTC, HuskyNator wrote: On Sunday, 17 April 2022 at 17:04:57 UTC, Bastiaan Veelo wrote: You might want to have a look at https://code.dlang.org/packages/intel-intrinsics — Bastiaan. This does not discuss core.simd or __vector type, or did I miss/mininterpret something? It wraps `core.simd` with an eye on portability. I haven’t used it myself, but my impression is that if you’re interested in `core.simd`, intel-intrinsics may be a better option. I think there is also better documentation. There is a video of a DConf presentation that you may want to watch. — Bastiaan.
Re: Can Enums be integral types?
On Tuesday, 19 April 2022 at 01:25:13 UTC, Era Scarecrow wrote: The 'integral' or numeric value is used for uniqueness, […] There is nothing that requires enum values to be unique, though: ```d import std; void main() { enum E {Zero = 0, One = 0, Two = 0} writeln(E.Two); // Zero! } ``` — Bastiaan.
Re: Can Enums be integral types?
On Saturday, 16 April 2022 at 11:39:01 UTC, Manfred Nowak wrote: In the specs(17) about enums the word "integral" has no match. But because the default basetype is `int`, which is an integral type, enums might be integral types whenever their basetype is an integral type. On the other hand the specs(7.6.5.3) about types say | A bool value can be implicitly converted to any integral type, | with false becoming 0 and true becoming 1. This seems senseless, when the enum has no names defined for one of these values. Not sure where the question is, but [6.5.3](https://dlang.org/spec/type.html#bool) makes that this works: ```d int i = true; // 1 ``` However this does not: ```d enum E : int {Zero, One, Two} E e1 = true; // Error: cannot implicitly convert expression `true` of type `bool` to `E` E e2 = 1; // Error: cannot implicitly convert expression `1` of type `int` to `E` ``` The reason is in [17.1.5](https://dlang.org/spec/enum.html): “EnumBaseType types cannot be implicitly cast to an enum type.” — Bastiaan.
Re: How to use Vector Extensions in an opBinary
On Sunday, 17 April 2022 at 11:16:25 UTC, HuskyNator wrote: I recently found out there is [support for vector extensions](https://dlang.org/spec/simd.html) But I have found I don't really understand how to use it, not even mentioning the more complex stuff. I couldn't find any good examples either. You might want to have a look at https://code.dlang.org/packages/intel-intrinsics — Bastiaan.
Re: package libs on windows
On Tuesday, 1 February 2022 at 21:17:09 UTC, Abby wrote: I would like to know if there is a way to set path to lib to downloaded with package instead of harcoded. That’s documented on the [package page](https://code.dlang.org/packages/d2sqlite3). Are you trying to link with a separately downloaded version, or de included version? How have you configured your `dub.json`, and do you supply any options in the `dub` invocation? — Bastiaan.
Re: std.signals: Why emit() not extist?
On Thursday, 30 December 2021 at 19:13:10 UTC, Marcone wrote: I get this error: Error: undefined identifier `emit`, did you mean function `exit`? Did you `import std.signals`? — Bastiaan.
Re: First time using Parallel
On Sunday, 26 December 2021 at 15:20:09 UTC, Bastiaan Veelo wrote: So if you use `workerLocalStorage` to give each thread an `appender!string` to write output to, and afterwards write those to `stdout`, you'll get your output in order without sorting. Scratch that, I misunderstood the example. It doesn't solve ordering. The example works because order does not matter for addition. Sorry for spreading wrong information. -- Bastiaan.
Re: First time using Parallel
On Sunday, 26 December 2021 at 06:10:03 UTC, Era Scarecrow wrote: [...] ```d foreach(value; taskPool.parallel(range) ){code} ``` [...] Now said results are out of order [...] So I suppose, is there anything I need to know? About shared resources or how to wait until all threads are done? Have a look at `taskPool.workerLocalStorage`. I learned about this in [a post by data pulverizer](https://forum.dlang.org/post/ddgxqoitxoaljfwnl...@forum.dlang.org), who gives this example (slightly modified): ```d import std.traits : isFloatingPoint; auto dot(T)(T[] x, T[] y) if (isFloatingPoint!T) in (y.length == x.length) { import std.range : iota; import std.parallelism : parallel, taskPool; auto sums = taskPool.workerLocalStorage(0.0L); foreach (i; parallel(iota(x.length))) sums.get += x[i] * y[i]; T result = 0.0; foreach (threadResult; sums.toRange) result += threadResult; return result; } void main() { double[] x = [1, 2, 3, 4, 5]; double[] y = [6, 7, 8, 9, 10]; assert(dot(x, y) == 130); } ``` (https://run.dlang.io/is/Ia8A0k) So if you use `workerLocalStorage` to give each thread an `appender!string` to write output to, and afterwards write those to `stdout`, you'll get your output in order without sorting. --Bastiaan.
Re: Why does is the RandomAccessInfinite interface not a valid RandomAccessRange?
On Sunday, 19 December 2021 at 09:19:31 UTC, D Lark wrote: Do you know if there's a nightly version I can specify to use your fix? Are you inheriting from `RandomAccessInfinite`? Then you can probably add ```d static if (__VERSION__ < 2099) enum bool empty = false; ``` to make it work. — Bastiaan.
Re: DMD32 D Compiler v2.097.2-dirty ?
On Monday, 6 September 2021 at 15:37:31 UTC, Paul wrote: I like to write CLEAN code:) Why does my DMD installation say v2.097.2-dirty? https://forum.dlang.org/post/qqxmnoshytmzflviw...@forum.dlang.org I suppose it is due to how the scripts work that produce the compiler release. I guess these can be found online somewhere; Martin Nowak has been taking care of the releases for many years. I agree that it would look better to “clean this up”, but knowing that it is just cosmetics most people have more pressing tasks at hand… It looks like it would be easy enough for anyone to fix, though :-) — Bastiaan.
Re: Curious effect with traits, meta, and a foreach loop ... mystifies me.
On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote: ```d /*…*/ // this is fine (notice that 'val' is never used foreach( i, val ; u.tupleof ){ ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } // this fails with: "Error: variable 'i' cannot be read at compile time // // foreach( i ; 0 .. 3 ){ //ptr = u.tupleof[i].x.ptr; //writeln("ptr: ", ptr); // } } ``` As Adam mentioned `tupleof` only exists at compile time, and a `foreach` over a `tupleof` gets unrolled at compile time, akin to a `static foreach`. Consequently you can make your snippet work by prepending `static` (and fixing the range): ```d static foreach (i; 0 .. u.tupleof.length) { ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } ``` https://run.dlang.io/is/T6jrjf Not sure if that helps in what you’re trying to achieve though, as that isn’t clear to me. —Bastiaan.
Re: implimenting interface function by inheriting from other class
On Saturday, 21 August 2021 at 20:35:43 UTC, Alexey wrote: Hello ```D interface Int { void coolFunc(); } class C1 { void coolFunc() { return; } } class C2 : C1, Int { } void main() { auto c = new C2; } ``` dmd says it's not Ok: t.d(14): Error: class `t.C2` interface function `void coolFunc()` is not implemented how to make dmd happy? Not sure if this is the best way, but it does make dmd happy: https://run.dlang.io/is/44F3AE ```d class C2 : C1, Int { override void coolFunc() { C1.coolFunc; } } ``` It looks lame, I admit. — Bastiaan.
Re: simple (I think) eponymous template question ... what is proper idimatic way ?
On Tuesday, 17 August 2021 at 20:29:51 UTC, james.p.leblanc wrote: So, below is my code: import std.stdio; import std.meta : AliasSeq; template isAmong(T, S...) { static if (S.length == 0) enum isAmong = false; else enum isAmong = is(T == S) || isAmong(T, S[1..$]); } alias MyTypes = AliasSeq!(int, float); auto myFunc(T)(T a, T b) if (isAmong!(T, MyTypes)) { writeln(" in myFunc "); return; } void main(){ writeln("started ..."); auto a = 1; auto b = 2; myFunc!(int)(a, b); return; } And, here are the error message: (master) Notes > dmd recursive_template.d recursive_template.d(9): Error: circular reference to variable `recursive_template.isAmong!(int, int, float).isAmong` recursive_template.d(17): Error: template instance `recursive_template.isAmong!(int, int, float)` error instantiating recursive_template.d(29):while looking for match for `myFunc!int` Can anyone see what is going on? Best Regards, James https://run.dlang.io/is/m5svQ2 The error was in line 8. T (Teoh) forgot to take the first of `S` in `is(T == S[0])`. The error message improves after adding the `!` in `isAmong!(T, S[1..$])`, which, surprisingly, is optional! — Bastiaan.
Re: Getting a working example of opIndexAssign using opSlice ... have troubles ...
On Sunday, 15 August 2021 at 20:41:51 UTC, james.p.leblanc wrote: struct A { int opIndexAssign(int v); // overloads a[] = v int opIndexAssign(int v, size_t[2] x); // overloads a[i .. j] = v int[2] opSlice(size_t x, size_t y); // overloads i .. j } void test() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } I have hacked at this trying to get a simple working example. Not sure if this does enough of what you’re looking for, but this covers the minimal steps to get it working: https://run.dlang.io/is/m5svQ2 ```d import std; struct A { int opIndexAssign(int v) // overloads a[] = v { writeln(__FUNCTION__); return 42; } int opIndexAssign(int vh, size_t[2] x) // overloads a[i .. j] = v { writeln(__FUNCTION__); return 43; } int[2] opSlice(size_t x, size_t y) // overloads i .. j { writeln(__FUNCTION__); return [44, 45]; } } void main() { A a; int v; a[] = v; // same as a.opIndexAssign(v); a[3..4] = v; // same as a.opIndexAssign(v, a.opSlice(3,4)); } ``` — Bastiaan.
Re: D has the same memory model as C++
On Wednesday, 11 August 2021 at 05:33:06 UTC, Tejas wrote: On Tuesday, 10 August 2021 at 21:19:39 UTC, Bastiaan Veelo wrote: On Tuesday, 10 August 2021 at 16:00:37 UTC, Tejas wrote: Basically, what are the subtle gotcha's in the differences between C++ and D code that looks similar The only gotcha that comes to my mind is that `private` means private to the module in D, not private to the aggregate. — Bastiaan. A few others that I know: When importing one module(say ```m2```) into another (say ```m1```), the symbols of ```m1``` aren't automatically visible in ```m2```. You must import ```m1``` in ```m2``` for that. How is that different from C++? I think you meant to say that if `m1` imports `m2`, the symbols of `m2` don't automatically become visible by importing `m1`. Indeed you also have to import `m2` for that, *unless* `m1` `public`ly imports `m2`. You can't just initialize variables willy-nilly in a module, you must do them inside ```static this()``` Or declare them with an initial value. I'm not aware of a rule that requires module level variables to be initialized in `static this()`, but if you require them to be initialized at startup with a value not known at compile time, then that is the place to do it. I don't think you can go about this willy-nilly in C++ either... Method function pointers don't exist in D, equivalent functionality is achieved by using a delegate that captures the context of a class instantiated object. To use a function pointer explicitly, you can't just write ```(func)(arguments)```, it is ```()(arguments)```(thank you evilrat) To take the address of a method (in order to assign it to a delegate) requires `&`, yes, but not when calling the delegate. --Bastiaan.
Re: D has the same memory model as C++
On Tuesday, 10 August 2021 at 18:13:17 UTC, Tejas wrote: On Tuesday, 10 August 2021 at 18:07:35 UTC, Bastiaan Veelo wrote: On Tuesday, 10 August 2021 at 16:00:37 UTC, Tejas wrote: there's casting away const, a clearly seperate language feature which has no equivalent in D; You *can* cast away `const` in D: https://run.dlang.io/is/sWa5Mf — Bastiaan. Yes, but it is UB, not defined and supported by the standard/implementation. OK, strictly speaking casting away `const` is in the language, but modifying after that is UB. https://dlang.org/spec/const3.html#removing_with_cast — Bastiaan.
Re: D has the same memory model as C++
On Tuesday, 10 August 2021 at 16:00:37 UTC, Tejas wrote: Basically, what are the subtle gotcha's in the differences between C++ and D code that looks similar The only gotcha that comes to my mind is that `private` means private to the module in D, not private to the aggregate. — Bastiaan.
Re: D has the same memory model as C++
On Tuesday, 10 August 2021 at 16:00:37 UTC, Tejas wrote: there's casting away const, a clearly seperate language feature which has no equivalent in D; You *can* cast away `const` in D: https://run.dlang.io/is/sWa5Mf — Bastiaan.
Re: Error when compile with DMD using -m64?
On Tuesday, 10 August 2021 at 17:13:31 UTC, Marcone wrote: On Tuesday, 10 August 2021 at 15:55:42 UTC, Bastiaan Veelo wrote: Use `size_t` and `ptrdiff_t` instead to make your program compile in both 32 bit and 64 bit modes. https://dlang.org/spec/type.html#aliased-types -- Bastiaan. Thank you very much! Your information was very precious! It worked very well! Now I can create x32 or x64 compatible programs without creating two codes. You’re welcome :-) — Bastiaan.
Re: Error when compile with DMD using -m64?
On Tuesday, 10 August 2021 at 01:29:04 UTC, Marcone wrote: Solved converting long and int. Use `size_t` and `ptrdiff_t` instead to make your program compile in both 32 bit and 64 bit modes. https://dlang.org/spec/type.html#aliased-types -- Bastiaan.
Re: How Add Local modules mymodule.d using DUB?
On Monday, 9 August 2021 at 16:32:13 UTC, Marcone wrote: My main program need import a local module called mymodule.d. How can I add this module using DUB? Thank you. Let’s assume you just created a dub project in `myproject` with `dub init`. Place `mymodule.d` alongside `app.d` in `myproject/source`. Now you can `import mymodule` in `app.d`. Dub takes care of the linking. — Bastiaan.
Re: writef, compile-checked format, pointer
On Monday, 9 August 2021 at 22:01:18 UTC, Patrick Schluter wrote: On Monday, 9 August 2021 at 19:38:28 UTC, novice2 wrote: format!"fmt"() and writef!"fmt"() templates with compile-time checked format string not accept %X for pointers, but format() and writef() accept it https://run.dlang.io/is/aQ05Ux ``` void main() { import std.stdio: writefln; int x; writefln("%X", ); //ok writefln!"%s"(); //ok //writefln!"%X"(); //compile error } ``` is this intentional? Yes. %X is to format integers. It is to format pointers as well, according to the last table on https://dlang.org/phobos/std_format.html. |Type|Format character|Formatted as| |-|-|-| |Pointer| 's' |A null pointer is formatted as 'null'. All other pointers are formatted as hexadecimal numbers with the format character 'X'.| | |'x', 'X' |Formatted as a hexadecimal number.| It looks like a bug to me. — Bastiaan.
Re: Exit before second main with -funittest
On Friday, 30 July 2021 at 05:51:41 UTC, Brian Tiffin wrote: [... interesting account of the D experience ...] **Kudos team and contributors.** Can't really suggest that many improvements to resources needed for learning D, as a hobbyist not on a clock, being new still and low enough to not know what detail interactions might be less approachable. So far, very approachable. Not confusing, but tantalizing caves to explore and integrate into knowing about potentials, super powers, and dark corners that may need to be accounted for. And friendly people to pester with random brain train new here questions. Have good, make well, and thanks. I enjoyed reading all of that. -- Bastiaan.
Re: how to make D program footprint smaller ?
On Friday, 9 July 2021 at 03:07:04 UTC, dangbinghoo wrote: as questioned in the previous thread, I need to find out something like `--as-needed` options available for D. You are probably looking for the [-i](https://dlang.org/dmd-osx.html#switch-i%5B) compiler option. As far as I know `dub` is not devised to work with that, so making use of it can be finicky. I have managed to get it to work on a `sourceLibrary` that we control, not sure how applicable it is on a third party package. — Bastiaan.
Re: Can I get the time "Duration" in "nsecs" acurracy?
On Friday, 9 July 2021 at 21:13:02 UTC, rempas wrote: On Friday, 9 July 2021 at 20:54:21 UTC, Paul Backus wrote: On Friday, 9 July 2021 at 20:43:48 UTC, rempas wrote: I'm reading the library reference for [core.time](https://dlang.org/phobos/core_time.html#Duration) and It says that the duration is taken in "hnsecs" and I cannot understand if we can change that and choose the precision. Does anyone know if we can do that? It is stored internally in "hnsecs", but you can convert it to other units using the `total` method [1]; for example, `myDuration.total!"nsecs"`. [1] https://dlang.org/phobos/core_time.html#.Duration.total It doesn't work for me. I have the following code: ``` MonoTime start = MonoTime.currTime(); // Doing stuff MonoTime end = MonoTime.currTime(); Duration dur = end - start; dur = dur.total!"nsecs"; ``` and I get the following error message: "Error: cannot implicitly convert expression \`dur.total()\` of type \`long\` to \`Duration`" You cannot change the precision of `Duration`, it always counts in multiples of 100 nsecs. You can count how many multiples of other units fit into the same `Duration` using `total`, but it will just return a number, not a “converted” `Duration`. `toString` will produce an easy readable string (more or less), as in https://run.dlang.io/is/baqKLG, where “hnsec” is the smallest unit. If you think hectonanosecond is a weird unit, then [you are not alone](https://forum.dlang.org/post/pwotyniksrskdzmea...@forum.dlang.org), and it [has been pointed out](https://forum.dlang.org/post/khppfxsyfefjksvri...@forum.dlang.org) that it does not comply with SI. — Bastiaan.
Re: Is there an alias for standard libraries to use in import statement?
On Sunday, 4 July 2021 at 07:40:44 UTC, BoQsc wrote: I just started with a fresh look at the D language and would like to be able to rewrite this code: import std; void main() { writeln("Hello D"); } Into more readable standard library name: import system; void main() { writeln("Hello D"); } That is [easy](https://run.dlang.io/is/af8dMY), just define the `system` module and publicly `import std`: --- test.d ```d import system; void main() { writeln("Hello D"); } ``` --- system.d ```d module system; public import std; ``` But like Mike, I advise against this. It will confuse every D programmer that is trying to read your code. What is most natural depends heavily on your background and what language you are coming from. `std` is perfectly natural if you're coming from C++. Fun fact (but equally ill advised): You can hide the entire import from view like this: ```d void main() { writeln("Hello D"); } /* Lean on Enter for a while */ import std; ``` -- Bastiaan.
Re: Printing Tuple!(...)[] using for loop?
On Friday, 2 July 2021 at 04:21:24 UTC, Kirill wrote: I have a `Tuple!(string, ..., string)[] data` If there are only strings in the tuple, it could be simplified by making it a static array of strings instead. The compile-time index issue would go away. —Bastiaan
Re: How to call stop from parallel foreach
On Thursday, 24 June 2021 at 20:56:26 UTC, Ali Çehreli wrote: On 6/24/21 1:33 PM, Bastiaan Veelo wrote: > distributes the load across all cores (but one). Last time I checked, the current thread would run tasks as well. Ali Indeed, thanks. — Bastiaan.
Re: How to call stop from parallel foreach
On Thursday, 24 June 2021 at 21:05:28 UTC, Bastiaan Veelo wrote: On Thursday, 24 June 2021 at 20:41:40 UTC, seany wrote: Is there any way to control the number of CPU cores used in parallelization ? E.g : take 3 cores for the first parallel foreach - and then for the second one, take 3 cores each -> so 3 + 3 * 3 = 12 cores out of a 16 core system? Thank you. There might be, by using various `TaskPool`s with a smaller number of work threads: https://dlang.org/phobos/std_parallelism.html#.TaskPool.this.2. But I cannot see the benefit of doing this. It will just distribute the same amount of work in a different way. Actually, I think this would be suboptimal as well, as the three outer threads seem to do no real work. — Bastiaan.
Re: How to call stop from parallel foreach
On Thursday, 24 June 2021 at 20:41:40 UTC, seany wrote: On Thursday, 24 June 2021 at 20:33:00 UTC, Bastiaan Veelo wrote: By the way, nesting parallel `foreach` does not make much sense, as one level already distributes the load across all cores (but one). Additional parallelisation will likely just add overhead, and have a net negative effect. — Bastiaan. Okey. So consider : foreach(array_elem; parallel(an_array)) { dothing(array_elem); } and then in `dothing()` : foreach(subelem; array_elem) { dootherthing(subelem); } - Will this ALSO cause the same overhead? You can nest multiple `foreach`, but only parallelise one like so: ```d foreach(array_elem; parallel(an_array)) foreach(subelem; array_elem) dootherthing(subelem); ``` So there is no need to hide one of them in a function. Is there any way to control the number of CPU cores used in parallelization ? E.g : take 3 cores for the first parallel foreach - and then for the second one, take 3 cores each -> so 3 + 3 * 3 = 12 cores out of a 16 core system? Thank you. There might be, by using various `TaskPool`s with a smaller number of work threads: https://dlang.org/phobos/std_parallelism.html#.TaskPool.this.2. But I cannot see the benefit of doing this. It will just distribute the same amount of work in a different way. — Bastiaan.
Re: How to call stop from parallel foreach
On Thursday, 24 June 2021 at 18:23:01 UTC, seany wrote: I have seen [this](https://forum.dlang.org/thread/akhbvvjgeaspmjntz...@forum.dlang.org). I can't call break form parallel foreach. Okey, Is there a way to easily call .stop() from such a case? Yes there is, but it won’t break the `foreach`: ```d auto tp = taskPool; foreach (i, ref e; tp.parallel(a)) { // … tp.stop; } ``` The reason this does not work is because `stop` terminates the worker threads as soon as they are finished with their current `Task`, but no sooner. `parallel` creates the `Task`s before it presents a range to `foreach`, so no new `Task`s are created during iteration. Therefore all elements are iterated. outer: foreach(i, a; parallel(array_of_a)) { foreach(j, b; parallel(array_of_b)) { By the way, nesting parallel `foreach` does not make much sense, as one level already distributes the load across all cores (but one). Additional parallelisation will likely just add overhead, and have a net negative effect. — Bastiaan.
Re: Financial Library
On Sunday, 13 June 2021 at 12:46:29 UTC, Financial Wiz wrote: What are some of the best Financial Libraries for D? I would like to be able to aggregate as much accurate information as possible. Thanks. I am not into financials, but these libs show up in a search: https://code.dlang.org/search?q=Decimal. Perhaps you know some other relevant terms to search for. One of the [sponsors](https://dlang.org/foundation/sponsors.html) of dlang is Symmetry Investments, who run a hedge fund. Their use of D is pretty advanced, and includes many libs and utilities that are not limited to financial applications. These are the ones that I know of: https://code.dlang.org/search?q=Mir, https://code.dlang.org/packages/dpp, https://code.dlang.org/packages/pegged, https://code.dlang.org/packages/excel-d, https://github.com/symmetryinvestments. — Bastiaan.
Re: Inclusion of Parenthesis on Certain Functions
On Sunday, 13 June 2021 at 15:45:53 UTC, Justin Choi wrote: I've tried looking through the documentation but can't find an explanation for why you can use it without parenthesis. https://dlang.org/spec/function.html#optional-parenthesis (Some exceptions regarding delegates and function pointers exist.) —Bastiaan
Re: coreutils with D trials, wc, binary vs well formed utf
On Monday, 24 May 2021 at 16:58:33 UTC, btiffin wrote: [...] Just bumped into https://dlang.org/blog/2020/01/28/wc-in-d-712-characters-without-a-single-branch/ [...] Is there a(n easy-ish) way to fix up that wc.d source in the blog to fallback to byte stream mode when a utf-8 reader fails an encoding? Welcome, Brian. I have allowed myself to use exception handling and `filter`, which I regard to be no longer branch free. But it does (almost) produce the same output as gnu wc: ```d Line toLine(char[] l) pure { import std.utf : UTFException, byChar; import std.ascii : isWhite; import std.algorithm : filter; try { return Line(l.byCodePoint.walkLength, l.splitter.walkLength); } catch (UTFException) { return Line(l.length, l.byChar.splitter!(isWhite). filter!(w => w.length > 0).walkLength); } } ``` The number of chars can be returned in O(0) by the `.length` property. Use of `byChar.splitter!(isWhite)` considers the ASCII values of the chars, but without the `filter` it counts too many words. The reason is that a mix of different white space characters causes problems (https://run.dlang.io/is/QzjTN0): ```d writeln("Hello \t D".splitter!isWhite); // ["Hello", "", "", "D"] writeln("Hello \t D".splitter); // ["Hello", "D"] ``` This surprises me, could be a bug. So `filter!(w => w.length > 0)` filters out the "words" with zero length... Compared to gnu wc this reports one line too many for me, though. There may be more elegant solutions than mine. -- Bastiaan.
Re: Struct initialization extra comma - should it compile
On Sunday, 25 April 2021 at 13:39:54 UTC, JN wrote: struct Foo { int x, y, z; } void main() { Foo bar = Foo(1,); } This compiles without syntax errors, is this expected? Yes, the [specification](https://dlang.org/spec/declaration.html#StructInitializer) is like this: ``` StructMemberInitializers: StructMemberInitializer StructMemberInitializer , StructMemberInitializer , StructMemberInitializers ``` — Bastiaan.
Re: When should I use SortedRange.release?
On Friday, 23 April 2021 at 21:34:39 UTC, Steven Schveighoffer wrote: `SortedRange` itself is kind of a kludge of "policy" that isn't fit for function. I use release to get the original data type out (via r.save.release), but that's about it. See my rant about it [here](https://forum.dlang.org/post/r7ia94$19uo$1...@digitalmars.com) -Steve Understood, thanks. --Bastiaan.
Re: When should I use SortedRange.release?
On Friday, 23 April 2021 at 18:35:25 UTC, Paul Backus wrote: On Friday, 23 April 2021 at 17:35:13 UTC, Bastiaan Veelo wrote: What happens when a range is released? What happens if a range is not released? What happens if a range is released more than once? And what does "controlled" imply here? In what way has `SortedRange` control over the underlaying data? What can I do and what can't I do to the underlying data as long as `SortedRange` has control? I had to look at the source to figure this out. Fortunately, the source is pretty simple: https://phobos.dpldocs.info/source/std.range.d.html#L10833 Turns out, it just calls `core.lifetime.move`. So I guess when the docs say "control", what they are really talking about is ownership. Practically speaking, this means that in generic code, we should avoid using a `SortedRange` after calling `release`, since we do not know whether the range is owning or non-owning w.r.t. the underlying data. Thanks. There is no word in the documentation about when `SortedRange` would or would not be owning data, though, and hence when `release` would be appropriate to call. To me `release` seems to be calling `std.algorithm.mutation.move` , but it is probably very similar to `core.lifetime.move`. In case the underlying data is a slice, I think we end up at https://phobos.dpldocs.info/source/std.algorithm.mutation.d.html#L1459, which I can't see accomplishes anything in [this example](https://dlang.org/phobos/std_algorithm_sorting.html#.sort) (except returning the slice that went in): ```d int[] array = [ 1, 2, 3, 4 ]; // sort in descending order array.sort!("a > b"); writeln(array); // [4, 3, 2, 1] // sort in ascending order array.sort(); writeln(array); // [1, 2, 3, 4] // sort with reusable comparator and chain alias myComp = (x, y) => x > y; writeln(array.sort!(myComp).release); // [4, 3, 2, 1] ``` -- Bastiaan.
When should I use SortedRange.release?
For reference, `SortedRange.release` is [documented](https://dlang.org/phobos/std_range.html#.SortedRange) as such: "Releases the controlled range and returns it." Wow thanks! I love functions that are named exactly as what they do ;-) Seriously though, I still don't know what it is that it does, and why and when it should be done, and when not. What happens when a range is released? What happens if a range is not released? What happens if a range is released more than once? And what does "controlled" imply here? In what way has `SortedRange` control over the underlaying data? What can I do and what can't I do to the underlying data as long as `SortedRange` has control? My failure to understand this function makes me fear I don't understand `SortedRange` at all, and thereby don't understand how to use `algorithm.sorting` properly. Thanks! -- Bastiaan.
Re: Range Error
On Sunday, 11 April 2021 at 19:45:30 UTC, Ruby The Roobster wrote: What am I doing wrong here? Is it the 'for' loop? Yes, there is a `7` where there should be an `i` on this line: ```d for(int i=7;7>=0;i--) ``` This will go on forever, so you get a range error as soon as `i < 0`. —Bastiaan.
Re: Example for Mir-Random fails
On Saturday, 3 April 2021 at 19:02:34 UTC, Brad wrote: I just do not know enough about the D libraries to figure out what is wrong. I know it is a case of type mismatch. The example appears on the Mir-Random page as listed under DUB: https://code.dlang.org/packages/mir-random [...] I think you are seeing conflicts between Phobos and Mir: they both provide unpredictableSeed and Random. If you want to use the ones from Mir, be sure to not import std or std.random, or use fully qualified names. — Bastiaan.
Re: C++/D class interop example crashes
On Saturday, 27 March 2021 at 15:09:20 UTC, Jan wrote: I just tried to get this example to work: https://dlang.org/spec/cpp_interface.html#using_d_classes_from_cpp It kept crashing for me with a 'privileged instruction' error when the function 'bar' was executed. Finally I removed the call to writefln and voilà it finally works. So why does it fail? I assumed the standard library functions should all work. I'm compiling with "dmd -shared -m64 -debug" and link against a C++ DLL that was built with VS2019. Should the D DLL not contain everything to be self-sufficient to use it's entire runtime functionality? And if not, what other functions might be problematic? The example links objects statically. You may be experiencing additional challenges with crossing DLL boundaries. I have not yet used DLLs, but did you initialise the D runtime? — Bastiaan.
Re: Contributing CDF bindings to Deimos
On Thursday, 25 March 2021 at 04:00:33 UTC, Chris Piker wrote: As an aside, software developers at NASA Goddard have now heard of D which is nice. They were pleased to see that it was supported by gcc. (Hat tip to the GDC team) That’s cool. I’d love to see NASA on https://dlang.org/orgs-using-d.html one day. — Bastiaan.
Re: Why are enums with base type string not considered strings?
On Sunday, 14 March 2021 at 16:09:39 UTC, Imperatorn wrote: On Sunday, 14 March 2021 at 10:42:17 UTC, wolframw wrote: enum BoolEnum : bool { TestBool = false } enum CharEnum : char { TestChar = 'A' } enum StringEnum : string { TestString = "Hello" } pragma(msg, isBoolean!BoolEnum); // true pragma(msg, isSomeChar!CharEnum); // true pragma(msg, isSomeString!StringEnum); // false Why does isSomeString not return true for an enum with base type string May be a regression? https://issues.dlang.org/show_bug.cgi?id=16573 Indeed: https://run.dlang.io/is/liSDBZ It regressed in 2.079.1. Seems to be worth an issue report. —Bastiaan.
Re: Dlang spec
On Thursday, 11 March 2021 at 19:38:01 UTC, Imperatorn wrote: I created some PDFs (on request) of the dlang spec mobi-file and uploaded them here: https://gofile.io/d/ijctZt Different converters were used, hence multiple files. Maybe someone can upload a good version on dlang.org and link to it? The spec is written in ddoc format, and I thought that ddoc was able to output in PDF (at least at one point). It didn’t look very good and I’m not sure if the functionality is still there. I was only able to find an old initiative [1] and two old threads discussing the idea [2][3]. I didn’t read all that now. Regarding uploading, the way this usually goes is that you submit a PR against the website. But I’m not sure it will be accepted if the process cannot be automated so that the PDFs stay in sync with any future changes in the spec without manual intervention. In my opinion the way to produce quality PDF is through LaTeX. Maybe something can be based on adrdox to produce useful LaTeX, that would be an interesting project. — Bastiaan. [1] https://forum.dlang.org/post/dhq4k6$12tp$1...@digitaldaemon.com [2] https://forum.dlang.org/post/i9fco2$i05$1...@digitalmars.com [3] https://forum.dlang.org/post/kc883a$1b8p$1...@digitalmars.com
Re: D's Continous Changing
On Wednesday, 3 March 2021 at 23:30:20 UTC, harakim wrote: Contrast to me trying to figure out how to format a number in binary. format!"%b"(number) does not work but is very similar to what is suggested in the documentation. I was able to figure out it's format("%b", number) but it took a few minutes. This works for me: rdmd --eval="writeln(format!`%b`(5));" 101 rdmd --eval="writeln(__VERSION__);" 2096 -- Bastiaan.
Re: D's Continous Changing
On Wednesday, 3 March 2021 at 23:30:20 UTC, harakim wrote: Every time I come back to a D program I wrote over a year ago, it seems like there are numerous breaking changes and it takes me a while to get it to compile again. I am porting a large code base from Extended Pascal to D and I know that there will be changes in the language in the future that will take an effort to adapt to. Yet, I am still in the camp of wanting these changes to happen because we don't want to port from a dead language to another dead language, we need the language to be alive. The way I deal with this is to lock down version numbers with the revision number of our code base. By having dub.selections.json under revision control we make sure that the same version of dependencies are used every time until we upgrade, and by having this in dub.json: ``` "toolchainRequirements": { "frontend": "==2.096" }, ``` we ensure that the code simply refuses to compile with any other language version. So, if two years from now we were to check out a revision that was two years old, yes we would have to downgrade the compiler but it would still work. Upgrading to a newer language version or dependency version can be done outside of the main development branch, where it can be properly tested before merging. Ideally I want the build system to automatically install and/or activate the compiler specified in the code base so that a toolchain upgrade becomes just like a regular feature commit, possibly using one of the existing compiler version managers [1, 2] or by extending dub itself. Then, fellow developers will hardly notice compiler upgrades, the build farm doesn't need attention, and bisecting revisions to pin down the occurrence of a regression can be done without complications. I think it is important that warts in the language and standard library are removed, and luckily we have a proper deprecation mechanism. My advice is, if you pick up a two-year old project and don't want to deal with breakages, you just continue with the versions from that time; Until you choose to use newer features, but you can plan for the work that this requires. -- Bastiaan. [1] https://dlang.org/install.html [2] https://code.dlang.org/packages/dvm
Re: Minimize GC memory footprint
On Wednesday, 3 February 2021 at 13:37:42 UTC, frame wrote: I have to deal with GC as long I want to use other libraries that are relying on it or even just phobos. Conclusion so far (for Windows): 32bit: - GC just doesn't work at all ?? Do you mean no collections happen? 32bit GC should just work. 64bit: - Collections are rare. It can be necessary to call GC.collect() manually. - Scope guards to explicit clean up / free memory at function exit have no deep impact on most cases. - If your application should save memory call GC.minimize() when it's appropriate. It seems that calling GC.enable() if it's already enabled just disables the automatic GC again? Is this a bug? I cannot reproduce it outside my application yet since it's not clear when the GC starts collecting, but it always shows the same behaviour: // GC.enable(); Case A: The app is very kind in memory usage (~20 MB) GC.enable(); Case B: The app is consuming huge amount of memory (~900 MB) GC.disable(); GC.enable(); Case A again GC.disable(); GC.enable(); GC.enable(); Case B again That looks like a bug indeed. I also have to struggle what the specs' text actually mean: This function is reentrant, and must be called once for every call to disable before automatic collections are enabled. I think it means that you need to make sure that enable() is called as many times as disable() is called before collection can happen automatically. — Bastiaan.
Re: Using the Standard Library with C++ Interop
On Friday, 5 February 2021 at 21:40:29 UTC, wolfiesnotfine wrote: In any case, I'm unsure how I would runtime init from C++. Is there a specific function I should call? https://dlang.org/phobos/core_runtime.html#.rt_init Could this be done at compile time in a consteval or constexpr function? This being the runtime, I presume it should be called at run time :-) I haven’t used it, but searching for rt_init should give you some pointers. —Bastiaan
Re: writeln and write at CTFE
On Wednesday, 13 January 2021 at 09:11:53 UTC, Guillaume Piolat wrote: On Wednesday, 13 January 2021 at 08:35:09 UTC, Andrey wrote: Hello all, Tell me please how can I "writeln" and "write" in function that is used in CTFE? At the moment I get this: import\std\stdio.d(4952,5): Error: variable impl cannot be modified at compile time Or may be exist some other ways to do it? pragma(msg, ); This may however not do what you wish it to do: https://forum.dlang.org/post/mailman.4526.1499573493.31550.digitalmars-d-le...@puremagic.com — Bastiaan.
Re: Using a betterC dub package in ordinary D
On Friday, 8 January 2021 at 18:28:36 UTC, Ferhat Kurtulmuş wrote: On Friday, 8 January 2021 at 15:40:12 UTC, Bastiaan Veelo wrote: Hi, When I use earcutd [1] in an ordinary D project, I get a link error for the __D7earcutd12__ModuleInfoZ symbol. [...] Dear Bastiaan, I am not an expert in dub system, but I have just pushed a modification in dub.json. I am not sure if it solves your problem. My modification is "configurations": [ { "name": "default", "targetType": "library" }, { "name": "betterC", "targetType": "library", "dflags": ["-betterC"] } ] now client projects must explicitly pass the subConfiguration parameter to compile it with betterC. Much appreciated Ferhat! This works like a charm. I am kind of surprised that it does, as I expected dvector to need the same treatment. Excellent support by the way, thanks! Off topick, the original js implementation is documented to not generate results that are guaranteed to be correct. I could not find information on what the conditions are that cause deviations, and how large these then can be. Do you have an idea about this or experience with accuracy of the algorithm? I am looking into whether earcutd can replace GLU tesselation. We use the result for engineering purposes (not only visualisation) and correctness is important to us. Thanks! Bastiaan.
Using a betterC dub package in ordinary D
Hi, When I use earcutd [1] in an ordinary D project, I get a link error for the __D7earcutd12__ModuleInfoZ symbol. This is because the earcutd dub.json has `"dflags": ["-betterC"]`. I think this is in error, my understanding of betterC code is that it can be compiled with "-betterC", but does not need to (and must not when used in D context). Am I right? What are the best practices for betterC dub packages? Thanks, Bastiaan. [1] https://code.dlang.org/packages/earcutd
Re: Writing a really fast lexer
On Saturday, 12 December 2020 at 18:15:11 UTC, vnr wrote: On Saturday, 12 December 2020 at 16:43:43 UTC, Bastiaan Veelo wrote: Have you looked at Pegged [1]? It will give you the lexer and parser in one go. I'd be very interested to see how it performs on that kind of input. -- Bastiaan. [1] https://code.dlang.org/packages/pegged Yes, I know Pegged, it's a really interesting parser generator engine, nevertheless, the grammar of what I would like to analyse is not a PEG. But I am also curious to know the performances of this tool for very large inputs. Are you able to share the grammar? Since you plan to parse using recursive descent, I think there is a good chance that the language can be defined as a PEG. I am using it to parse Pascal, whose grammar was defined long before PEG was a thing. — Bastiaan.
Re: Writing a really fast lexer
On Friday, 11 December 2020 at 19:49:12 UTC, vnr wrote: For a project with good performance, I would need to be able to analyse text. To do so, I would write a parser by hand using the recursive descent algorithm, based on a stream of tokens. I started writing a lexer with the d-lex package (https://code.dlang.org/packages/d-lex), it works really well, unfortunately, it's quite slow for the number of lines I'm aiming to analyse (I did a test, for a million lines, it lasted about 3 minutes). As the parser will only have to manipulate tokens, I think that the performance of the lexer will be more important to consider. Therefore, I wonder what resources there are, in D, for writing an efficient lexer. Have you looked at Pegged [1]? It will give you the lexer and parser in one go. I'd be very interested to see how it performs on that kind of input. -- Bastiaan. [1] https://code.dlang.org/packages/pegged
Re: Pass enum variable as const ref arg
On Friday, 4 December 2020 at 12:54:25 UTC, Andrey wrote: Hello, void test(const ref string[3] qazzz) { qazzz.writeln; } void main() { enum string[3] value = ["qwer", "ggg", "v"]; test(value); } Gives errors: It works if you pass `-preview=rvaluerefparam` to the compiler. But the other suggestions are better IMO. —Bastiaan.
Re: Is garbage detection a thing?
On Sunday, 29 November 2020 at 16:05:04 UTC, Mark wrote: Hi, can I ask you something in general? I don't know anyone whom I could ask. I'm a hobbyist with no science degree or job in computing, and also know no other programmers. I have no good understanding why "garbage collection" is a big thing and why "garbage detection" is no thing (I think so). In order to detect garbage, you need extensive run-time instrumentation, the difficulties of which you have indicated yourself. In addition comes that detection depends on circumstance, which is an argument against the debug/release strategy you proposed. There is no guarantee that you’ll find all problems in the debug build. Garbage collection also comes at a runtime cost, but strategies exist to minimise those, and in addition a GC enables valuable language features. One such strategy is to minimise allocations, which improves performance in any memory management scheme. [...] What I don't understand is, when today there exist tools for C++ (allocator APIs for debugging purposes, or Address-Sanitizer or maybe also MPX) to just detect that your program tried to use a memory address that was actually freed and invalidated, why did Java and other languages not stop there but also made a system that keeps every address alive as long as it is used? Elimination of memory problems is much more valuable than detection. Recovering from memory errors at run time is unreliable. One very minor criticism that I have is: With GC there can be "semantically old data" (a problematic term, sorry) which is still alive and valid, and the language gives me the feeling that it is a nice system that way. But the overall behavior isn't necessarily very correct, it's just that it is much better than a corrupted heap which could lead to everything possibly crashing soon. At least in D, you can avoid old data to hang around for too long. See core.memory. Or maybe I could use the safe-c subset in D? But I believe it uses garbage collection. I know nothing about it, sorry. @safe D is not a sub-set, indeed it uses garbage collection. Fact is that there are very few domains where this is a problem. Not all garbage collectors are equal either, so if you think garbage collection is bad in one language, this may not directly apply in another. In D the garbage collector is even pluggable, various implantations exist. Have you seen the GC category on the blog?https://dlang.org/blog/2017/03/20/dont-fear-the-reaper/ BetterC is a subset of D, it does not use garbage collection. You may be interested in current work being done in static analysis of manual memory management in D: https://youtu.be/XQHAIglE9CU The advantage of D is that all options are open. This allows the following approach: 1) Start development without worrying about memory. Should collection cycles be noticeable: 2) Profile your program and make strategic optimisations https://youtu.be/dRORNQIB2wA. If this is not enough: 3) Force explicit collection in idle moments. If you need to go further: 4) Completely eliminate collection in hot loops using @nogc and/or GC.disable. When even this is not enough: 5) Try another GC implementation. And if you really need to: 6) Switch to manual memory management where it matters. This makes starting a project in D a safe choice, in multiple meanings of the word. — Bastiaan.
Re: Can't pass [] to extern function object method
On Wednesday, 18 November 2020 at 10:50:12 UTC, frame wrote: I found the "bug". It was caused by a debug {} statement within a struct method. I assume that the debug symbol is just incompatible called from the DLL context. Were the DLL and main program built in different modes (debug/release)? Then this problem is understandable. Otherwise I find this surprising, and probably worth a bug report? — Bastiaan.
Re: How can execute method in new Thread?
On Saturday, 14 November 2020 at 17:21:15 UTC, Marcone wrote: Error: D:\dmd2\windows\bin\..\..\src\phobos\std\parallelism.d(516): Error: struct `Fruit` does not overload () I think you need to pass the this pointer somehow. This works: import std; struct Fruit { string name; static void printmyname(Fruit thisFruit) { writeln(thisFruit.name); } void showname() { task!printmyname(this).executeInNewThread; } } void main() { Fruit f = Fruit("Banana"); f.showname(); } This does too: import std; struct Fruit { string name; void printmyname() { writeln(name); } void showname() { task!((Fruit me){me.printmyname;})(this).executeInNewThread; } } void main() { Fruit f = Fruit("Banana"); f.showname(); } —Bastiaan.
Re: App hangs, GC.collect() fixet it. Why?
On Monday, 28 September 2020 at 21:58:31 UTC, Steven Schveighoffer wrote: On 9/28/20 3:28 PM, Bastiaan Veelo wrote: I’m leaning towards ditching the memory mapped I/O on the D end, and replace it by regular serialisation/deserialisation. That will be a manual rewrite though, which is a bit of bummer as memory mapped files are widely used in our Pascal code. But this will probably give the best end result. 2 things: 1. I agree this is the answer. If you ever ditch the old Pascal code, then you can reactivate the memory-mapped code. 2. You can possibly do the translation outside of your programs. That is, it wouldn't be entirely impossible to simply have a process running that ensures the "D view" and the "Pascal view" of the same file is kept in sync. Then you can keep the memory mapped code the same, and just define sane structures in your D code. If you aren't required to have both Pascal and D programs reading and writing the file at the same time, this shouldn't be a problem. There is no need to run both versions concurrently. The issue is that design offices typically maintain a library of past designs for as long as they are in existence, to build new designs off of. So being able to read or import the files that were written with an ancient version of our software is very valuable. Our old compiler offered two alternatives for file i/o: one where all elements are of the same type, the other one (memory mapped files) being the "only" option for files of mixed type. Ideally, the structs that are used for i/o do not have any pointers in them, and certainly in the more recent file versions that would be the case. In older versions that might not be the case; then the pointers obviously would be given meaningful values after the structs would have been read back in. These cases we would be able to work around, though, by converting the old structs to new ones upon import. BTW, one further thing I don't understand -- if this is memory mapped data, how come it has issues with the GC? And what do the "pointers" mean in the memory mapped data? I'm sure there's good answers, and your actual code is more complex than the simple example, but I'm just curious. The main problem is that the transpiler doesn't know which structs are used for i/o and would need 1-byte alignment, and which structs have pointers into GC memory and must not be 1-byte aligned. The alternative to switching to serialisation/deserialisation is to stay with the automated translation of the memory mapped file implementation, not automatically 1-byte align every struct but manually align the ones that are used in i/o. This is however sensitive to mistakes, and the translated mmfile implementation has a bit of a smell to it. It is also not portable, as it uses the WinAPI directly. Still, it may be the quickest route to get us back on track. I am very glad to have identified the problem, and there being ways to deal with it. I just hope this will be the last big hurdle :-) -Bastiaan.
Re: App hangs, GC.collect() fixet it. Why?
On Monday, 28 September 2020 at 15:44:44 UTC, Steven Schveighoffer wrote: On 9/28/20 8:57 AM, Bastiaan Veelo wrote: I am glad to have found the cause of the breakage finally, but it won't be easy to find a generic solution... Obviously, this isn't a real piece of code, but there is no way around this. You have to align your pointers. The other option is to not use the GC and use manual memory management. If this is a compatibility thing between D and Pascal, and you absolutely have to have the same layout, is there a way to adjust the structure in Pascal? Like put the elements that misalign the pointers at the end of the structure? Another totally drastic approach would be to supply your own even-more-conservative GC which will scan misaligned pointers. Probably going to hurt performance quite a bit. You might be able to get away with marking only certain blocks as having misaligned pointers, but you will have to scan all the stacks with this assumption. Some more information about the setup you are using might help (I'm assuming D and Pascal are using the same memory in the same process, otherwise this wouldn't be a problem). In particular, where does the data come from, and how malleable is it in your system? Are there times where references to the D data only exist in Pascal? -Steve Thanks a lot for thinking with me. I’m not linking any Pascal objects, so I don’t need to maintain binary compatibility in memory; Only compatibility of data files. The problem arises when those files are read using memory mapped files, from which structs are memcpy’d over. This is of course the result of machine translation of the current Pascal implementation. Manual memory management is an option and would be straightforward in principle, as we’ve done that for ages. The only thing is that this memory cannot contain other allocations on the GC heap, such as strings or other slices, unless they are both aligned and their root is registered. Fixing the alignment in Pascal is possible in principle, but any old files would then need to first be processed by the last Pascal version of the programs, which we then would need to keep around indefinitely. There would also be issues when we port from 32 bit to 64 bit. Another option could be to use 1-byte aligned structs for I/O, and copy the members over in default aligned versions. But this cannot be part of the automated transcompilation. Thanks for suggesting a custom gc, which I had not thought of. I’m leaning towards ditching the memory mapped I/O on the D end, and replace it by regular serialisation/deserialisation. That will be a manual rewrite though, which is a bit of bummer as memory mapped files are widely used in our Pascal code. But this will probably give the best end result. -Bastiaan.
Re: App hangs, GC.collect() fixet it. Why?
On Friday, 5 June 2020 at 21:20:09 UTC, Steven Schveighoffer wrote: This kind of sounds like a codegen bug, a race condition, or (worst case) memory corruption. I think it must have been memory corruption: I had not realized that our old Pascal compiler aligns struct members on one byte boundaries, and also uses ubyte as the base type for enumerations (or ushort if required) instead of uint. When using memory mapped files this binary incompatibility likely caused the corruption. But, after correcting that mistake, suddenly things broke that had been working for a long time. Having no idea what could be wrong this time, I spent quite some time dustmiting (thanks Vladimir!) and manually reducing the code. Voilà: import std.stdio; import core.memory; struct Nothing { } struct Info { align(1): ubyte u; Nothing*[2] arr; } Info* info; void main() { info = new Info; writeln("1"); GC.collect(); info.arr[0] = new Nothing; writeln("2"); GC.collect(); info.arr[1] = new Nothing; writeln("info.arr[0] = ", info.arr[0]); writeln("info.arr[1] = ", info.arr[1]); assert(info.arr[0] != info.arr[1], "Live object was collected!"); } (The assert triggers on Windows, not on run.dlang.org.) Unfortunately for me, I cannot blame this on the compiler. It violates the requirements from the spec: "Do not misalign pointers if those pointers may point into the GC heap" (https://dlang.org/spec/garbage.html) I am glad to have found the cause of the breakage finally, but it won't be easy to find a generic solution... -Bastiaan.
Re: Why Pegged action dont not work in this case ?
On Sunday, 19 April 2020 at 16:47:06 UTC, Basile B. wrote: I 've started experimenting Pegged action. Quickly i got blocked by this problem. The start action works where I use the rule but not directly in the rule. I don't understand the difference between how you use "where" and "directly in". Note that semantic actions are executed during the parsing process, even in branches that eventually fail, before the parser back tracks. They are not a substitute for traversing the final parse tree, rather, they are a method for manipulating the parsing process as it happens. That's why `endResultRecord` is executed directly after `(',' Result)*` succeeds, and `beginResultRecord` is executed directly after `ResultRecord` succeeds (even if `'(gdb)'` would not match). Test program: [...] ResultRecord< {beginResultRecord} Token? '^' ResultClass (',' Result)* {endResultRecord} Remove the space between "<" and "{", then it works. Also I'd like to report that actions dont work with partially specialized templates: --- T handleResultRecord(bool end, T)(T t); // then you use handleResultRecord!true and handleResultRecord!false in the PEG. --- That fails for the same reason as `handleResultRecord!true(1)` fails to instantiate. -- Bastiaan.
App hangs, GC.collect() fixet it. Why?
I've been tracking down a hang in our pilot app. Using writeln, it appears to hang at newing a slice. After many hours of trying things, I discovered that program flow would continue past that point when I inserted a call to `GC.collect()` just before. Then it stalled again at a call to Win32 `SetMenu()`. Again, inserting `GC.collect()` before that made the problem go away. This band-aid isn't going to scale in the long run. I feel I'm treating symptoms, and wonder what the cause is. Any ideas? I know the GC is not disabled somehow because if I print `GC.profileStats()`, I see that there are collections even without my explicit calls to `GC.collect()`. Thanks, Bastiaan.
Re: Postblit segfault.
On Monday, 1 June 2020 at 09:42:44 UTC, Boris Carvajal wrote: On Monday, 1 June 2020 at 06:35:36 UTC, MaoKo wrote: Hello, I don't understand why this code segfault on Reduced to: import std.stdio; struct S {} void main() { S[1] s; writeln(s); } This used to work up to dmd 2.084.1. It fails since 2.085.1. Please file a regression report at https://issues.dlang.org/enter_bug.cgi?product=D — Bastiaan.
Re: CT BitArray
On Thursday, 1 November 2018 at 08:50:38 UTC, Bastiaan Veelo wrote: On Thursday, 1 November 2018 at 00:01:04 UTC, Stefan Koch wrote: On Wednesday, 31 October 2018 at 23:14:08 UTC, Bastiaan Veelo wrote: Currently, BitArray is not usable at compile time, so you cannot do ``` enum e = BitArray([1, 1, 1, 0]); ``` This gives /dlang/dmd/linux/bin64/../../src/phobos/std/bitmanip.d(1190): Error: `bts` cannot be interpreted at compile time, because it has no available source code [] meanwhile use module level BitArrays like ``` immutable BitArray e; static this() { e = BitArray([1, 1, 1, 0]); } ``` Note to self: when this occurs, the above error message does not offer a trace to the place where this originates. To get that, temporarily insert the following at the indicated line in bitmanip.d: ``` if(__ctfe) assert(false, "trap"); ``` --Bastiaan.
Re: New with alias
On Tuesday, 10 March 2020 at 06:09:23 UTC, tcak wrote: I write a code as below: auto result = new char[4]; It allocates memory as expected. This is a slice of four chars, which can be used as a dynamic array. Later I define an alias and do the above step: alias Pattern = char[4]; This is an alias for a static array with a fixed length of four chars. auto result = new Pattern; But compiler says: Error: new can only create structs, dynamic arrays or class objects, not `char[4]`'s Is this a bug, or `alias` doesn't work how I was thinking? It is not a bug. You cannot new static arrays. You can do this, though: Pattern pattern; // One static array of four chars. auto patterns = new Pattern[3]; // A slice with three static arrays of four chars. --Bastiaan.
Re: Specify dmd or ldc compiler and version in a json dub file?
On Tuesday, 8 August 2017 at 09:17:02 UTC, data pulverizer wrote: I would like to know how to specify dmd or ldc compiler and version in a json dub file. Update: you can at least specify these in the toolchain requirements section: https://dub.pm/package-format-json.html#toolchain-requirements I myself am looking for ways to satisfy these automatically, using a tool like dvm (https://code.dlang.org/packages/dvm) in preBuildCommands. Bastiaan.
Re: Slice/Substr [0..?lastIndexOf(".")] How refer itself without create a variable?
On Thursday, 5 December 2019 at 11:28:51 UTC, Marcone wrote: Simple example: writeln("Hi\nHow are you?\nGood".splitLines()[0][0..?lastIndexOf(r"\")]); How to refer to this string in lastIndexOf() without create a variable? Thank you. .splitLines[0] already just produces "Hi", containing no "\", so this example is a bit broken. writeln("#", "Hi\nHow are you?\nGood".splitLines()[0], "#"); // #Hi# You could write a function to work around having to declare a variable: string upto(string input, string delim) { return input[0 .. input.countUntil(delim)]; } void main() { writeln(upto("Up to colon: skip this", ":")); // Up to colon writeln("Up to colon: skip this".upto(":")); // Up to colon } You can use a function literal or lambda, but it isn't pretty: writeln((string s){return s[0..s.countUntil(":")];}("Up to colon: skip this")); // Up to colon writeln((s => s[0..s.countUntil(":")])("Up to colon: skip this")); // Up to colon Bastiaan.
Re: const and immutable values, D vs C++?
On Wednesday, 4 December 2019 at 14:44:43 UTC, Ola Fosheim Grøstad wrote: When is there a noticable difference when using const values instead of immutable values in a function body? And when should immutable be used instead of const? f(){ const x = g(); immutable y = g(); ... do stuff with x and y … } There is a difference I guess if g() returns a reference type and is an inout function. immutable y will only work if the reference returned is immutable. Const is a promise to the rest of the code that you will never mutate it. Immutable is a promise by the rest of the code that it will never mutate. Immutable is more powerful, allowing data sharing in overlapping slices and between threads without locks. Const is more versatile, allowing references to data regardless of its mutability. So if g() always returns immutable, it’s best to receive it as such, not const. If it can be either, it must be received as const. I'm comparing D to C++ and I get the following mapping: Does that make sense at all? D’s const is transitive, C++’s is not. Bastiaan.
Re: Unexpected aliasing
On Tuesday, 12 November 2019 at 08:15:20 UTC, Basile B. wrote: I'm curious to know what is the equivalent in Pascal that your transpiler fails to translate since Pascal records don't have constructors at all. Maybe you used an old school 'Object' ? Note that Extended Pascal is not exactly Pascal. An example: TYPE Ints(upperBound) = ARRAY [1 .. upperBound] of Integer; MyRecord = RECORD integers : Ints(5); END; SchematicRecord(num) = RECORD integers : Ints(num); END; IntsPtr = ^Ints; PROCEDURE myProcedure(PROTECTED VAR someArr : Ints); BEGIN writeln(someArr.upperBound); END; PROCEDURE proc; VAR dynamicInts : IntsPtr; rec : MyRecord; BEGIN dynamicInts = new(10); myProcedure(dynamicInts^); myProcedure(rec.integers); END; In this case, only the upper bound of Ints is parameterized, but the lower bound could be parameterized as well. Records can also be schematized. Procedure arguments can take schemas that are undiscriminated, they carry their schemaparameters as properties. Bastiaan.
Re: Unexpected aliasing
On Monday, 11 November 2019 at 21:52:12 UTC, Jonathan M Davis wrote: On Monday, November 11, 2019 12:17:37 PM MST Bastiaan Veelo via Digitalmars- d-learn wrote: [...] I could use some help in rewriting the code below so that arr1 and arr2 each have their own data; ideally with minimal changes so that I can make the transcompiler do the right thing. Thanks! Bastiaan. void main() { import std.stdio; WrapIntegerArray arr1; arr1[0] = 42; WrapIntegerArray arr2; writeln(arr2[0]); // 42, not 0. writeln("arr1.wrap.arr.ptr = ", arr1.wrap.arr.ptr); writeln("arr2.wrap.arr.ptr = ", arr2.wrap.arr.ptr); // identical assert(arr2[0] == 0); // fails } struct IntegerArray { int[] arr; alias arr this; this(int l) { arr = new int[l]; } } struct WrapIntegerArray { auto wrap = IntegerArray(5); // This is CTFE! :-( alias wrap this; } All struct and class members which are directly initialized must have their values known at compile-time. For structs, that's what goes in the init value for the type. A side effect of this is that it's usually a bad idea to directly initialize dynamic arrays which are member variables. You need to do the initialization in a constructor. And for structs, if you need a no-arg constructor, then you'll need to use a factory function (since structs can't have no-arg constructors). e.g. struct WrapIntegerArray { IntegerArray wrap; alias wrap this; this(int len) { wrap = IntegerArray(len); } } or struct WrapIntegerArray { IntegerArray wrap; alias wrap this; static make() { WrapIntegerArray retval; retval.wrap = IntegerArray(5); return retval; } } So, you could then have something like auto arr1 = WrapIntegerArray(5); arr1[0] = 42; or auto arr1 = WrapIntegerArray.make(); arr1[0] = 42; but if you use the init value (which is what you get if you let the type be default-initialized), then you'll have to first do something to allocate the dynamic array if you want to be able to index it, since if you don't give it a value at compile-time, it's null (and you don't want to give it a value at compile-time, because then every default-initialized struct of that type will refer to the same dynamic array). Of course, you could always just append values, and the dynamic array will be allocated and grow accordingly, but that's obviously not the same as allocating it up front to have a specific length. - Jonathan M Davis Thank you Jonathan. A factory function seems to be what I need, then. It'll be an interesting challenge to have my transpiler detect when a factory function is needed, and making sure that they are called at the right places. But this might escalate since structs can have members that are structs that have a factory function. So the enclosing struct also needs a factory function. And so forth. My problem is the translation of so called schematic arrays, a type that I have only seen in Extended Pascal. A schematic array is a type in which the length of the array is a parameter of the type. Extended Pascal does not have dynamic arrays, so schematic arrays are its attempt at improving a bit on just plain static arrays. The length parameter can be constant, in which it behaves akin to templates (which it doesn't have either), but it can also be set at run time during initialization (so I can't translate it to a template). Maybe I can omit the translation of schematic arrays (IntegerArray in this case) altogether and instead detect where and how they are instantiated. Then replace them with a static array whenever the length is known at compile time, and a dynamic array otherwise. A static array is not nice, but at least they can be members of structs without a factory function. Either way, my transpiler needs to smarten up... Bastiaan.
Re: Unexpected aliasing
On Monday, 11 November 2019 at 20:05:11 UTC, Antonio Corbi wrote: Defining and using a constructor for WrapIntegerArray seems to work: void main() { import std.stdio; WrapIntegerArray arr1 = WrapIntegerArray(5); arr1[0] = 42; WrapIntegerArray arr2 = WrapIntegerArray(5); writeln(arr2[0]); // 42, not 0. writeln("arr1.wrap.arr.ptr = ", arr1.wrap.arr.ptr); writeln("arr2.wrap.arr.ptr = ", arr2.wrap.arr.ptr); // identical assert(arr2[0] == 0); // fails } struct IntegerArray { int[] arr; alias arr this; this(int l) { arr = new int[l]; } } struct WrapIntegerArray { this (int v) { wrap = IntegerArray(5); } IntegerArray wrap; alias wrap this; } Hope this helps. Antonio Thanks, Antonio. My problem is that the length of the array should be a built-in property of WrapIntegerArray (immutable in this case); what I'd actually want is a constructor without arguments. Jonathan's suggestion of using a factory function comes closest to that. Bastiaan.
Unexpected aliasing
Recently I got my first surprise with our use of D. The symptom was that two local variables in two different functions appeared to be sharing data. A simplified example is shown below (the original was machine translated from Pascal and involved templates and various levels of indirection). What I did not know is that the initial value of struct members is a compile time feature, apparently. What I suspect is happening is that the array lives in the static data segment (or is created in the module constructor?) and that the slices inside arr1 and arr2 get initialised to point to that same array. I could use some help in rewriting the code below so that arr1 and arr2 each have their own data; ideally with minimal changes so that I can make the transcompiler do the right thing. Thanks! Bastiaan. void main() { import std.stdio; WrapIntegerArray arr1; arr1[0] = 42; WrapIntegerArray arr2; writeln(arr2[0]); // 42, not 0. writeln("arr1.wrap.arr.ptr = ", arr1.wrap.arr.ptr); writeln("arr2.wrap.arr.ptr = ", arr2.wrap.arr.ptr); // identical assert(arr2[0] == 0); // fails } struct IntegerArray { int[] arr; alias arr this; this(int l) { arr = new int[l]; } } struct WrapIntegerArray { auto wrap = IntegerArray(5); // This is CTFE! :-( alias wrap this; }
Re: Saving and loading large data sets easily and efficiently
On Monday, 30 September 2019 at 20:10:21 UTC, Brett wrote: [...] The way the data is structured is that I have a master array of non-ptr structs. E.g., S[] Data; S*[] OtherStuff; then every pointer points to an element in to Data. I did not use int's as "pointers" for a specific non-relevant reason [...] I would seriously consider turning that around and work with indices primarily, then take the address of an indexed element whenever you do need a pointer for that specific non-relevant reason. It makes I/O trivial, and it is safer too. size_t[] OtherStuff; size_t[int] MoreStuff; Bastiaan.
Re: How to use #pragma omp parallel for collapse(n) in dlang?
On Tuesday, 13 August 2019 at 08:41:07 UTC, ijet wrote: How to use #pragma omp parallel for collapse(n) in dlang? I don’t understand the question. Bastiaan.
Re: 1 new
On Friday, 2 August 2019 at 18:25:28 UTC, jmh530 wrote: When I navigate to https://forum.dlang.org/ I have a message that says "1 new reply" to "your posts." Normally, I click on that "1 new reply" and find the post that's new, go to it, and the message disappears. However, it doesn't seem to go away anymore. I tried looking at many different old posts without luck. At one point it was up to "2 new replies," but I viewed that other post and it went back down to "1 new reply." Does anyone else have this? I always have “2 new replies” on that page, no matter how often I take a look. The feature seems a bit broken to me. Bastiaan.
Re: How to get name of my application (project)
On Saturday, 3 August 2019 at 09:26:03 UTC, Andrey wrote: Hello, how to get name of my application (project) that we write in dub.json? Is there any compile-time constant like __MODULE__? The name of an application is not a compile time constant: you can rename the executable at any time. Like Rémy said, thisExePath.baseName will get you the name at run time. Bastiaan.
Re: Help me decide D or C
On Friday, 2 August 2019 at 13:45:17 UTC, Alexandre wrote: On Friday, 2 August 2019 at 12:30:44 UTC, berni wrote: On Wednesday, 31 July 2019 at 18:38:02 UTC, Alexandre wrote: [...] In my oppinion C should have been deprecated about 50 years ago and it's not worth while to learn it if you are not interested in the history of programming or you have to learn it, because you need to maintain software which is allready written in C. But that's my oppinion; others may have a different sight. [...] Could you elaborate more about C being a burden? I have read so many people saying C gives a great foundation and should be everyone's first language. Now I am confused. One example is this recent post: https://forum.dlang.org/post/yjgkatpbkdyyksldg...@forum.dlang.org “[...] recently all the problems I am having with D are because D is actually superior to C and some assumptions I still have because of C should be uninstalled from my brain.” If you plan on ending up with D anyway, I think that learning C first is an unnecessary detour and can be counter productive in some ways. And if your objective is to have fun, I would recommend against C (except for a masochistic kind of fun). Don’t take the detour, take the D tour! :-) Bastiaan.
Re: Help me decide D or C
On Thursday, 1 August 2019 at 20:02:08 UTC, Aurélien Plazzotta wrote: [...] But don't fool yourself, D is not for beginners. Ali Çehreli is a very skilled programmer, ergo, he can't reason like a new/starting programmer anymore, regardless of his patience and kindness. I am sorry, but this is very strange reasoning. Would you recommend a book on programming written by someone who is not a skilled programmer himself in any language? I certainly would not. Besides, the OP has already expressed his appreciation for Ali’s writing. Bastiaan.
Re: 1 - 17 ms, 553 ╬╝s, and 1 hnsec
On Friday, 17 May 2019 at 18:36:00 UTC, ag0aep6g wrote: I'd suggest "17 ms, and 553.1µs" for a better default (1 hns is 0.1 µs, right?). No weird "hnsecs", no false precision, still all the data that is there. I was going to propose the same. Hns is weird. Bastiaan.
Re: Windows / redirect STDERR to see assert messages
On Sunday, 12 May 2019 at 13:39:15 UTC, Robert M. Münch wrote: When developing Windows GUI applications I use: // detach from console and attach to a new one, works for x86 and x86_64 FreeConsole(); AllocConsole(); freopen("CONIN$", "r", stdin); freopen("CONOUT$", "w", stdout); freopen("CONOUT$", "w", stderr); so that the GUI app opens a console for writeln() output etc. I assumed this should work for assert() messages as well. But it seems it doesn't. If an assert fails, I don't see any output. Is assert using something else? What's wrong about this approach? Are you sure the last call to freopen doesn't return NULL? You are opening the same file twice and I'm not sure that works. Test with `stderr.writeln("test")`. Bastiaan.
Re: CTFE in imported static initializers
On Monday, 13 May 2019 at 20:39:57 UTC, Steven Schveighoffer wrote: Why? I can't even use it at compile time... pragma(msg, moddata.length); Is that a good test or "usable at compile time", though? Isn't pragma(msg) done at an earlier stage than CTFE? I think that was the argument for ctfeWriteln. (We both know that I'm out of my league here, but anyway :)) Bastiaan.
Re: Compile time mapping
On Sunday, 12 May 2019 at 18:47:20 UTC, Bogdan wrote: On Sunday, 12 May 2019 at 17:53:56 UTC, Bastiaan Veelo wrote: If I understand your question correctly, you have two enums of equal length, and you want to convert members across enums according to their position, right? My question was very vague, sorry about that. In my use case I'd like to map SDL2 keyboard scan codes to my own game input keyboard codes. The two enums would look something like this: ``` enum SDL_Scancode { SDL_SCANCODE_UNKNOWN = 0, SDL_SCANCODE_A = 4, SDL_SCANCODE_B = 5, SDL_SCANCODE_C = 6, SDL_SCANCODE_D = 7, } enum MY_Scancode { KEY_A, KEY_B, KEY_C, KEY_D, } ``` The two enums are not of equal length, so in the end I just decided to create an immutable array of type My_Scancode[] where the index is an SDL_Scancode and the value is the corresponding MY_Scancode enum member. I'm ok with using some memory for this, as long as it's as fast as possible. If the only difference is the extra _UNKNOWN member, you can still use the static foreach approach. Just make it a non-template function and rip out the checks, and add a +1 in the right place.