Re: __gshared is "somewhat" transitive, isn't it ?
On Thursday, 16 May 2024 at 17:04:09 UTC, user1234 wrote: Given ```d struct S { int member; } __gshared S s; ``` It's clear that `s.member` is `__gshared` too, right ? What does happen for ```d struct S { int member; static int globalMember; } __gshared S s; ``` Is then `S.globalMember` a TLS variable ? (I'd expect that) `__gshared` is a storage class. It means, store this thing in the global memory segment. `static` storage class means store this thing in TLS. Storage classes are *not* transitive, and they are not type constructors. They optionally might apply a type constructor to the type (such as the `const` storage class), but not always. So in this case `typeof(s)` is `S`, not `__gshared S`. `s.member` is in the global segment since structs members are placed within the struct memory location (in this case, the global memory segment). `globalMember` is placed in TLS because it's storage class is `static`, and `static` means, do not store with the instance (which for `s` would mean the global memory segment), but rather in TLS. -Steve
Re: D doesn't have weak references. So how can I make a associative array of objects without preventing their destruction?
On Friday, 10 May 2024 at 11:05:28 UTC, Dukc wrote: This also gets inferred as `pure` - meaning that if you use it twice for the same `WeakRef`, the compiler may reuse the result of the first dereference for the second call, without checking whether the referred value has changed! This would be weak pure since the reference is mutable. This cannot be memoized. -Steve
Re: "in" operator gives a pointer result from a test against an Associative Array?
On Friday, 10 May 2024 at 01:00:09 UTC, Andy Valencia wrote: On Friday, 10 May 2024 at 00:40:01 UTC, Meta wrote: Yes. The reason for this is that it avoids having to essentially do the same check twice. If `in` returned a bool instead of a pointer, after checking for whether the element exists (which requires searching for the element in the associative array), you'd then have to actually *get* it from the array, which would require searching again. Returning a pointer to the element if it exists (or `null` if it doesn't) cuts this down to 1 operation. Looking at Programming in D section 28.5, I'm guessing that pointer versus null is treated as the appropriate boolean value when consumed by an "if" test. So that example is getting a pointer to a string, or null, but the example looks exactly as the same as if it had directly gotten a bool. Yes, we say that a type has "truthiness" if it can be used in a condition (`while`, `if`, `assert`, etc). For a pointer, `null` is considered "false", whereas any other value is considered "true". So you can use statements like `if(key in aa)` to test for membership. A very nice idiom is to check if a key is in an associative array, and if so, use the value that it maps to: ```d if(auto v = key in aa) { // use *v as the value here } ``` You can change your code to `return (e in this.members) !is null;` -Steve
Re: TIL: statically initializing an Associative Array
On Tuesday, 7 May 2024 at 00:10:27 UTC, Andy Valencia wrote: I had a set of default error messages to go with error code numbers, and did something along the lines of: string[uint] error_text = [ 400: "A message", 401: "A different message" ]; and got "expression is not a constant" I eventually found this discussion: https://issues.dlang.org/show_bug.cgi?id=6238 I understand that it's problematic, but a message which makes it clearer that compile-time initialization of global AA's are not supported? Because it cost me about a half hour trying to figure out what I was doing wrong. This error message was changed in 2.101.x (unsure which point release): ``` onlineapp.d(1): Error: static initializations of associative arrays is not allowed. onlineapp.d(1):associative arrays must be initialized at runtime: https://dlang.org/spec/hash-map.html#runtime_initialization ``` (My workaround was to initialize the data structure once during app startup.) This was fixed [in 2.106.0](https://dlang.org/changelog/2.106.0.html#dmd.static-assoc-array) please upgrade your compiler. -Steve
Re: How can I put the current value of a variable into a delegate?
On Monday, 6 May 2024 at 06:29:49 UTC, Liam McGillivray wrote: Delegates can be a pain, as they often have results different from what one would intuitively expect. This can easily result in bugs. Here's a line that caused a bug that took me awhile to find: ``` foreach(card; unitCards) card.submitted = delegate() => selectUnit(card.unit); ``` Each `UnitInfoCard` object (which `card` is a member of) contains a `Unit` object called `unit`. The intention of this line was that each object in `unitCards` would call `selectUnit` with it's own `unit` every time it calls `submitted`. Instead, every card calls `submitted` with the *last* value of `card`. Yes, this is because the foreach loop reuses the same memory slot for `card`. Even though this is allocated as a closure, it still only allocates the frame stack of the *enclosing function*, and does not allocate a new slot for each loop iteration. You can force this by using a lambda which allocates the closure: ```d foreach(card; unitCards) card.submitted = (c2) { return () => selectUnit(c2.unit); }(card); ``` This is a lambda which accepts `card` as a parameter, and returns an appropriate delegate. It is important to use a parameter, because if you just use card inside there, it's still using the single stack frame of the calling function! I renamed the inner parameter `c2` to avoid confusion, but you could name it `card` also. Essentially, the stack frame of the inner function is now allocated a closure, and it has it's own reference to `card` as a parameter. This is a very old issue: https://issues.dlang.org/show_bug.cgi?id=2043 since "moved" to https://issues.dlang.org/show_bug.cgi?id=23136 I would love to see a solution, but the workaround at least exists! -Steve
Re: Show dialog box for uncaught exception (Windows, lld-link)
On Sunday, 5 May 2024 at 14:55:20 UTC, SimonN wrote: My application is a graphical game. I close stdout and stderr by passing `-subsystem:windows` to `lld-link` to suppress the extra console window. For a few fatal errors (missing required resources, can't open display, ...), I throw exceptions, log them to logfile, then re-throw them to crash. I can tell Windows users to look in the logfile, but it would be more fitting on Windows to show an error dialog box in addition to the logging. ```d int realMain(string[] args) { // all your normal code goes here } int main(string[] args) { version(Windows) { try { realMain(args); } catch(Exception e) { visualDisplayOfException(e); throw e; } } else { // presumably, non-windows systems shouldn't show a graphical Exception // trace? realMain(args); } } ``` -Steve
Re: Phobos function to remove all occurances from dynamic array?
On Wednesday, 1 May 2024 at 01:09:33 UTC, Liam McGillivray wrote: This is presumably such a common task that I'm surprised it isn't easy to find the answer by searching; Is there a standard library function that removes all elements from a dynamic array that matches an input argument? In `std.array` there's the `replace` function which is supposed to replace all occurrences that match an input with another. It seems to work as described on strings, but I get compiler errors when using it on other array types. I've tried using it to replace occurrences of a certain object in an array with `[]` in order to remove all occurrences, but it's not allowed. Is there a Phobos function that does what I want? It would be crazy if there isn't. `remove` https://dlang.org/phobos/std_algorithm_mutation.html#remove ```d arr = arr.remove!(v => shouldBeRemoved(v)); ``` Why the reassignment? Because `remove` removes elements *in place*, and does not change the range extents. It returns the portion of the range that contains the unremoved elements. So to give an example: ```d auto arr = [1, 2, 3, 4, 5]; auto result = arr.remove!(i => i % 2 == 1); // remove odd elements assert(result == [2, 4]); // first 2 are the slice that is stored in result // the last three are leftovers. assert(arr == [2, 4, 3, 4, 5]); ``` -Steve
Re: Adapting foreign iterators to D ranges
On Monday, 22 April 2024 at 11:36:43 UTC, Chloé wrote: The first implementation has the advantage is being simpler and empty being const, but has the downside that next is called even if the range ends up not being used. Is either approach used consistently across the D ecosystem? I always go for the simplest approach. So that means, pre-fill in the constructor. Yes, the downside is, if you don't use it, then the iterator has moved, but the range hasn't. But returning to the iterator after using the range is always a dicey proposition anyway. The huge benefit is that all the functions become simple and straightforward. But there is no "right" approach. And using composition, you may be able to achieve all approaches with wrappers. Phobos does various things depending on what people thought was good at the time. It sometimes causes some very unexpected behavior. I recommend always using the same approach for the same library, that way your users know what to expect! -Steve
Re: Statically compiled binary with C interop crashes.
On Thursday, 18 April 2024 at 11:05:07 UTC, yabobay wrote: On Wednesday, 17 April 2024 at 15:24:07 UTC, Ferhat Kurtulmuş wrote: On Wednesday, 17 April 2024 at 11:03:22 UTC, yabobay wrote: I'm using [dray](https://code.dlang.org/packages/dray) in my project with dub, here's the relevant parts of the dub.json: [...] İt seems your issue is related to the raylib itself, neither the binding you use nor the d programming language. İnstalling x11 development package may resolve the issue. I have the equivalent package installed both on the build machine and the machine i tried to run the code on. Also, no i shouldn't. It's supposed to be a statically linked binary libglfw, which is embedded statically in raylib, is trying to dynamically open libx11. https://github.com/raysan5/raylib/blob/c1fd98591d7996dd45a5ce9ecbb4b571607d417b/src/external/glfw/src/x11_init.c#L1269 So what it appears to be is, glfw tries to open a specified libx11, and fails, and then the program errors and exits. The library selected is determined by a compiler directive (see above that line), you may have to rebuild raylib with the right directive based on what libx11 you have on the system. Note, these are not *dynamically linked* libraries, but *dynamically loaded* libraries. That is, the system linker ldd is not pre-loading the library, raylib is finding the library and loading it at runtime. -Steve
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Sunday, 14 April 2024 at 22:36:18 UTC, Liam McGillivray wrote: On Friday, 12 April 2024 at 15:24:38 UTC, Steven Schveighoffer wrote: ```d void InitWindow(int width, int height, ref string title) { InitWindow(width, height, cast(const(char)*)title); } ``` This is invalid, a string may not be zero-terminated. You can't just cast. Well, it did work when I tried it (using a string variable, not a literal of course). It displayed as it is supposed to. A cast "working" isn't enough. It could work in certain cases, with certain environmental conditions, etc., but fail horribly with memory corruption in other cases. It could even happen on different runs of the program. It could happen that it works 99.999% of the time. The risk is not worth it. But from the information I can find on the web it looks like strings are sometimes but not `always` zero-terminated. Not a great look for the language. Are there any rules to determine when it is and when it isn't (for string variables)? string literals are zero-terminated. All other strings are not. If you have a string generated at compile time, the chances are good it has zero termination. However, the implicit conversion to `char *` is the clue that it is zero terminated. If that doesn't happen automatically, it's not guaranteed to be zero terminated. A string generated at runtime only has zero termination if you add a 0. You should not cast to a pointer assuming the zero is going to be there. Casting is a blunt instrument, which does not validate what you are doing is sound. A cast says "compiler, I know what I'm doing here, let me do this even though it's outside the language rules". So there are a few things to consider: 1. Is the string *transiently used*. That is, does the function just quickly use the string and never refers to it again? Given that this is raylib, the source is pretty readable, so you should be able to figure this out. I suppose. But if it turns out that the string is used continuously (as I assume to be the case with `InitWindow` and `SetWindowTitle`) and it doesn't make a copy of it, I imagine it would be difficult to design the function overload, as it would need to store a copy of the string somewhere. In that case, the only clean solution would be to have a global array of strings to store everything that's been passed to such functions, but that doesn't feel like a very satisfying solution. I may take a look inside some Raylib functions if I get back to this task. You can pin memory in the GC to ensure it's not collected by using `core.memory.GC.addRoot`, which is effectively "storing in a global array". 2. If 1 is false, will it be saved in memory that is scannable by the GC? This is one of the most pernicious issues with using C libraries from D. In this case, you will need to either allocate the memory with C `malloc` or pin the GC memory. You mean that the GC can destroy objects that still have references from the C code? Yes. If the GC is unaware of the memory that is being used by the C code, it can't scan that code for pointers. It may collect these strings early. For transiently used strings, I would point you at the function [`tempCString`](https://github.com/dlang/phobos/blob/0663564600edb3cce6e0925599ebe8a6da8c20fd/std/internal/cstring.d#L77), which allocates a temporary C string using malloc or a stack buffer, and then frees it when done with it. Thank you. In a previous thread, someone told me that having to do many deallocations slows down the program, and the GC is more efficient because it deallocates many objects simultaneously. Is this something worth considering here, or is the overhead going to be tiny even when it's called a few times per frame? In an *application*, I would recommend not worrying about the allocation performance until it becomes an issue. I'm writing a simple game, and never have worried about GC performance. When you do need to worry, you can employ strategies like preallocating all things that need allocation (still with the GC). In a *general library*, you do have to worry about the requirements of your users. If you can allocate locally (on the stack), this is the most efficient option. This is what `tempCString` does (with a fallback to `malloc` when the string gets to be large). The obvious problem in all this is to avoid accepting string literals (which are magic and automatically convert to const char *). This is currently impossible with function overloading, and so you need a separate function name, or put them in a different module. Aren't there any compile-time conditions for this? Unfortunately no. `string` does not implicitly convert to `char *` unless it is a string literal, and string literals bind to `string` before `char *`. So you can't rely on the overload working. -Steve
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Friday, 12 April 2024 at 00:04:48 UTC, Liam McGillivray wrote: Here's what I wanted to do. In the library I'm working on, there are various declarations for functions defined in an external C library following the line `extern (C) @nogc nothrow:`. Here are some examples of such declarations which have a `const(char)*` parameter: ```d void InitWindow(int width, int height, const(char)* title); void SetWindowTitle(const(char)* title); Shader LoadShader(const(char)* vsFileName, const(char)* fsFileName); ``` I wanted to generate definitions of overloads of these functions using strings as parameters instead of `const(char)*`. For the `InitWindow` function shown above, the overload should be defined like this: ```d void InitWindow(int width, int height, ref string title) { InitWindow(width, height, cast(const(char)*)title); } ``` This is invalid, a string may not be zero-terminated. You can't just cast. or alternatively, like the following: ```d void InitWindow(int width, int height, string title) { InitWindow(width, height, title.toStringz); } ``` This will allocate from the GC. So there are a few things to consider: 1. Is the string *transiently used*. That is, does the function just quickly use the string and never refers to it again? Given that this is raylib, the source is pretty readable, so you should be able to figure this out. 2. If 1 is false, will it be saved in memory that is scannable by the GC? This is one of the most pernicious issues with using C libraries from D. In this case, you will need to either allocate the memory with C `malloc` or pin the GC memory. For transiently used strings, I would point you at the function [`tempCString`](https://github.com/dlang/phobos/blob/0663564600edb3cce6e0925599ebe8a6da8c20fd/std/internal/cstring.d#L77), which allocates a temporary C string using malloc or a stack buffer, and then frees it when done with it. The obvious problem in all this is to avoid accepting string literals (which are magic and automatically convert to const char *). This is currently impossible with function overloading, and so you need a separate function name, or put them in a different module. -Steve
Re: How can I tell D that function args are @nogc etc.
On Friday, 12 April 2024 at 03:57:40 UTC, John Dougan wrote: What is the procedure for bug reporting? I'm looking at the issues tracker and have no clue how to drive the search to see if this is already there. https://issues.dlang.org While entering the bug title, it does a fuzzy search for existing open and closed issues. -Steve
Re: How can I tell D that function args are @nogc etc.
On Thursday, 11 April 2024 at 03:17:36 UTC, John Dougan wrote: Interesting. Thank you to both of you. On Wednesday, 10 April 2024 at 17:38:21 UTC, Steven Schveighoffer wrote: On Wednesday, 10 April 2024 at 11:34:06 UTC, Richard (Rikki) Andrew Cattermole wrote: Place your attributes on the right hand side of the function, not the left side. Use the left side for attributes/type qualifiers that go on the return type. Just a word of warning, this explanation suggests putting qualifiers on the left side would affect the return type, this is not the case. So in my example, what did I actually tell the compiler with the placement of the attributes? And how was it different between the function type alias declaration, and the actual function declaration? More specifically, what are the semantic differences below? ```d alias FnPrefixT = @nogc nothrow @safe bool function(int); // Versus alias FnSuffixT = bool function(int) @nogc nothrow @safe; ``` So D can provide a nice mechanism to show what is happening -- `pragma(msg, ...)` If I do that with the two types above I see something *very* interesting: ```d pragma(msg, FnPrefixT); pragma(msg, FnSuffixT); ``` ``` bool function(int) nothrow @nogc bool function(int) nothrow @nogc @safe ``` That surprises me. `nothrow` and `@nogc` go onto the type, but not `@safe` if put before the declaration? I have no idea why. All I can think of is that it is a bug. and ```d @nogc nothrow @safe bool fnPrefix(int) { stuff } // Versus bool fnSuffix(int) @nogc nothrow @safe { stuff } ``` ```d pragma(msg, typeof(fnPrefix)); pragma(msg, typeof(fnSuffix)); ``` ``` nothrow @nogc @safe bool(int) nothrow @nogc @safe bool(int) ``` (as expected) -Steve
Re: mmap file performance
On Thursday, 11 April 2024 at 00:24:44 UTC, Andy Valencia wrote: I wrote a "count newlines" based on mapped files. It used about twice the CPU of the version which just read 1 meg at a time. I thought something was amiss (needless slice indirection or something), so I wrote the code in C. It had the same CPU usage as the D version. So...mapped files, not so much. Not D's fault. And writing it in C made me realize how much easier it is to code in D! For a repeatable comparison, you should provide the code which does 1MB reads. I have found that mmapped files are faster than reading buffered files, but maybe only for large files? -Steve
Re: "Error: `TypeInfo` cannot be used with -betterC" on a CTFE function
On Tuesday, 9 April 2024 at 23:50:36 UTC, Richard (Rikki) Andrew Cattermole wrote: On 10/04/2024 11:21 AM, Liam McGillivray wrote: On Sunday, 7 April 2024 at 08:59:55 UTC, Richard (Rikki) Andrew Cattermole wrote: Unfortunately runtime and CTFE are the same target in the compiler. So that function is being used for both, and hence uses GC (appending). Are you sure that string appending was really the problem that caused the "TypeInfo" build error? I forgot about this, but I had already had a working CTFE function with string appending before adding the new one that lead to this error. The symbols that it generates could be used in the program compiled with `betterC`. No, for a string it shouldn't trigger the need for TypeInfo. But that wouldn't have worked regardless. Array appending calls a runtime function which accepts `TypeInfo` (In this case, `TypeInfoGeneric!char`). So this does indeed involve `TypeInfo`. But also, even if `TypeInfo` weren't involved, it also needs the GC which is unavailable with betterC. It's just that the `TypeInfo` error happens first. The move to use templates instead of `TypeInfo` is slowly happening. -Steve
Re: How can I tell D that function args are @nogc etc.
On Wednesday, 10 April 2024 at 11:34:06 UTC, Richard (Rikki) Andrew Cattermole wrote: Place your attributes on the right hand side of the function, not the left side. Use the left side for attributes/type qualifiers that go on the return type. Just a word of warning, this explanation suggests putting qualifiers on the left side would affect the return type, this is not the case. Attributes apply to the *declaration*. In some cases this effectively applies to the return type, in some cases it applies to the function, in some cases it applies to the context pointer. In order to apply type constructors to the return type, you need to use parentheses: ```d const int foo(); // const applies to the context pointer of `foo`, not `int` const(int) bar(); // const applies to `int` return type ref int baz(); // ref applies to `baz`, which in turn means "ref returning function" ``` Where this becomes tricky is return types that are function pointers/delegates. Then using the right side of the function/delegate *type* is the only way. ```d @safe void function() foo(); // `foo` is safe, the function pointer it returns is not void function() @safe bar(); // `bar` is not safe, the function pointer returned is void function() @safe baz() @safe; // both are safe ``` -Steve
Re: Boneheaded question regarding compilation...
On Monday, 1 April 2024 at 21:23:50 UTC, WhatMeWorry wrote: Huge fan of Mike Shah's YouTube videos regarding D and his latest for D conference: https://mshah.io/conf/24/DConf%20%20Online%202024%20_%20The%20Case%20for%20Graphics%20Programming%20in%20Dlang.pdf So I installed github desktop app and cloned his Talks repo. There is a build command commented out at the top of the main.d file which I've been trying to compile, via the command line: C:\Users\kheas\Documents\Talks\2024\dconf_online\hello_triangle>dmd -g -J. main.d ./glad/gl/*.d -L-L/usr/local/lib -L-lglfw3 -of=prog && ./prog Error: cannot find input file `.\glad\gl\*.d` import path[0] = C:\D\dmd2\windows\bin64\..\..\src\phobos import path[1] = C:\D\dmd2\windows\bin64\..\..\src\druntime\import I'm using a Windows 11 machine so I thought that maybe the syntax was for Linux environment. But replacing all the '/' with '\\' did not work. Those are indeed Linux parameters and not windows compatible. This can’t be fixed by switching slash styles. You need the appropriate libs and the appropriate linker switches. -Steve
Re: Limits of implicit conversion of class arrays
On Monday, 25 March 2024 at 07:16:35 UTC, Per Nordlöw wrote: On Saturday, 23 March 2024 at 11:04:04 UTC, Dmitry Olshansky wrote: The first and second is unsound (infamously allowed in Java). In the general case, yes. But, do you see any errors with the code ```d class Base {} class Derived : Base {} @safe pure nothrow unittest { Base b; Derived d; b = d; // pass Base[] bs; Derived[] ds; bs ~= ds; // pass bs = ds; // fail [1], should pass bs = cast(Base[])ds; // fail [2], should pass } ``` Yes, it's unsafe, as you can replace an element of `ds` with something that has no relation to `Derived`. Once you cast the slice you can populate it with Derived2 objects that are not Derived, hence breaking type safety of the ds slice. Again, in the general case, yes. So what is different in this code example compared to the general case? Hint: this has overlaps with a missing compiler optimization in dmd (and many other statically typed languages) enabled by a specific kind of data flow analysis. Which one? If there is a way to end up with a `Derived` reference to point at something that is not a `Derived` *without a cast* in system code, or *even with a cast* in safe code, then it is an error. It doesn't matter if you aren't actually doing it. If you know you are not making that mistake, change it to system, and cast to inform the compiler that you "know what you are doing". -Steve
Re: Unittests pass, and then an invalid memory operation happens after?
On Wednesday, 27 March 2024 at 21:43:48 UTC, Liam McGillivray wrote: In my current [game project](https://github.com/LiamM32/Open_Emblem), [something strange](https://github.com/LiamM32/Open_Emblem/issues/20) has happened as of a recent commit. When running `dub test`, all the unittests appear to pass, but then after the last unittest has concluded an "Invalid memory operation" happens. Removing a few lines replaces this error with a segfault, but either way, these errors shouldn't be happening. Weirdly, the commit where these errors first appear did nothing but replace a single class-member function with a seemingly identical function through a mixin template. The errors seem to be related to object deletion. The traceback output for the first error, and where GDB points to for the second error, is the destructor for my `Unit` class. You see, every `Unit` object is associated with a particular `Map` object and `Faction` object, which it hold references to. Those objects in turn each have an array of `Unit` objects that they are associated with. In the `Unit` destructor, I have it call the `removeUnit` function in both the associated `Map` and `Faction` objects. The errors are happening in either the `Unit` destructor itself, or the `removeUnit` function that it calls. Until the commit that introduced these errors, the `removeUnit` function was written directly in the `Map` class in it's module, but this commit replaced it with the mixin template `UnitArrayManagement`, which `Faction` also uses. `Unit` destructor: ``` ~this() { this.alive = false; if (this.map !is null) this.map.removeUnit(this); if (this.faction !is null) this.faction.removeUnit(this); if (this.currentTile !is null) this.currentTile.occupant = null; } ``` The GC does not guarantee destructor order. So this code is not valid -- e.g. you can't count on `map` to be a valid object at this point. In my estimation, the code is not correct in principle anyway -- if the `map` has a pointer to the `unit`, then neither will be collected without both being garbage, and so there is no need to do these calls (they are all going away presently). The *only* thing you should be doing in a destructor is freeing non-GC resources. I read that the garbage collector *sometimes* but not *always* calls destructors on deletion, which sounds crazy to me. The GC is not guaranteed to delete memory or run destructors. In the current implementation, it will destroy everything at the end of the program that was allocated using the GC, but the language does not guarantee this. The second error, which can be achieved by removing the instances of `writeln` in `removeUnit` (making it seemingly identical now to the version of this function previously defined in the `Map` class) is also strange. It seems to be a case of the `Unit` object calling a `Map` object that no longer exists. However, that's also strange, as the `Map` object is supposed to delete all it's associated units on destruction. As mentioned, GCs do not work this way -- you do not need to worry about cascading removal of anything. You should assume in the destructor that all references in the type that were pointing at GC blocks are now invalid (i.e. dangling pointers). So why are these things even happening *after* the unittests have been run? What else do I need to know about object destruction? What may be happening? The GC is cleaning up all allocated memory, in *no particular order*. -Steve
Re: Reworking the control flow for my tactical role-playing game
On Sunday, 17 March 2024 at 00:14:55 UTC, Liam McGillivray wrote: As many of you know, I have been trying to write a tactical role-playing game (a mix of turn-based stategy & RPG) in D. This is the furthest I have ever gotten in making an interactive program from the main function up. Right now, it is not yet playable as a game, but you can interact with it and get a rough idea of what I'm going for. Feel free to download and run it to see what I have so far. https://github.com/LiamM32/Open_Emblem I got it to run on my mac, I had to do a few updates to the dub.sdl file, but it did work, though I couldn't figure out how to make attacks work. ## The Current Structure: The code for Open Emblem (name subject to change) is split between a source library, which handles the internal game logic, and a graphical front-end program which uses that library, but makes it usable. This is kind of cool, I like the idea! ### The Library: All sounds good ### The Raylib Front-end: After looking at many libraries and taking a shot at [ae](https://github.com/CyberShadow/ae) & [godot-D](https://github.com/godot-d/godot-d) but not really figuring it out, I was recommended [raylib-d](https://github.com/schveiguy/raylib-d), a binding for [raylib](https://www.raylib.com/) by @Steven Schveighoffer. Raylib is a rather simple graphical library written in C. I ended up sticking with it because the website has so many easy-to-follow examples that make it easy as my first graphical library. They're written in, but I adapted them to D rather easily. Of course, being written in C has limitations as it isn't object-oriented. This is front-end is in the [`oe-raylib/`](https://github.com/LiamM32/Open_Emblem/tree/master/oe-raylib) directory. For this front-end, I've made the classes `VisibleTile` and `VisibleUnit`, which inherit `Tile` & `Unit`, but add sprite data and other graphics-related functionality. I then have the `Mission` class which inherits the `MapTemp` class. This class dominates the program flow in it's current state. It handles loading data from JSON files, switching between different game phases and does most of the function calls related to rendering and input. The way I have it currently, there's a `startPreparation` function and `playerTurn` function, each of which run a once-per-frame loop that renders all the necessary objects and takes user input. They each have a rather messy set of if-statements for the UI system. Any UI elements that may pop-up are declared before the loop begins, with if-statements to determine whether they should be visible this frame. For UI elements, I currently have `version` flags for either `customgui` (which I started writing before discovering raygui) and `customgui`, which you can select between using `dub --config=`. Having both makes the code messier, but I haven't yet decided on which I prefer. They are both currently achieve equivalent functionality. Everything here is single-threaded. Despite that, I still get thousands of frames-per-second when disabling the cap on framerate. Note that disabling the cap on framerate just avoids the sleep-per-frame that raylib does. I always recommend setting a cap of something like 60 unless you are going to use vsync. To get a glimpse of a flaw with the current approach (which may be simpler to fix with an overhaul), try asking one of the units to move during your turn, but then try moving the other unit while the first one hasn't reached their destination. The first unit will stop. So when doing video game development with a main loop that needs to refresh the screen every frame, you need to componentize long-running operations into frame-size bits. So for instance, an animation that needs to move an object from A to B, should be captured into a temporary item (class object, struct, member of the sprite, etc), where you tell it every time you are drawing a frame (or even better yet, each game tick), and let it make the changes necessary for one tick of time. For instance, build an object that takes start position, end position, time to animate, and maybe a path function (like linear, ease-in/ease-out, etc), and then each frame calculates where the position should be based on the current time vs. the start time. Encapsulating all this into an object makes things easy to deal with. Then you just need to call it every frame/tick. ## Should I rework things? So now I am thinking of reworking the rendering system, but also changing some of my approach to how the Open Emblem library works. I've been thinking of adopting an event-driven approach, using signals and slots, for both the library and the front-end (and between the two). I'm curious if more experienced programmers think this is the right approach. I'm not sure if you want to do event driven here. It's a possibility. But I find a game-tick system, where each tick, you update each object
Re: Disable wrilten buf in docker
On Tuesday, 12 March 2024 at 06:36:09 UTC, zoujiaqing wrote: Hi, my application use writeln in docker don't display. Python add -u disable it. https://stackoverflow.com/questions/29663459/why-doesnt-python-app-print-anything-when-run-in-a-detached-docker-container Use setvbuf to switch to line buffering. Then you don’t have to manually flush everything https://en.cppreference.com/w/c/io/setvbuf -Steve
Re: New update fix
On Saturday, 2 March 2024 at 09:18:58 UTC, user1234 wrote: On Saturday, 2 March 2024 at 08:41:40 UTC, Salih Dincer wrote: SLM, What exactly did this patch with the new update fix? Nothing, it looks like what happened is that the issue was wrongly referenced by a dlang.org PR (https://github.com/dlang/dlang.org/pull/3701/commits/4e8db30f0bf3c330c3431e83fe8a75f843b40857). Not wrongly referenced. The pr changed the spec to be clearer about the behavior. The behavior did not change. The bug was closed as “fixed” incorrectly. I switched it to “wontfix” The change log generator must have picked it up because of that. -Steve
Re: Error when using `import`.
On Monday, 26 February 2024 at 23:27:49 UTC, Liam McGillivray wrote: I don't know whether I should continue this topic or start a new one now that the problem mentioned in the title is fixed. I have now uploaded some of the code to [a GitHub repository](https://github.com/LiamM32/Open_Emblem). To make this game usable, I will need a library for graphics and input. I don't have any experience with making GUI programs aside from a little bit with Qt and C++. If you are going for game development, I would recommend raylib-d (https://code.dlang.org/packages/raylib-d), which is my wrapper around the very good raylib library. For doing GUI, raygui is supported, but I also can say I've seen some good things from fluid: https://code.dlang.org/packages/fluid -Steve
Re: Error when using `import`.
On Monday, 26 February 2024 at 22:40:49 UTC, Liam McGillivray wrote: On Sunday, 25 February 2024 at 03:23:03 UTC, Paul Backus wrote: You can't give a class the same name as the file it's in. If you do, then when you try to use it from another file, the compiler will get confused and think you're referring to the file instead of the class (that's what "import is used as a type" means). Thank you. In PHP, I was told to put every class definition in a file of the same name (whether I like it or not). However, I actually now have it working *without* having done that. Both the file name and the class name are capitalized, and it's working. However, maybe that's because they each start with a `module` line that makes the module name lowercase. I will keep this in mind, and maybe rename the files. So D is weird about this. I always recommend you use a *package* (i.e. module foo.bar) instead of just a module (i.e. module bar). When you omit the module declaration, the compiler assumes the module name is the same as the file name *without the path taken into account*. What happens is if you have `Map` as a module, and then `Map` as the class name, using the name `Map` is going to be confusing (did you mean the module or the class?) However, if you have everything under a package, for example `foo`, i.e. a file `foo/Map.d` which contains the `Map` class, then when referring to `Map`, it can't be referring to the module, since you would have to refer to `foo.Map` for that. This means the class name `Map` by itself is unambiguous. A whole host of problems occurs with name lookup when you don't use packages. -Steve
Re: The difference between the dates in years
On Saturday, 10 February 2024 at 15:53:09 UTC, Alexander Zhirov wrote: Is it possible to calculate the difference between dates in years using regular means? Something like that ``` writeln(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1))); ``` At the same time, keep in mind that the month and day matter, because the difference between the year, taking into account the month that has not come, will be less. My abilities are not yet enough to figure it out more elegantly. OK, so I thought this was already taking into account the day of the month. This is what I came up with: ```d int diffMonthNew(Date d1, Date d2) { auto diff = d1.diffMonths(d2); if(diff > 0) return diff + (d1.day < d2.day ? -1 : 0); else if(diff < 0) return diff + (d1.day > d2.day ? 1 : 0); return 0; } ``` Then if you want the years, it would be `diffMonthNew(d1, d2) / 12` -Steve
Re: The difference between the dates in years
On Saturday, 10 February 2024 at 23:48:56 UTC, Jonathan M Davis wrote: If I understand correctly, he cares about how far into the month the dates are, whereas diffMonths ignores the smaller units, meaning that you get the same result no matter when in the month the dates are. So, 2000-05-10 - 1990-05-09 would give 10, whereas 2000-05-10 - 1990-05-30 would give 9. diffMonths / 12 would give 10 in both cases. I thought `diffMonths` was actually already taking this into account... Looking at the impl, it's pretty simple. Would it make sense to have an overload that takes into account the day as well as the month/year? This kind of stuff is sometimes tricky to get right. -Steve
Re: The difference between the dates in years
On Saturday, 10 February 2024 at 15:53:09 UTC, Alexander Zhirov wrote: Is it possible to calculate the difference between dates in years using regular means? Something like that ``` writeln(Date(1999, 3, 1).diffMonths(Date(1999, 1, 1))); ``` At the same time, keep in mind that the month and day matter, because the difference between the year, taking into account the month that has not come, will be less. My abilities are not yet enough to figure it out more elegantly. Maybe I'm not understanding the question, but why not that result / 12? -Steve
Re: How to get the client's MAC address in Vibe
On Wednesday, 7 February 2024 at 22:16:54 UTC, Alexander Zhirov wrote: Is there a way to identify a client by MAC address when using the Vibe library? The `NetworkAddress` [structure](https://vibed.org/api/vibe.core.net/NetworkAddress) does not provide such features. Or did I miss something? Mac is a hardware address. By the time the packets get to your server, that info is long gone. Even if you could get it, it likely is the MAC address of your router, not the peer. -Steve
Re: Scripting with Variant from std.variant: parameter passing
On Friday, 2 February 2024 at 08:22:42 UTC, Carl Sturtivant wrote: It seems I cannot pass e.g. an int argument to a Variant function parameter. What's the simplest way to work around this restriction? You'd have to implement the function that accepts the parameters and wraps in a Variant. This is the best I can come up with, which should be copy/pasteable to other shims: ```d void foo(Variant x, Variant y) { ... } import std.meta : allSatisfy; enum isVariant(T) = is(T == Variant); // this is going to suck at CTFE but... string argsAsVariants(size_t count) { import std.format; import std.range; import std.alglorithm; import std.array; return iota(count).map!(i => format("Variant(args[%s])", i).join(","); } // shim auto foo(Args...)(Args args) if (!allSatisfy!(isVariant, Args)) { mixin("return foo(", argsAsVariants(args.length), ");"); } ``` -Steve
Re: import locality with function parameters
On Friday, 2 February 2024 at 00:29:51 UTC, Carl Sturtivant wrote: Hello, I seem to recall that there is surprising template to import a module and get a type from it inside the declaration of the type of a parameter to a function, so that the module need not be imported outside of the function definition. I think there was a blog article some years ago about this where there was some indication that this or something with equivalent effect would be incorporated into D in some way. How do I define a function with a parameter that is a type in an outside module while keeping module import local to that definition? Are you thinking of this? https://dlang.org/phobos/object.html#.imported -Steve
Re: Effective String to Date conversion?
On Monday, 22 January 2024 at 10:56:04 UTC, atzensepp wrote: Dear D-gurus, being new to D I am trying my first steps and the language is quite intuitive and appealing. When reading a file and creating a hash for the reocrds I want to get only the most recent ones. For this I need to convert Date/Time-Strings to comparable DateTime-Objects. The code below works but looks a bit clumsy. Is there a more efficient (shorter) way to accomplish this? That's how I would do it also. I would note there also is a library I've used which works pretty well: https://code.dlang.org/packages/dateparser -Steve
Re: Safety is not what you think
On Tuesday, 30 January 2024 at 15:38:26 UTC, Paul Backus wrote: This definitely isn't allowed in C or C++. I wonder what the rationale is for having this behavior in D? It isn't allowed in C, but allowed in C++ https://godbolt.org/z/9xTPhsb5G As for rationale... I don't know why it wouldn't be allowed? You clearly need an lvalue to use prefix ++, and the result is the value after adding one, so why can't it be bound to a reference? I don't see where the problem would arise. -Steve
Re: Accessing array elements with a pointer-to-array
On Friday, 26 January 2024 at 11:38:39 UTC, Stephen Tashiro wrote: On Thursday, 25 January 2024 at 20:36:49 UTC, Kagamin wrote: On Thursday, 25 January 2024 at 20:11:05 UTC, Stephen Tashiro wrote: void main() { ulong [3][2] static_array = [ [0,1,2],[3,4,5] ]; static_array[2][1] = 6; } The static array has length 2, so index 2 is out of bounds, must be 0 or 1. I understand that the index 2 is out of bounds in an array of 2 things. I'm confused about the notation for multidimensional arrays. I thought that the notation uint[m][n] is read from right to left, so it denotes n arrays of m things in each array. So I expected that static_array[k][j] would denotes the kth element of the jth array. I find the following rule very straightforward to explaining it. If you have an array, it's of type `T[]`. The `T` represents the type of each element. When you access element with index `n` of this array, it's `arr[n]`, which gives you the `n+1`th `T` element in the array. So how do you match this to a static array `ulong[3][2]`? Well, the `T` in this case is `ulong[3]`, and the array part is `[2]`. So this is an array of 2 `ulong[3]`. Therefore, when you index such an array, `static_array[2]` will get the 3rd element of this 2-element array, and fail. -Steve
Re: Providing implicit conversion of
On Sunday, 21 January 2024 at 16:05:40 UTC, Gavin Gray wrote: The following code: ulong charlie = 11; long johnstone = std.algorithm.comparison.max(0, -charlie); writeln(format!"johnstone %s"(johnstone)); Results in (without any warning(s)): johnstone -11 However you choose to look at it, this means -11 > 0 (regardless of all arguments concerning implicit conversions, 1's and 2's complements, being efficient, etc). The language should not allow unary unsigned anything. This is unlikely to get fixed, just due to the nature of D's philosophy when it comes to C compatibility. It would also break a lot of existing code. -Steve
Re: Delegates and values captured inside loops
On Sunday, 21 January 2024 at 14:52:45 UTC, Renato wrote: On Saturday, 20 January 2024 at 16:53:12 UTC, ryuukk_ wrote: This is the workaround according to: https://issues.dlang.org/show_bug.cgi?id=21929#c9 Go used to have the same issue [but they fixed it](https://go.dev/blog/loopvar-preview) so this is no longer a problem in Go. Perhaps D could do something about it for the same reasons the Go blog post presented. Actually, D is much worse. It appears in that post that local variables in the loop were scoped on the loop iteration, but just not the iteration variables themselves. This means, the machinery to properly capture the loop variables was trivial, just change the scope where those variables are allocated. In D, there is no loop scope. So the compiler would have to establish a new mechanism to recognize which variables to stick into a closure. It's not impossible, but it is not the same scope as what Go had to do. -Steve
Re: vector crash
On Thursday, 18 January 2024 at 03:07:13 UTC, zjh wrote: ```d import dparse.ast; import dparse.lexer; import dparse.parser : parseModule; import dparse.rollback_allocator : RollbackAllocator; import core.stdcpp.vector; import core.stdcpp.string; ... ``` I have no experience with using cpp from D, and I'm not sure exactly what you are trying to do (your code is not complete), but using `string` in this context does not mean C++ std::string, it's a D string (`immutable(char)[]`). Are you sure this is what you are wanting to do? -Steve
Re: `static` function ... cannot access variable in frame of ...
On Monday, 15 January 2024 at 22:23:27 UTC, Bastiaan Veelo wrote: 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. 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. -Steve
Re: Socket handle leak and active handle warning with Vibe-D
On Monday, 15 January 2024 at 18:40:00 UTC, bomat wrote: Sorry, I probably should have mentioned I was on Windows. For testing it under Linux I commented out the call to `connectMongoDB`, since I don't have it installed there - and the warning went away. Interesting, I did not suspect that as the source of the problem at all. :P I'm now looking into how to clean up MongoDB connections properly, but don't see anything besides `cleanupConnections()` (which I'm already calling without any effect). Maybe I need to initialize it differently... I'll experiment a bit. You may have to do the same thing I did with redis: https://github.com/vibe-d/vibe.d/pull/2372 Good luck! I would also say, I don't know why Windows doesn't do the same trace info debug thing, except that probably whomever added it didn't care about windows. -Steve
Re: Socket handle leak and active handle warning with Vibe-D
On Monday, 15 January 2024 at 17:24:40 UTC, bomat wrote: On Sunday, 14 January 2024 at 20:36:44 UTC, Steven Schveighoffer wrote: There should be a version you can enable that tells you where that socket handle was allocated. That might give you a further clue as to why it's not closed when the system shuts down. I think the program tells you which version to enable when this happens, but if not, let me know and I'll find it. Thanks for the response, Steve. Hmmm, not sure if I'm missing something, but this is all the output I get from the program: ``` [main() INF] Listening for requests on http://[::1]:8080/ [main() INF] Listening for requests on http://127.0.0.1:8080/ [() INF] Received signal 2. Shutting down. [main() INF] Stopped to listen for HTTP requests on ::1:8080 [main( ) INF] Stopped to listen for HTTP requests on 127.0.0.1:8080 Warning: 1 socket handles leaked at driver shutdown. Warning: 1 socket handles leaked at driver shutdown. ``` Unless there's some switch to make it more verbose? Which driver are you using? In the posix driver, it should mention (and use) the debug flag `EventCoreLeakTrace`. https://github.com/vibe-d/eventcore/blob/7fa0a15fa541c3fcf65640ee332fd3a09c34730c/source/eventcore/drivers/posix/driver.d#L130 I didn't realize this wasn't across the board... -Steve
Re: Socket handle leak and active handle warning with Vibe-D
On Saturday, 13 January 2024 at 20:49:54 UTC, bomat wrote: I am still getting this in 2024 and vibe.d 0.9.7: ``` Warning: 1 socket handles leaked at driver shutdown. ``` I was wondering if maybe someone has new info on this... There should be a version you can enable that tells you where that socket handle was allocated. That might give you a further clue as to why it's not closed when the system shuts down. I think the program tells you which version to enable when this happens, but if not, let me know and I'll find it. -Steve
Re: Non-blocking keyboard input
On Sunday, 14 January 2024 at 13:41:26 UTC, Joe wrote: This does not actually work on my computer. It still blocks. Adam is no longer using mainstream D, and apparently not posting on this forum. I suggest you try to contact him via the arsd github page: https://github.com/adamdruppe/arsd -Steve
Re: Synchronisation help
On Monday, 1 January 2024 at 15:48:16 UTC, Anonymouse wrote: What is the common solution here? Do I add a module-level `Object thing` and move everything accessing the AA into `synchronized(.thing)` statements? Or maybe add a `shared static` something to `Foo` and synchronise with `synchronize(Foo.thing)`? Yeah, and the thing should be a `Mutex` object. A `Mutex` object uses it's underlying mutex primitive as its monitor. This also gives options for usage with methods as well as `synchronized` statements. Just make sure you mark it `__gshared` or `shared` so all threads see it. -Steve
Re: jsoniopipe - exaples?
On Friday, 29 December 2023 at 08:09:58 UTC, Zz wrote: Hi, Here are some samples from the std.json documentation. Any idea on how to do something similar using jsoniopipe? Directly copied from https://dlang.org/phobos/std_json.html import std.conv : to; // parse a file or string of json into a usable structure string s = `{ "language": "D", "rating": 3.5, "code": "42" }`; JSONValue j = parseJSON(s); // j and j["language"] return JSONValue, // j["language"].str returns a string writeln(j["language"].str); // "D" writeln(j["rating"].floating); // 3.5 // check a type long x; if (const(JSONValue)* code = "code" in j) { if (code.type() == JSONType.integer) x = code.integer; else x = to!int(code.str); } // create a json struct JSONValue jj = [ "language": "D" ]; // rating doesnt exist yet, so use .object to assign jj.object["rating"] = JSONValue(3.5); // create an array to assign to list jj.object["list"] = JSONValue( ["a", "b", "c"] ); // list already exists, so .object optional jj["list"].array ~= JSONValue("D"); string jjStr = `{"language":"D","list":["a","b","c","D"],"rating":3.5}`; writeln(jj.toString); // jjStr jsoniopipe is not focused on the `JSONValue` [equivalent](https://github.com/schveiguy/jsoniopipe/blob/7d63a2e19ae46a1ae56ccab4c6c872bcce094286/source/iopipe/json/dom.d#L22) You can see it's pretty basic and just serves as a "catch any type" thing. It could easily be replaced with `std.json.JSONValue`, though I like the fact that it's templated on the string type. The main focus of jsoniopipe is parsing and serialization -- I prefer to use real concrete structs/classes rather than variant types. In fact, the huge benefit from the library is that there is no intermediate type. But yeah, I could ingest all the functionality from std.json there. Or maybe even just use `JSONValue` from std.json. Could you make an issue? -Steve
Re: How to get serve-d to find dub dependencies
On Saturday, 23 December 2023 at 16:28:28 UTC, Renato wrote: On Saturday, 23 December 2023 at 16:13:01 UTC, Renato wrote: I am trying to use dependencies, so I need dub. On emacs, the imports from dub libraries cannot be found, even though dub can build it fine. How can I get emacs/serve-d to "see" the libraries added by dub? I found that dub has a command for letting the compiler know about the load paths: ``` dub describe --data=import-paths ``` This shows the correct paths for the project, so perhaps I can pass this to serve-d somehow? I've managed to kind of hack it by adding the paths to my `.dir-locals.el`: ``` ((nil . ((indent-tabs-mode . nil) (tab-width . 4))) (d-mode . ((compile-command . "dmd -L-ld_classic -run") (eglot-workspace-configuration . (:importPath ("/Users/renato/.dub/packages/console-colors/1.1.1/console-colors/source/")) ``` Far from ideal but this makes it half work... it actually shows the definitions in the library now and I can even navigate to the source, but still for some reason the import is shown as an error: ``` Expected 'consolecolors.d' or 'consolecolors/package.d' in one of the following import paths: ``` I believe that's because this is coming from d-mode, not serve-d (as serve-d actually "sees" it now)?! Anyway, would love to know how to get serve-d to automatically detect dub libs. dub recently changed how it stores packages. serve-d uses dub as a library to figure this out, so if the dub version serve-d is linked against does not match the version of dub you use to install/build, then it won't find the library includes. Check your version of dub against the version of dub serve-d is building against. Does the VS Code do that? If it does, this should work also on emacs. VS Code has a similar problem if you have a mismatch. The solution is to use the beta/nightly release channel of serve-d if you have a recent compiler. I will note there are some packages that serve-d just can't figure out for imports, because the configuration is done via dflags. -Steve
Re: Operator "+=" overloading for class?
On Monday, 18 December 2023 at 14:38:14 UTC, Ki Rill wrote: your code just return result value, but it should not return but save result to "this" see example at https://dlang.org/spec/operatoroverloading.html#index_op_assignment I get an error, but don't understand why. ```d auto opOpAssign(string op)(Value rhs) { this = this + rhs; return this; } // Error: `this` is not an lvalue and cannot be modified ``` Assigning an object is like copying a pointer. You may think you can try overloading the assignment, but it is [forbidden](https://dlang.org/spec/operatoroverloading.html#assignment): ``` However for class types, identity assignment is not allowed. All class types have reference semantics, so identity assignment by default rebinds the left-hand-side to the argument at the right, and this is not overridable. ``` But you aren't trying to do this. Instead you are trying to reassign the `this` reference, which is a local (and also forbidden). Think about it a second, your `this + rhs` is going to allocate a *new* object. Then if the assignment to the local `this` parameter succeeded, what happens outside the member function? The true reference that is calling this will not be updated! The only way to do this I can see is to reimplement for op=, or maybe perform the operation and swap the guts out. -Steve
Re: Manually relesing memory
On Saturday, 9 December 2023 at 10:12:11 UTC, Vlad Stanimir wrote: I am new to the language and am curios about manual memory management options. From what i can tell dlang offers the option for both manul and automatic management of memory resources. You might find all the answers in this blog series https://dlang.org/blog/the-gc-series/ -Steve
Re: now I need -allinst when dmd compiles the unittest
On Friday, 1 December 2023 at 22:00:52 UTC, kdevel wrote: If I not use -allinst the linker complains when using the current msgpack-d v1.0.5, e.g. [...]msgpack-d/src/msgpack/package.d:203: undefined reference to `pure nothrow @nogc @safe immutable(char)[] core.internal.dassert._d_assert_fail!(int)._d_assert_fail!(int)._d_assert_fail(scope const(immutable(char)[]), scope ref const(int), scope ref const(int))' [...]msgpack-d/src/msgpack/packer.d:1326: undefined reference to `pure nothrow @nogc @safe immutable(char)[] core.internal.dassert._d_assert_fail!(const(int))._d_assert_fail!(int)._d_assert_fail(scope const(immutable(char)[]), scope ref const(int), scope const(int))' [...]/msgpack-d/src/msgpack/unpacker.d:1505: undefined reference to `pure nothrow @nogc @safe immutable(char)[] core.internal.dassert._d_assert_fail!(int)._d_assert_fail!(int)._d_assert_fail(scope const(immutable(char)[]), scope ref const(int), scope ref const(int))' Are you using -checkaction=context? I have discovered that this happens if you build with -checkaction=context, but druntime has not been built with it, or you are using betterC. What happens is that an assert failure will trigger a call to a druntime function, and the compiler thinks that function is already instantiated in druntime, so it skips emitting the function, and expects druntime to be linked. I'm unsure whether druntime has the appropriate checkaction functions built by default, but definitely if you use betterC it won't be linked. For reference: https://issues.dlang.org/show_bug.cgi?id=22374 https://issues.dlang.org/show_bug.cgi?id=22902 https://issues.dlang.org/show_bug.cgi?id=19937 You even reported one of these... -Steve
Re: Advent of Code 2023
On Sunday, 3 December 2023 at 18:56:32 UTC, Johannes Miesenhardt wrote: On Sunday, 3 December 2023 at 14:51:37 UTC, Siarhei Siamashka wrote: [...] Thanks, this is super helpful. I have one other question, in the solution you posted and also the one I posted in the discord today. I was required to use byLineCopy. I first used byLine but I for some reason that I can't really explain only got the last line from that. I switched to byLineCopy because I saw it in other peoples solution and that magically fixed all problems I had. What exactly happened here? byLine reuses the buffer. So it is only valid while you haven’t fetched the next line. byLineCopy makes a copy of the line to give you so it will always remain valid. In these simple small type problems I find it easier to just fetch the whole file into a string and work with that. The performance of parsing the input is negligible. -Steve
Re: msghdr and cmsghdr mismatch for alpine musl
On Saturday, 25 November 2023 at 05:04:57 UTC, d007 wrote: `import core.sys.posix.sys.socket : msghdr, cmsghdr, iovec;` `msg_iovlen`, `msg_controllen`, `cmsg_len` is ulong for x86-64 in druntime. in alpine musl, they are int, socklen_t(uint), socklen_t(uint). Is this mismatch can cause problems is I use related api ? Yes. Mismatch of types is a really bad error for c interaction. -Steve
Re: Dirty DMD
On Saturday, 18 November 2023 at 18:52:07 UTC, JN wrote: Latest DMD for Windows downloaded from here: https://downloads.dlang.org/releases/2.x/2.105.3/dmd-2.105.3.exe reports version as dirty: DMD64 D Compiler v2.105.3-dirty Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved written by Walter Bright what does it mean by dirty? Something in the build process changes a file and therefore the thing that checks the version marks it as dirty. It’s perfectly fine, this is the official release. It’s a bit embarrassing to be honest. The windows binaries have been reporting dirty for years and nobody cares to fix it. -Steve
Re: D: How to check if a function is chained? a().b().c();
On Saturday, 18 November 2023 at 07:47:19 UTC, BoQsc wrote: Let's say we have a chain of functions. ``` a().b().c(); ``` I would like to have a behaviour in `a()` that would check if there is `b()` or `c()` chained to it. If `a();`is not chained: do a `writeln("You forgot to chain this function!");` A function that executes a program For me syntactically it is important. One real world application would be: `program("someProgramName").pipe("someOtherProgramName");` Executes and pipes output to another program. `program();` - Only executes the program. Consider adding @mustuse on the return type. https://dlang.org/spec/attribute.html#mustuse-attribute -Steve
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 13:58:17 UTC, Paul Backus wrote: It's easier to see if you compare the actual and expected argument lists side-by-side Expected: (ref const(S1) s) const Actual: (const(S1) ) ^ Mismatched 'this' argument This would be a much better output. Is this something you made up or did you get it from one of the compilers? LDC2, which is what I tested with, reported in the format that I mentioned. It might be something to add to the compiler that mismatches in `this` qualifiers should be reported separately, especially since the mutable form has no explicit qualifier. But I guess this is only an issue for constructors, because normal const functions can be called with mutable objects. That being said, I still consider this a bug, if the inout version works, the const version should work as well. I don't see the difference. So an interesting thing, if I change the `int i` to `int *i` in `S2`, instead of compiling I get the error: ``` Error: `inout` constructor `testinoutctor.S2.this` creates const object, not mutable ``` Which gives a much nicer error message! -Steve
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 08:50:34 UTC, dhs wrote: I am using following code: ```d struct S1 { this(ref const S1 s) const { writeln("copy"); } int i; } struct S2 { this(ref inout S2 s) inout { writeln("copy"); } int i; } void test() { const(S1) s1; S1 ss1 = s1; // error, ss1 not qualified as const const(S2) s2; S2 ss2 = s2; // fine, why? } ``` Isn't "inout" supposed to copy the const-ness of its parameter to the constructor's attribute? In other words: why doesn't ss2=s2 fail here? `ss2 = s2` does not fail because the type is implicitly convertible to non-const (a const int can be converted to a mutable int). Change `i` to `int *` and it will fail. IMO, the first should succeed as well. And I will note that the error looks different from what you say: ``` Error: copy constructor `testinoutctor.S1.this(ref const(S1) s) const` is not callable using argument types `(const(S1))` ``` I'm not sure what this means. There shouldn't be a copy being made here, as the thing is already const. I don't understand this error, and it looks like a bug to me. -Steve
Re: Dlang installer with VSCode broken
On Sunday, 5 November 2023 at 22:28:29 UTC, Daniel Donnelly, Jr. wrote: This is on my friend's machine, who I am teaching D. What can be done? Can you describe what you did? Also, might be helpful to file an issue on the code-d github repository itself: https://github.com/Pure-D/code-d -Steve
Re: Convert String to Date and Add ±N Hours
On Saturday, 4 November 2023 at 18:11:53 UTC, Vahid wrote: Hi, I have a date string with the format of "2023-11-04 23:10:20". I want to convert this string to Date object and also, add ±N hours to it. For example: `"2023-11-04 23:10:20" + "+2:00" = "2023-11-05 01:10:20"` `"2023-11-04 23:10:20" + "-2:30" = "2023-11-05 20:40:20"` How can I do this? Parse the date. There is a nice package on code.dlang.org that is for date parsing: https://code.dlang.org/packages/dateparser -Steve
Re: why remove octal literal support?
On Friday, 3 November 2023 at 15:07:41 UTC, d007 wrote: dlang is know for compile speed, but in reality d project compile slow because so much ctfe and tempalte. Why bring more ctfe call by remmove octal literal ? octal literals are extremely error prone, because people sometimes use leading zeroes for alignment, not realizing that it means the number is completely different. Actual correct octal literal use is vanishingly small. Banning C-style octal literals just makes it so the compiler flags unintended errors like this. -Steve
Re: What are the best available D (not C) File input/output options?
On Thursday, 2 November 2023 at 15:46:23 UTC, confuzzled wrote: I tried std.io but write() only outputs ubyte[] while I'm trying to output text so I abandoned idea early. Just specifically to answer this, this is so you understand this is what is going into the file -- bytes. You should use a buffering library like iopipe to write properly here (it handles the encoding of text for you). And I really don't have a good formatting library, you can rely on formattedWrite maybe. A lot of things need to be better for this solution to be smooth, it's one of the things I have to work on. -Steve
Re: is the array literal in a loop stack or heap allocated?
On 10/10/23 10:54 PM, mw wrote: Hi, I want to confirm: in the following loop, is the array literal `a` vs. `b` stack or heap allocated? and how many times? ask the compiler: ```d void main() @nogc { int[2] a; int[] b; int i; while(++i <=100) { a = [i, i+1]; // array literal //b = [i, i+1]; // yes, this allocates, had to comment it out } } ``` -Steve
Re: T[] opIndex() Error: .. signal 11
On 10/5/23 1:49 AM, ag0aep6g wrote: For some further reading, there's an open issue about the unexpected slicing: https://issues.dlang.org/show_bug.cgi?id=14619 Thank you I had forgotten about that issue! -Steve
Re: T[] opIndex() Error: .. signal 11
On 10/3/23 11:12 AM, Joel wrote: The following program crashes, but doesn’t if I change (see title) T[] to auto. The program doesn’t even use that method/function. What’s the story? It's a stack overflow. when doing foreach on your type, the compiler *always* uses a slice first if it compiles and is a valid range. So `foreach(x; ints)` really translates to `foreach(x; ints[])`. Normally not a problem. But your `opIndex()` is calling `this.array`. What does `this.array` do? a foreach on your type. Which calls `opIndex`, which calls `array`, which calls `opIndex`, etc. When you make it auto, well, then inside the `array` function, it won't use the `opIndex` (because clearly, the type hasn't been determined). And so it goes with the range functions without first doing a slice. But then outside the type, now that `opIndex` type has been inferred, it can now use `foreach(x; ints[])`, and that goes back to the regular mechanism. A minimized case is here: ```d struct S { int front() => 1; void popFront() {} bool empty() => true; auto opIndex() { foreach(x; this) {} return int[].init; } } void main() { S s; foreach(x; s) {} } ``` If you run this on run.dlang.io, and click the "AST" button, you will get this for the type and the main function: ```d import object; struct S { int front() { return 1; } void popFront() { } bool empty() { return true; } auto @system int[] opIndex() { { S __r2 = this; for (; !__r2.empty(); __r2.popFront()) { int x = __r2.front(); } } return null; } } void main() { S s = 0; { scope int[] __r3 = s.opIndex()[]; ulong __key4 = 0LU; for (; __key4 < __r3.length; __key4 += 1LU) { int x = __r3[__key4]; } } return 0; } ``` Note the difference in how the foreach code is lowered. Inside `opIndex`, it's lowered to the range functions. Outside, it uses the slice operator to switch to iterating a `scope int[]`. If you now switch the `auto` to `int[]`, it's a segfault, because now the `opIndex` has a concrete return type, and it *can* use the `opIndex`, inside `opIndex`. I really think the implicit slice should be revisited. It shouldn't happen in this case. -Steve
Re: The difference between T[] opIndex() and T[] opSlice()
On 10/3/23 12:09 PM, Paul Backus wrote: On Tuesday, 3 October 2023 at 13:07:00 UTC, Steven Schveighoffer wrote: Now, you can define a further `opIndexAssign(T val, size_t idx)`. However, now you lose capabilities like `a[0]++`, which I don't think has a possibility of implementing using an `opIndex` operator, and it would be pretty ugly if you had to. Works for me, with both `++` and `+=`: https://run.dlang.io/is/JckTVG AST output confirms that these are lowered to use `opIndex`. Looking at the spec, it seems like `opIndex` would only be pre-empted here if you overloaded `opIndexUnary` (for `++`) and/or `opIndexOpAssign` (for `+=`). OK, so it's not as bad as I thought, but surely the compiler should recognize that `opIndexAssign(val, idx)` doesn't work, but `opIndex(idx) = val` does? -Steve
Re: The difference between T[] opIndex() and T[] opSlice()
On Monday, 2 October 2023 at 20:42:14 UTC, Paul Backus wrote: On Monday, 2 October 2023 at 20:34:11 UTC, Salih Dincer wrote: In an old version (for example, v2.0.83), the code you implemented in the places where Slice is written above works as desired. In the most current versions, the parameterized opIndexAssign(T value) gives the error: onlineapp.d(51): Error: function `onlineapp.Matrix!double.Matrix.opIndexAssign(double value)` is not callable using argument types `(double, ulong)` onlineapp.d(51):expected 1 argument(s), not 2 **Source:** https://run.dlang.io/is/TPAg5m I don't know what's wrong in your example but this works for me: ```d struct S { void opIndexAssign(int value) { import std.stdio; writeln("assigned ", value); } } void main() { S s; s[] = 7; } ``` So in the example linked by Salih, the `opIndex` returns a ref, which is a valid mechanism to properly do `a[0] = val;`. However, since `opIndexAssign` exists, the compiler expects that to be used instead. Essentially, by naming the slice assign the same operator as index assign, you have eliminated the possibility for ref assignment via indexing. Now, you can define a further `opIndexAssign(T val, size_t idx)`. However, now you lose capabilities like `a[0]++`, which I don't think has a possibility of implementing using an `opIndex` operator, and it would be pretty ugly if you had to. This seems like a design flaw in the `opIndex` overloading changes. I would stick with `opSliceAssign` if faced with this problem (glad it still works!) It could also be considered a bug but I don't know the overload implications. -Steve
Re: The difference between T[] opIndex() and T[] opSlice()
On 10/1/23 1:41 PM, Salih Dincer wrote: Hi, What is the difference between T[] opIndex() and T[] opSlice(), which haven't parameters? None. It used to be that opSlice was the only way, and the mechanisms opSlice uses are still valid. -Steve
Re: Straight Forward Arrays
On 10/1/23 1:13 PM, dhs wrote: It may not be a problem in practice. My concern was performance, because each time we add an element to the array, the garbage collector has to map the slice to the allocation it belongs to. FWIW, there is a cache that makes this decently fast, so it doesn't have to go all the way into the GC to get all the information for every append. But it *most definitely* not going to be as fast as reading a local "capacity" variable. -Steve
Re: Straight Forward Arrays
On 10/1/23 10:34 AM, Steven Schveighoffer wrote: The complexity is from the way d does operator overloading and indexing. It should be pretty straightforward. I’ll see if I can post a simple wrapper. I didn't tackle any attribute or memory safety issues, or many operator overloads, but this is going to be reasonably close. It should make a copy of the data when copied. Note this still uses the GC for storage, and when expanding, uses the GC to fetch the capacity (this could be done in one call, but meh). Some niceties of builtin arrays may not work, but this is somewhat of the cost you pay for trying to make a custom type. ```d struct VTArray(T) { private T[] _storage; private size_t _length; const size_t length() => _length; void length(size_t newLen) { if(newLen <= _storage.length) _length = newLen; else { _storage.length = newLen; _storage.length = _storage.capacity; } } inout this(ref inout(VTArray) other) { this(other[]); } inout this(inout(T)[] buf) { auto x = buf.dup; x.length = x.capacity; _length = buf.length; _storage = cast(inout)x; } ref inout(T) opIndex(size_t idx) inout { assert(idx < length); return _storage[idx]; } void opOpAssign(string s : "~", V)(auto ref V other) { static if(is(V == T[])) { immutable avail = _storage.length - length; if(avail < other.length) { _storage[length .. $] = other[0 .. avail]; _storage ~= other[avail .. $]; _storage.length = _storage.capacity; // expand to capacity; } else { _storage[length .. length + other.length] = other; } _length += other.length; } else static if(is(V == T)) { if(length == _storage.length) { _storage.length += 1; _storage.length = _storage.capacity; } _storage[_length++] = other; } else static if(is(V == VTArray)) { this ~= other[]; } } void opAssign(T[] arr) { _storage = arr.dup; _storage.length = _storage.capacity; _length = arr.length; } void opAssign(VTArray vtarr) { this = vtarr._storage[0 .. vtarr.length]; } inout(T)[] opIndex() inout => _storage[0 .. _length]; void toString(Out)(auto ref Out output) { import std.format; formattedWrite(output, "%s", this[]); } } void main() { auto arr = VTArray!int.init; arr ~= 1; arr ~= [2,3,4,5]; import std.stdio; writeln(arr); auto arr2 = arr; arr2[0] = 5; writeln(arr); writeln(arr2); arr2 ~= arr; writeln(arr2); } ``` This should give you a reasonable head-start. -Steve
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 13:24:27 UTC, dhs wrote: On Sunday, 1 October 2023 at 13:05:12 UTC, Steven Schveighoffer wrote: On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: [...] Std::vector uses value semantics. D does not have anything like that. It could be done someone just has to do it. Yes, and therein lies the problem: writing a dynamic array is not a very difficult task for an old developer like me. I looked at the D runtime and at the Phobos implementation for reference. The code is so extremely difficult to understand and uses so many advanced D features, that I doubt that I am up to the task. For me, the point of switching to D was to use a language that is simpler to read and maintain. The complexity is from the way d does operator overloading and indexing. It should be pretty straightforward. I’ll see if I can post a simple wrapper. -Steve
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: Hi, Is there a straight forward Array type in D similar to C++'s vector class? Something along the lines of the tuple: (pointer to elements, length, capacity). [...] Std::vector uses value semantics. D does not have anything like that. It could be done someone just has to do it. -Steve
Re: Vibe.d download function, how to get callback when done or error?
On 9/23/23 8:07 AM, j...@bloow.edu wrote: I'm using download(url, filename) to download files in vibe.d. The issue is that I do not know when the download is finished or errors. There is a callback for the streaming side but not for the file download. You might misunderstand how vibe is doing async. Basically, that fiber is put to sleep until the download is finished, and then you get the result. You write your code as if it were synchronous. If you call this outside of an async context, vibe will start up an event loop and run it until your download is done. -Steve
Re: range shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`
On Sunday, 24 September 2023 at 10:00:31 UTC, Joe wrote: For absolutely no reason I started getting this error. Last night I compiled the project and it worked just fine. This morning I made a single insignificant change and tried to compile and got that error. Only possible thing is that for some reason some change in updating the compiler may have no propagated correctly till after the reboot. [...] This sounds like a compiler issue. Are you on the latest compiler? Which compiler? Is there a set of code you can post or upload which causes the problem? -Steve
Re: "readln" after "readf"
On Thursday, 21 September 2023 at 09:14:14 UTC, pascal111 wrote: I've a problem when I'm using "readln" after "readf" that I couldn't see my program rest and the lines of the execution ran fast: module main; import std.stdio; import std.string; import std.conv; int main(string[] args) { char[] yy; int x,y,z; writef("Enter a number: "); readf(" %d",); writef("Enter a number: "); readf(" %d",); z=x+y; writefln("Hi! %d",z); writef("Enter a number: "); readln(yy); yy = strip(yy); x=to!int(yy); writef("Enter a number: "); readln(yy); yy = strip(yy); y=to!int(yy); z=x+y; writefln("Hi! %d",z); return 0; } Your readfs are not consuming the newline at the end. Add `\n` to the end of the format text. -Steve
Re: How to use core.vararg to print D variadic arguments and their types without using ! (template instantiation)?
On 9/15/23 4:14 PM, Basile B. wrote: On Thursday, 14 September 2023 at 15:19:29 UTC, BoQsc wrote: https://dlang.org/phobos/core_vararg.html The common way to use **va_arg** is `va_arg!(int)(_argptr);` What would be the alternative way or syntax that behave exactly the same way, even if more verbose? `va_arg!(int)(_argptr);` is taken from an example in: https://dlang.org/spec/function.html#d_style_variadic_functions here's how ```d import core.vararg; void main() { foo(.5, 5); } void foo(...) { int i = void; va_arg(_argptr, typeid(i), ); assert(i == 5); double d = void; va_arg(_argptr, typeid(d), ); assert(d == .5); } ``` Note that this doesn't work in gdc. The templated version is actually more akin to what C does. -Steve
Re: Setting struct as default parameter of a function using struct literal?
On Monday, 11 September 2023 at 19:59:37 UTC, ryuukk_ wrote: I would love to be able to use C style designated initialization everywhere too.. Recent version of D added named arguments so you can do something like: ```D void someFunction(Options option = Options(silenceErrors: false)) ``` I don't like the useless repeating "option option option", but that's D for you ```d void someFunction(bool silenceErrors = false, bool otherOption = true) someFunction(otherOption: false); // works ``` I know options structs have benefits besides allowing parameter specification, but with the latest allowance of named parameters, it's worth exploring whether you still want to use an options struct or not. -Steve
Re: malloc error when trying to assign the returned pointer to a struct field
On Saturday, 9 September 2023 at 09:21:32 UTC, rempas wrote: Now, if only one could expect how and why "libc" knows that and doesn't just care to give me the memory I asked it for? Or it could be than D does something additional without telling us? Which can explain when this memory is only present when I assign the value to the "this._ptr` field! You are focusing on the wrong problem. You asked for size bytes, and malloc gave you size bytes. It doesn't "know" anything special. Then you proceeded at some point to write *past* the size bytes. What did you overwrite? Probably some internal malloc implementation structure. Then it later noticed "hey, this structure doesn't make sense, I'm going to report it to the user!" That's why you see the message. Memory problems are very difficult to find, and typically an error is triggered far away from the source, in seemingly unrelated code. This is why whenever I see an error that smells like memory corruption, I stop all other work and find it. Memory errors can come and go based on random chance or how the compiler lays out functions. So having it "just go away" isn't enough. Very very infrequently, this happens because of a codegen issue, but most of the time it's pilot error. -Steve
Re: malloc error when trying to assign the returned pointer to a struct field
On Friday, 8 September 2023 at 07:59:37 UTC, rempas wrote: I do have the following struct: ... That's some minimal code that I do have just to showcase it. This is not ideal. Why? Because 99% of the time, a poster has come here with a problem they don't know how to solve, and have focused in on where they *think* the problem is. However, the problem isn't there. But us reading the description can only see what the poster sees, and either don't see a problem ("I'm just as confused as you are!") or know there is more to the story. Not only that, but frequently not-complete code is... not complete. And people tend to focus on problems they can see (e.g. where is that `_len` defined?), frustrating the poster with "trivial" problems that are solved "in the real code". Inevitably, there is a subsequent post with the real code, and that contains the problem. The best thing to post is a minimally reproducing example. The next best thing is a link to a complex reproducing example. Which you have done later (I will take a look). I just wanted to point this out because it's a frequent problem on these forums. So, some times, this work will works, some others, it will give me the following error: `Fatal glibc error: malloc.c:2594 (sysmalloc): assertion failed: (old_top == initial_top (av) && old_size == 0) || ((unsigned long) (old_size) >= MINSIZE && prev_inuse (old_top) && ((unsigned long) old_end & (pagesize - 1)) == 0)` This is an internal message from glibc. It seems the malloc structure is corrupted. Is there any possible that there is a compiler bug? I do use ldc2 and `betterC`! There is always a chance... Now, critiquing your original code, I see red flags here: ```d u64 _cap = 0; // Total amount of elements (not bytes) we can store ``` and then later: ```d this(i64 size) { this._len = 0; this._cap = size; ``` ok, so `size` must mean the number of elements, not the number of bytes. ```d static if (is(T == char)) { size += 1; } // Additional space for the null terminator this._ptr = cast(T*)malloc(size); ``` Here, you have allocated `size` bytes for the array. Is this what is intended? Your comments suggest otherwise! If `T.sizeof` is 2 or more, then you still only allocate e.g. 20 bytes for a `_cap` of 20. but an array of 20 T's would require 40 bytes. -Steve
Re: AA vs __gshared
On 8/12/23 5:55 AM, IchorDev wrote: On Thursday, 10 August 2023 at 15:20:28 UTC, Steven Schveighoffer wrote: That shouldn't matter. Well, it does here. The AA is mutated during the loop, so perhaps this is an optimisation quirk where it works with `for` but segfaults in `foreach`? I've pretty thoroughly abused the `for` version and I haven't gotten it to segfault yet. oh yeah. That is not allowed. Any mutation of the AA during iteration can invalidate existing foreach or ranges over the AA. Basically, a rehash can cause the buckets to jumble up, and in that case, the "current index" can be changed to point at a null bucket. More here: https://dlang.org/spec/statement.html#foreach_restrictions In fact, that statement is way too broad. Invalidation of iteration should be based on the type's requirements. We really should put a note in the AA spec page. I also highly recommend using `emplace` to handle all the sticky issues with lifetime/construction. Have not run into the aforementioned sticky issues yet, but I can't even find `emplace`'s docs anywhere now. https://dlang.org/phobos/core_lifetime.html#.emplace I recall it being incompatible with classes that have @nogc/nothrow constructors though, which made it pretty useless to me, and it wouldn't work with BetterC, which was a requirement for the allocation wrapper I was writing at the time. It probably won't work with betterC, but that's probably just because of linker errors. Any attribute requirements would be inferred based on the attributes of your constructor, because emplace is a template. -Steve
Re: sort with char’s
On Saturday, 12 August 2023 at 06:47:50 UTC, Joel wrote: writeln(name[].each!(n => n.write)); // get "christensenyes" //, " <> ", name[].sort!"a>b".each!(n => n.write)); This writes each character individually, and then at the end writes the result of `each` with a newline. In this case, `each` [docs](https://dlang.org/phobos/std_algorithm_iteration.html#each) say: Returns: Yes.each if the entire range was iterated, No.each in case of early stopping. `Yes.each` is going to print as "yes". -Steve
Re: Why is GC.collect not @safe?
On 8/2/23 7:40 AM, Nick Treleaven wrote: Presumably an allocation like `new T` (for a type with a @safe constructor) can be made anywhere a call to `GC.collect` can be made, which may trigger a collection. So why isn't `GC.collect` marked @safe? It should be. Maybe historical reasons? One possible (but wrong) reason is that destructors can be unsafe. But you are correct in that allocation can cause a collection. -Steve
Re: HTTP Post Body Parameters
On 8/1/23 7:57 PM, Vahid wrote: Hi, I want to submit a request to server with "x-www-form-urlencoded" header. This is the simplified version of my code: auto http = HTTP("https://myurl.com/api;); http.addRequestHeader("Content-Type", "application/x-www-form-urlencoded"); http.addRequestHeader("Authorization", "SID:TOKEN"); auto params = "Param1=one=two"; http.setPostData(params, "application/x-www-form-urlencoded"); http.onReceive = (ubyte[] response) { return cast(string) response; }; onReceive is a push from the library to you. Returning the response doesn't actually do anything. You need to store it somewhere. e.g. ```d ubyte[] msg; http.onReceive = (ubyte[] response) { msg ~= response; return response.length; // tell the receiver how much data was read }; http.perform(); // fills in msg return msg; ``` from the std.net.curl docs about onReceive (which by the way, should return a ulong, I'm not sure how your cast to string even compiles): The event handler that receives incoming data. Be sure to copy the incoming ubyte[] since it is not guaranteed to be valid after the callback returns. -Steve
Re: Anyone help me with a stack dump?
On 7/31/23 9:09 AM, Cecil Ward wrote: The unitttests that I have just put in crash spectacularly with an access violation. I built the code with LDC for Aarch64 / OSX and I fired up lldb. I now have to learn lldb quick. (BTW Where can I get an x86 / linux build of lldb or similar ?) This is the stack dump, and I could do with some help decoding parts of it unittest_L1541 -> unittest on line 1541. Probably something in there doing appending? I myself have a hard time with lldb. I understand gdb a lot better. -Steve
Re: AA vs __gshared
On 7/28/23 11:15 AM, IchorDev wrote: On Friday, 28 July 2023 at 11:15:31 UTC, Steven Schveighoffer wrote: All `__gshared` does is give you storage that is accessible from all threads, "All __gshared does is give you [a live bomb, ready to go off at any moment]" !! It seems like it's not __gshared at all, but misusing malloc with GC pointers. On Friday, 28 July 2023 at 14:10:16 UTC, Kagamin wrote: Your error is using allocating the object with malloc. Since gc doesn't see your AA, the AA is freed and you get UAF. Friend, I think you nailed it. After adding this I haven't been able to reproduce the segfault again: ```d this(long n){ (){ cache = new typeof(cache); assert(cache); import core.memory; core.memory.GC.addRoot(cast(void*)cache); }(); // ... ``` It did always happen at random, so perhaps I haven't spent enough time testing it yet, but I've gone far longer without it segfaulting than ever before. This is the wrong approach, it's the allocating call that should add the root (actually a range). For instance, the mutex is not added, that might be collected. Or if you add more GC-pointing things into the class, that could be a problem. What I'd do is: ```d T alloc(T, A...)(auto ref A args){ enum classSize = __traits(classInstanceSize, T); void* mem = core.stdc.stdlib.malloc(classSize); assert(mem !is null, "Out of memory"); core.memory.GC.addRange(mem[0 .. classSize]); scope(failure) { core.memory.GC.removeRange(mem[0 .. classSize]); core.stdc.stdlib.free(mem); } T inst = cast(T)mem; inst.emplace(__traits(parameters)); return inst; } ``` And of course, a `dealloc` that removes the range should also be added. -Steve
Re: Syntax for Static Import of User Define Attributes
On 7/28/23 8:10 AM, Vijay Nayar wrote: However, this makes me wonder. Is there any reason why the `@` shouldn't recognize the dots in a fully-qualified-name on its own, without the need for parentheses? It might be possible to expand the grammar. It seems very specific to UDAs, as it doesn't just throw out `Expression` or whatnot. It probably has to do with the spot that it's in (declaration). I'll defer to the compiler experts to decide what makes the most sense. -Steve
Re: Syntax for Static Import of User Define Attributes
On 7/28/23 4:15 AM, Vijay Nayar wrote: On Thursday, 27 July 2023 at 21:24:44 UTC, Dennis wrote: On Thursday, 27 July 2023 at 21:19:08 UTC, Vijay Nayar wrote: Attempted Fix 2: Enclose the entire attribute name in parenthesis. ``` static import vibe.data.serialization; class ChatCompletionFunctions { @(vibe.data.serialization.name)("name") ... } ``` Try: ```D @(vibe.data.serialization.name("name")) ``` This one causes a different error, because it invokes the template-argument syntax: https://dlang.org/spec/attribute.html#uda I tried it and it worked for me. The template-argument syntax is normal. It's just a list of types or expressions (i.e. not a function argument list) What is the error? -Steve
Re: Designated initializers to function argument
On 7/28/23 3:35 AM, IchorDev wrote: On Tuesday, 11 July 2023 at 17:43:43 UTC, Steven Schveighoffer wrote: On 7/11/23 11:22 AM, Ki Rill wrote: On Tuesday, 11 July 2023 at 15:16:54 UTC, Ki Rill wrote: apply(Appearance(color: BLACK, strokeWidth: 4)); // other fields are default initialized: strokeOpacity, fillOpacity, Yes, I was going to reply that v 2.103 has added (stealthily) named parameters *as a partial implementation*. Included in this is struct initializers, and constructors and functions that are *not* templates. If you are willing to use DMD 2.103 and above, you should be good. N-no way?! The spec makes no mention of them, is it really safe to use them yet? It isn't going away. I would wait a bit for libraries, because you don't want to force your users to require such a recent version of the compiler. Using it in an executable is fine. -Steve
Re: AA vs __gshared
On 7/28/23 4:39 AM, IchorDev wrote: Issue is, this code I posted actually runs just fine, unlike the real code. My actual code does this HIGHLY SUSPICIOUS thing when printing their length each time before using them: ``` 766 766 765 766 767 768 768 768 768 768 768 768 768 768 768 768 768 768 768 128000 Error Program exited with code -11 (backtrace:) #0 0x55670c46 in rt.aaA.Impl.findSlotLookup(ulong, scope const(void*), scope const(TypeInfo)) inout () #1 0x55661592 in _aaInX () ``` My suspicion would be a race condition in your real code, and no race condition in this toy code. Second suspicion would be memory corruption (possibly caused by a race condition). Therefore I must logically conclude that DRuntime's AAs are cursed! Unless this is a well-known issue or something... AAs have worked forever. I've never had problems with them. Not saying there's not a bug here, maybe there is. But I would be surprised. Thinking back, I've actually had them cause segfaults in non-threaded code, maybe `__gshared` was never the cause at all. All `__gshared` does is give you storage that is accessible from all threads, but is not typed as `shared`. It doesn't change how the data is used. -Steve
Re: Which D compiler is the most maintained and future-proof? [DMD GDC and LDC]
On 7/24/23 9:30 AM, cc wrote: On Monday, 24 July 2023 at 09:29:09 UTC, Richard (Rikki) Andrew Cattermole wrote: There isn't a huge concern with which one you use. Its quite common to use dmd for development, and ldc for release for example. They all share the same frontend, so they really only differ between them by their glue code to the relevant backend and some modules in druntime that are optional. Oh and inline assembly, although there is some compat code in ldc/gdc for dmd style. If dmd dies, so does ldc/gdc basically. Each one sees active development although gdc only has one developer. Ldc keeps up with the dmd releases pretty well. If DMD dies, the other two will live on. This is open source after all. Is there any list of known significant "gotchas" with moving to LDC from DMD? Any unexpected surprises to watch out for or be careful for? I'm thinking of all the "features" of DMD that are now considered verboten by many users (e.g. compiling with -release, disabling of asserts or array bounds checking, etc). Known edge cases of compiler optimization causing different behavior between vendors? DMD is the point of all D feature introductions, and so anything that works with LDC should work with DMD. It's the other way around that might cause trouble, since there may be DMD features which haven't yet made it into LDC. There are also subtle ways to consider things "broken" which might affect you if you care about that. Like for instance floating point handling is different, so you might not get exactly the same binary results. -Steve
Re: Garbage Collectors
On 7/19/23 10:46 AM, Johan wrote: On Wednesday, 19 July 2023 at 11:27:14 UTC, Richard (Rikki) Andrew Cattermole wrote: [...] you would have to do a new build of druntime/phobos special which isn't the easiest thing to do. Side remark: LDC ships with the ldc-build-runtime tool which should help the user a lot in building druntime/phobos. (downloads the correct source belonging to the specific compiler version, and then builds the libraries with user-specified flags, compilers, etc.) This is very cool to know, I wasn't aware! -Steve
Re: Garbage Collectors
On 7/19/23 3:24 AM, IchorDev wrote: So, D’s default garbage collector is the one named “conservative” in DRuntime… I see there’s also “manual” which doesn’t actually function as a GC, which is interesting. Nothing says what ProtoGC is… so I guess it’s useless. Has anyone ever published any custom GCs? A search through the dub package registry yielded nothing. How hard would it be to port (for instance) a Java GC to D’s interface? To answer the question about ProtoGC, it is a stub GC which will create the appropriate GC (based on runtime flags) when the first function that requires actually using the GC is called. It is actually the default GC. This was introduced to implement more pay-as-you-go runtime features. If you don't use the GC, no GC is created. If I recall correctly, you must attempt to allocate using the GC for the ProtoGC to do its thing. Everything else is just simple stubs (e.g. ProtoGC.free does nothing, since it can never allocate memory) -Steve
Re: Print debug data
On 7/18/23 5:04 PM, Alain De Vos wrote: ? use `stats` instead of `Stats`. The `Stats` name is the type, whereas the `stats` method is the call that gets the stats. It's kind of a terrible message, I wish it would change to something more informative. -Steve
Re: How to free memory ater use of "new" to allocate it.
On 7/16/23 11:58 PM, Alain De Vos wrote: Maybe code above works when you enforce an Garbage-collection-run ? Code below works fine. So you cannot use "new" but must use malloc? ``` import std.stdio:writefln; import object: destroy; import core.memory: GC; import core.stdc.stdlib: malloc,free; void dofun(){ auto pa=cast(int *)malloc(1000*int.sizeof); writefln("%12x",pa); auto a=pa[0..1000]; free(a.ptr); } int main(){ dofun(); auto pb=cast(int *)malloc(1000*int.sizeof); writefln("%12x",pb); auto b=pb[0..1000]; free(b.ptr); return 0; } ``` Notice how you didn't call `destroy(a)` there. If you did, then `free(a)` would be equivalent to `free(null)`, which would do nothing. -Steve
Re: How to free memory ater use of "new" to allocate it.
On 7/16/23 11:41 PM, Alain De Vos wrote: The following program prints two different addresses. Meaning the new allocates memory until the program dies. So the means memory leak by default ? ``` import std.stdio:writefln; import object: destroy; import core.memory: GC; void dofun(){ auto a=new int[1000]; writefln("%12x",); destroy(a); GC.free(a.ptr); } int main(){ dofun(); auto b=new int[1000]; writefln("%12x",); return 0; } ``` No, what I am trying to explain is that `destroy(a)` is literally equivalent to `a = null`. If you then `free(a)` do you think it does anything? -Steve
Re: How to free memory ater use of "new" to allocate it.
On 7/16/23 2:41 PM, Alain De Vos wrote: Is this ok ? ``` void main(){ int[] i=new int[1]; import object: destroy; destroy(i); import core.memory: GC; GC.free(GC.addrOf(cast(void *)(i.ptr))); } ``` No, that won't work. Check out `i` value after you call `destroy` on it: ```d destroy(i); // basically sets i = null assert(i.ptr is null); // yep GC.free(i.ptr); // basically free(null) which is a no-op ``` Also note that `destroy` is *shallow*. It does not dig into pointers or arrays. So even if your array was of elements with a destructor, destroying the array doesn't destroy the elements. In this case, all you need to do is: ```d GC.free(GC.addrOf(i.ptr)); ``` You don't need the cast here. You shouldn't need the addrOf, but this is still open: https://issues.dlang.org/show_bug.cgi?id=13558 -Steve
Re: Issue De-referencing a Pointer to a Struct in an Array
On 7/14/23 1:23 PM, Pen Hall wrote: I think i figured out my issue... The issue was that 'board' is a pointer, and all of the ways I tried to de-reference it, failed. I just tried the form `(*board)[number][symbol][letter]` which worked to de-reference it. `&(*board)[number][symbol][letter]`, of course, works to get a pointer to that spot in memory. A nice abstraction available in D is a nested function. e.g.: ```d ref boardRef => *board; // or with traditional syntax: ref Tile[8][8][8] boardRef() { return *board; } ``` This should allow you to use `boardRef[number][symbol][i]` -Steve
Re: Giant template - changing types everywhere
On 7/14/23 12:40 PM, Christian Köstlin wrote: Would Eponymous Templates (https://dlang.org/spec/template.html#implicit_template_properties) work with the wrapping template? Only if all the functions are named the same as the template. With eponymous templates, you no longer get access to any of the members of the template aside from the eponymous member(s). -Steve
Re: Giant template - changing types everywhere
On 7/14/23 1:51 AM, Cecil Ward wrote: On Friday, 14 July 2023 at 05:09:58 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 05:05:27 UTC, Cecil Ward wrote: On Friday, 14 July 2023 at 05:03:31 UTC, Cecil Ward wrote: The way I can see it going is a giant template encompassing pretty much the whole file. Does that mean that the caller who calls my one public function does so by passing the type dchar or wchar ? And then we generate the strings from that. It might be rather more natural for the caller to pass one of the string types into the template. That’s where I get rather more confused, say caller calls Transform(dstring)(dstring str) or can they just do Transform( "str"d ) and it would work out that the type is immutable dchar[] ? Perhaps I should just make up a small example file with two functions in it to see if I can get the syntax right? If I wrap the whole thing with a template declaration of the xchar type, then can I get away with no changes to the individual function definitions? I tried it, wrapped the whole thing in a template definition and it compiled, but then my test file which calls Transform( someDString ) failed to compile with errors saying it couldn’t find the definition of Transform in the other module, which is or was public. It’s as if it is no longer public because it’s now inside the template. So templates don't automatically instantiate, you have to specify them. And then if your function is inside the template, to access it, you will need to do: ```d GiantTemplate!dstring.Transform(str); ``` But this is not a usual way of creating API. Instead, you should template individual functions on the string type. Depending on what you are doing, you can use: ```d T Transform(T)(T val) T[] Transform(T)(T[] val) ``` The first will cover cases where you have custom string types that aren't arrays, the second will just capture the array type, and ensures that the parameter/return is an array. When you make template functions like this, a feature of D called Implicit Function Template Instantiation (IFTI) will automatically instantiate the template for you, so you don't have to specify the template parameters. You just call `Transform(str)` and it works. With the wrapping template solution, this is not available -- you must explicitly instantiate the wrapper. If you are having problems, it is nearly impossible to diagnose without some actual code to look at. -Steve
Re: Giant template - changing types everywhere
On 7/13/23 8:08 PM, Cecil Ward wrote: What I really want to do though is provide one single templated function with the kind of characters / strings as a parameter. I want to have something like T Transform( T )( T str) called as auto result = Transform!(dstring)( dstring str ); ```d T[] Transform(T)(T[] str) ``` Note that you don't have to specify the type when calling: ```d Transform(someDstring); // infers dchar ``` I’m quite confused as to how to proceed. This is quite a large module ~ 2k loc, and I don’t really want to go through and change every private function into a templated one. Should I just make the whole thing into a giant template containing many functions? If you have more questions, please ask. Some examples of how making a template would be painful would be helpful. -Steve
Re: Designated initializers to function argument
On 7/11/23 11:22 AM, Ki Rill wrote: On Tuesday, 11 July 2023 at 15:16:54 UTC, Ki Rill wrote: ```D // or this apply(Appearance(color: BLACK, strokeWidth: 4)); // other fields are default initialized: strokeOpacity, fillOpacity, etc... ``` Ok, this works with DMD v2.103, but does not work with an older version (I had ldc2 installed based on DMD v2.98). Yes, I was going to reply that v 2.103 has added (stealthily) named parameters *as a partial implementation*. Included in this is struct initializers, and constructors and functions that are *not* templates. If you are willing to use DMD 2.103 and above, you should be good. -Steve
Re: Pre-expanding alloc cell(s) / reserving space for an associative array
On 7/10/23 8:44 AM, H. S. Teoh wrote: On Mon, Jul 10, 2023 at 09:30:57AM +, IchorDev via Digitalmars-d-learn wrote: [...] From the spec it sounds as though (but good luck testing for sure) that if you have (for example) 6 big dummy key-value pairs in the AA to begin with, then if you use `.clear` it "Removes all remaining keys and values from [the] associative array. The array is not rehashed after removal, __to allow for the existing storage to be reused.__" [...] This is not an accurate understanding of what actually happens. The AA implementation consists of a primary hashtable (an array), each slot of which points to a list of buckets. Clearing the AA does not discard the hashtable, but does dispose of the buckets, so adding new keys afterwards will allocate new buckets. So the buckets used by the dummy key-value pairs do not get reused without a reallocation. This used to be the case, but in the latest implementation, the AA uses open addressing. That is, if a slot is full, it linearly searches the table for the next open slot. This cuts down significantly on cache misses, since the hash slot itself stores the hash, so the pointer only needs to be followed if the hash matches. Fun historical fact, the original AA used a tree to store colliding elements, which means that all AA keys had to support both opEquals and opCmp. BUT, you are right that the elements themselves are individual blocks of memory, and only the bucket array is reused. If you want to see how the hash table works, without having to deal with all the typeinfo acrobatics that the actual builtin AA uses, you can look at my newaa library: https://github.com/schveiguy/newaa This is the exact implementation of the AA internals, but uses compile-time introspection instead of typeinfo. -Steve
Re: Pre-expanding alloc cell(s) / reserving space for an associative array
On 7/9/23 4:24 PM, Cecil Ward wrote: Before I posted a question about avoiding unnecessary allocs/reallocs when adding entries to an array like so uint[ dstring ] arr; when I build it up from nothing with successive insertions. The array is accessed by a key that is a dstring. I was told that I can’t use .reserve or the like on it? Is that correct? My memory fails me, powerful pain drugs. Is there an alternate method I could use ? To be honest, the number of entries is likely to be extremely modest, so this is not a huge performance issue, six entries would be considered quite a lot. The string keys are probably not very very long. But I’m learning good habits for the day when I might have a bigger such database. No there is no such `.reserve` call for associative arrays. It might be possible to implement, but it's quite a bit different from a normal array reserve -- an associative array allocates all its elements as individual memory blocks, so there is no place to reserve things. You would have to add e.g. a free-list, that is reserved from the allocator itself. -Steve
Re: Linker error, doing something wrong?
On 7/9/23 10:01 AM, Dmitry Olshansky wrote: Trying to compile the following: https://github.com/DmitryOlshansky/photon/blob/master/tests/curl_download.d with: ldc2 curl_download.d -L-lcurl get: "__D6photon12__ModuleInfoZ", referenced from: __D13curl_download12__ModuleInfoZ in curl_download.o "__D6photon5macos4core2goFDFZvZv", referenced from: __D13curl_download4mainFZ13spawnDownloadMFAyaQdZv in curl_download.o "__D6photon5macos4core9startloopFZv", referenced from: __Dmain in curl_download.o "__D6photon9runFibersFZv", referenced from: __Dmain in curl_download.o ld: symbol(s) not found for architecture arm64 clang: error: linker command failed with exit code 1 (use -v to see invocation) Error: /usr/bin/cc failed with status: 1 Am I missing something? You need to link the library that contains photon. -Steve
Re: Weird template instantiation speed?
On 7/9/23 7:54 AM, IchorDev wrote: While working on some new bindings, I've discovered that if `opAssign` in a struct template "`BindingTempl(T)`" has the return type "`BindingTempl!T` then it adds about 4 seconds to the compile time per instantiation of `BindingTempl`. The added compile time is much lower if a function other than `opAssign` returns `BindingTempl!T`. Is opAssign a particularly bad operator to overload in templates or something? This is probably a bug somewhere, 4 seconds is too much. A reduced test case would be helpful. But I wanted to note, inside a struct template, the template name (by itself) is equivalent to the current instantiation. So just returning `BindingTempl` would be equivalent, and might not trigger this problem. See if that helps. -Steve