Re: D feature request
On Monday, 5 August 2024 at 03:09:41 UTC, IchorDev wrote: On Sunday, 4 August 2024 at 10:32:38 UTC, Richard (Rikki) Andrew Cattermole wrote: Chuck it into the ideas forum. If it interests somebody, somebody else can work on it. Also sometimes if a feature is very minor you can submit a ‘feature request’ issue. "enhancement" is the bugzilla word for this. IIRC it's in the "severity" field.
Re: importC with struct name and function conflict
On Monday, 5 August 2024 at 11:02:24 UTC, Dakota wrote: This will not work for me. (huge code base I can not change and maintain) You don't have to change the code where the type is defined per se, you just need to put it in any C file that can access the C symbol. clib_helpers.c: ```C #include typedef struct S S_t; ``` app.d: ``` import clib_helpers; S_t s; ```
Re: importC with struct name and function conflict
On Saturday, 3 August 2024 at 11:55:53 UTC, Dennis wrote: On Saturday, 3 August 2024 at 05:10:37 UTC, Dakota wrote: How can I get the function and type from importC? is there a auto rename mechanism ? The most pragmatic workaround is to add a typedef to the C code: ```C int S; struct S { int a, b; }; typedef struct S S_t;// add this typedef ``` https://dlang.org/spec/importc.html#tag-symbols Thanks for tips. This will not work for me. (huge code base I can not change and maintain)
Re: D feature request
On Sunday, 4 August 2024 at 10:32:38 UTC, Richard (Rikki) Andrew Cattermole wrote: Chuck it into the ideas forum. If it interests somebody, somebody else can work on it. Also sometimes if a feature is very minor you can submit a ‘feature request’ issue.
Re: D feature request
On 04/08/2024 10:06 PM, aberba wrote: So if I have a feature request, but I don't have the necessary technical skills to draft a DIP with the implementation details, is there a process in D community to submit such a request? Other communities using GitHub have a way to file an issue which then gets labelled as a feature request and others can vote (thumbs up) on it such that with enough interest and momentum, someone with the right skills or the language maintainers can start to collect feedback and draft a DIP. Is the there such a process in D? Chuck it into the ideas forum. If it interests somebody, somebody else can work on it.
Re: Get compile time string of dmd command line options "-os" & "-target"
On Saturday, 3 August 2024 at 12:15:46 UTC, Dennis wrote: On Thursday, 1 August 2024 at 04:00:08 UTC, An Pham wrote: pragma(msg, os.stringof...?); pragma(msg, target.stringof...?); There's no built-in way, but you can define it yourself in a helper module: ```D version(Windows) enum os = "windows"; else version(AArch64) enum os = "aarch64"; else static assert(0, "unsupported os"); ``` First, I will note that "windows" and "aarch64" are not in the same category... Second, there are some already-built parts in phobos: https://dlang.org/phobos/std_compiler.html https://dlang.org/phobos/std_system.html I also went ahead and did some for arch and runtime flavor, in a project where I needed these, feel free to steal (Boost licensed): https://github.com/schveiguy/raylib-d/blob/master/install/source/app.d#L135-L154 -Steve
Re: Get compile time string of dmd command line options "-os" & "-target"
On Thursday, 1 August 2024 at 04:00:08 UTC, An Pham wrote: pragma(msg, os.stringof...?); pragma(msg, target.stringof...?); There's no built-in way, but you can define it yourself in a helper module: ```D version(Windows) enum os = "windows"; else version(AArch64) enum os = "aarch64"; else static assert(0, "unsupported os"); ```
Re: importC with struct name and function conflict
On Saturday, 3 August 2024 at 05:10:37 UTC, Dakota wrote: How can I get the function and type from importC? is there a auto rename mechanism ? The most pragmatic workaround is to add a typedef to the C code: ```C int S; struct S { int a, b; }; typedef struct S S_t;// add this typedef ``` https://dlang.org/spec/importc.html#tag-symbols
Re: importC error: can not find the #define ERR_INVALID -1
On Saturday, 3 August 2024 at 05:07:55 UTC, Dakota wrote: ```c #define ERR_SUCCESS 0 #define ERR_INVALID -1 // invalid argument ``` If the number >=0, it work. < 0 will not work. DMD64 D Compiler v2.110.0-beta.1 https://issues.dlang.org/show_bug.cgi?id=24639 -Steve
Re: How to work with long paths on Windows?
On Monday, 14 November 2022 at 18:45:40 UTC, Imperatorn wrote: On Monday, 14 November 2022 at 14:43:50 UTC, Preetpal wrote: On Monday, 14 November 2022 at 10:44:11 UTC, Imperatorn wrote: On Tuesday, 13 September 2022 at 19:54:15 UTC, Preetpal wrote: [...] Have you set longPathAware in the applications manifest? Yeah that's how I dealt with the issue. I just replied to my own question with a working example that people who might find this post can refer to: [gist](https://gist.github.com/preetpalS/2fd6c6bf05a94734f89b70b679716bf3) (see my comment in the gist for how to make it work). Don't get in the weeds, it really did my my head this path thing, but I found a way, I tried LongPath Tool Program and that sorted it.
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote: ```d Option!int something() { return None(); // Error: cannot implicitly convert expression `None()` of type `None` to `Option!int` } ``` Not D per se, but you can check Adam D. Ruppe's current work. If I am not mistaken, the thing you are asking for is already possible in the nightly release. https://dpldocs.info/this-week-in-arsd/Blog.Posted_2024_02_20.html#implicit-construction Juraj
Re: Segmentation fault while reading a file
On Thursday, 1 August 2024 at 14:42:36 UTC, Ruby The Roobster wrote: Thank you. I am not very well acquainted with the standard library, and this cleans up things significantly. Question: Is there a good guide to Phobos anywhere? I would like to learn the more commonly used algorithms / convenience functions, so I don't have to look through the docs trying to find what I want, and so that I don't keep having to re-invent the wheel when trying to work with data. I’m actually not sure. I think the best stuff is usually the examples in the documentation. If you’re searching for whether something might be in Phobos, try seeing if there’s a module that sounds right in the [index](https://dlang.org/phobos/index.html). In general I just peruse different modules until I see a function that fits what I need. It also depends on how functional you like your code, there’s a lot of map/filter/etc. stuff that I regularly write my own ad-hoc code for.
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 14:20:29 UTC, user1234 wrote: That was a general criticism of implicit construction. We are only talking about it in the context of returning from a function. The classic example is ```d struct S {int i;} function f(S s); function f(int i); unittest { f(0); } // both match ``` unless the idea would rather be to allow implicit construction only in the context of initialization. You are wasting my time. Show me how this applies to retuning from within a function.
Re: Any way to automatically convert structs on return?
Thanks everyone for the replies! I just thought it was weird that implicit construction is seemingly supported when directly initialising a struct but not in any other case. I guess it's because it's clearly less ambiguous. On Thursday, 1 August 2024 at 13:07:09 UTC, Lance Bachmeier wrote: For the program you've written, I'm happy it doesn't compile, because a lot of the time the compiler would be making buggy code compile - though I would love to have a way to do it explicitly. In this case you can change your definition of None to use alias this and it will compile: The alias this doesn't work generically, though. Either way I agree that implicit construction, if it was present in D, should not be the default, instead being opt-in like say through an `implicit this(...)` or whatever instead of C++'s horrendous implicit by default behaviour.
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 08:46:00 UTC, IchorDev wrote: P.S. You might want to put `value = void`, otherwise it’ll always be default-constructed. Doing `= void` can violate the assumptions of a destructor of T. Nullable uses a union to store T, so it can decide when to call the destructor.
Re: Segmentation fault while reading a file
On Thursday, 1 August 2024 at 07:03:04 UTC, IchorDev wrote: Hey just a heads up, you might wanna use [`readText`](https://dlang.org/library/std/file/read_text.html) and [`lineSplitter`](https://dlang.org/library/std/string/line_splitter.html) just so you don’t have to deal with file handles. ... Thank you. I am not very well acquainted with the standard library, and this cleans up things significantly. Question: Is there a good guide to Phobos anywhere? I would like to learn the more commonly used algorithms / convenience functions, so I don't have to look through the docs trying to find what I want, and so that I don't keep having to re-invent the wheel when trying to work with data.
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 10:59:03 UTC, IchorDev wrote: On Thursday, 1 August 2024 at 09:55:08 UTC, user1234 wrote: The problem would be that sorting the candidates of an overload set would be more complicated. Also in certain cases it would be less obvious to get which one is selected. Please elaborate about how this would interact with function overloads at all? That was a general criticism of implicit construction. The classic example is ```d struct S {int i;} function f(S s); function f(int i); unittest { f(0); } // both match ``` unless the idea would rather be to allow implicit construction only in the context of initialization.
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote: but this doesn't: ```d Option!int something() { return None(); // Error: cannot implicitly convert expression `None()` of type `None` to `Option!int` } ``` For the program you've written, I'm happy it doesn't compile, because a lot of the time the compiler would be making buggy code compile - though I would love to have a way to do it explicitly. In this case you can change your definition of None to use alias this and it will compile: ``` struct None { alias convert this; Option!int convert() { return Option!int(None()); } } ```
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 09:55:08 UTC, user1234 wrote: The problem would be that sorting the candidates of an overload set would be more complicated. Also in certain cases it would be less obvious to get which one is selected. Please elaborate about how this would interact with function overloads at all? The function has the same parameters, same return type, same attributes… what’s different exactly?
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 08:46:00 UTC, IchorDev wrote: [...] I’m pretty sure this is intentional to prevent ambiguity, but I can’t quite remember what the point of that is. The problem would be that sorting the candidates of an overload set would be more complicated. Also in certain cases it would be less obvious to get which one is selected.
Re: Any way to automatically convert structs on return?
Emma kirjoitti 1.8.2024 klo 10.25: This kind of prevents ergonomic code like the above. Instead you have to use a function like `Option!T None(T)() => Option!T()` and then you have to repeat yourself with `return None!int` and etc... it's quite annoying :( While this isn't exactly less verbose, I mention it because at least you don't have to write the type twice: ```D Option!int something() { return typeof(return)(None()); }
Re: Any way to automatically convert structs on return?
On Thursday, 1 August 2024 at 07:25:53 UTC, Emma wrote: This code works: ```d struct None {} struct Option(T) { bool hasSome; T value; this(None) {} this(T v) { hasSome = true; value = v; } } Option!int a = 123;// automatically constructs an Option!int from a bare int Option!int b = None(); // same as above but with None ``` but this doesn't: ```d Option!int something() { return None(); // Error: cannot implicitly convert expression `None()` of type `None` to `Option!int` } ``` This kind of prevents ergonomic code like the above. Instead you have to use a function like `Option!T None(T)() => Option!T()` and then you have to repeat yourself with `return None!int` and etc... it's quite annoying :( In C++ you may do this fairly easily, but of course there are various pitfalls because it's C++. But at least you can opt out with `explicit` most of the time. Thanks in advance! I’m pretty sure this is intentional to prevent ambiguity, but I can’t quite remember what the point of that is. You can always just write the constructor manually, but yes it’s a hassle. I wonder how open people would be to changing this restriction? P.S. You might want to put `value = void`, otherwise it’ll always be default-constructed. Phobos also has `Nullable` if you want another implementation for reference.
Re: Any way to automatically convert structs on return?
No, D does not support implicit construction. However in saying that, I will continue to argue in support of sum types when they get added to the language to support implicit construction!
Re: Segmentation fault while reading a file
Hey just a heads up, you might wanna use [`readText`](https://dlang.org/library/std/file/read_text.html) and [`lineSplitter`](https://dlang.org/library/std/string/line_splitter.html) just so you don’t have to deal with file handles. Also you can use something like [`formattedRead`](https://dlang.org/library/std/format/read/formatted_read.html) for parsing formatted floats more easily. Also please only use `in` if you have `-preview=in` and you know what it’s for. You were probably looking for `const`, because `in` with `-preview=in` is not useful for strings.
Re: Segmentation fault while reading a file
Nevermind. The segfault happened because I accidentally used the Mesh class before loading OpenGL. I don't know if it works as intended, but it no longer crashes.
Re: Segmentation fault while reading a file
On Wednesday, 31 July 2024 at 23:06:30 UTC, Ruby The Roobster wrote: ... or is `readln` bugging out because the file (backpack.obj contained in the linked .zip file) is too large? ... I don't have I compiler in hand to try your code at moment, but about your concern over the size of the file, you could try a simple object[1]: # cube.obj # g cube v 0.0 0.0 0.0 v 0.0 0.0 1.0 v 0.0 1.0 0.0 v 0.0 1.0 1.0 v 1.0 0.0 0.0 v 1.0 0.0 1.0 v 1.0 1.0 0.0 v 1.0 1.0 1.0 vn 0.0 0.0 1.0 vn 0.0 0.0 -1.0 vn 0.0 1.0 0.0 vn 0.0 -1.0 0.0 vn 1.0 0.0 0.0 vn -1.0 0.0 0.0 f 1//2 7//2 5//2 f 1//2 3//2 7//2 f 1//6 4//6 3//6 f 1//6 2//6 4//6 f 3//3 8//3 7//3 f 3//3 4//3 8//3 f 5//5 7//5 8//5 f 5//5 8//5 6//5 f 1//4 5//4 6//4 f 1//4 6//4 2//4 f 2//1 6//1 8//1 f 2//1 8//1 4//1 Matheus. [1] https://cs.wellesley.edu/~cs307/readings/obj-ojects.html
Re: copy must be const?!?
Hello A const copy ensures the copied value remains unchanged, providing safety and predictability. If the original is const, copying it as non-const could introduce unintended side effects. To modify a copied value, create a mutable copy explicitly. For file systems, copying write-protected files maintains their attributes for security reasons. To modify them, change the file permissions after copying. There isn't a direct way to tell the compiler to discard "const" or "immutable" attributes during a copy. You need to cast away constness explicitly where necessary.
Re: copy must be const?!?
On Friday, 26 July 2024 at 10:04:45 UTC, Jonathan M Davis wrote: On Friday, July 26, 2024 2:17:21 AM MDT Dom DiSc via Digitalmars-d-learn wrote: If you are not able to construct a mutable copy of a type, why on earth are you handing it over by value?!? Why not? Because you can't make a mutable copy? Structs are [...] often pseudo-reference types. [...] such types can often work just fine with const copies, because the data that's shared between objects is const or immutable. Then declare the template to take a const parameter. ```d immutable MyNonCopyableType x; MyNonCopyableType y = x; // compile error? ``` If you can't get a mutable copy of MyNonCopyableType, then yes, you'll get a compiler error. This is why you should get the same error, if the compiler cannot create a mutable parameter-by-value copy. In D, const is pretty much cancer, honestly. You do _not_ want to use it for generic code if you can possible avoid it, Why? In a template that guarantees not to modify a parameter by declaring it const, what bad can happen? because many, many types do not work with it at all. At least reading it should never be a problem. And nothing more one want to do with a const parameter. But I don't see your problem. I'm taking about situations where a const instance of a type IS ALREADY THERE (which will never be the case with any of your problematic types), and I want to have a mutable copy of them. So if the compiler would discard the const from parameters that are anyway never const, that's a NOP. All is fine. On the other hand if there is a const object, that should be an object of a type that indeed CAN provide mutable copies. This is also fine. So, where is the problem if the compiler drops "const" from the by-value copy of a parameter? in situations where a type can be logically const (or which could be const in C++), it cannot be const in D, because D's const is simply too restrictive. Sorry, but if a type is "logically const" (like a range) and you read it and thereby change it's internal state, then the template that guaranteed not to modify a parameter is very likely to destroy this internal state, and so you are much better of if this doesn't compile beforehand. Some templates are simply not meant to work with all kinds of user defined types. If you declare the parameter to be const, then there are a lot of types that won't work with the template. Fine. If I can change the internal state via read-functions, I don't want to work with that bogous type. If my intention is not to modify an object, I'm perfectly ok that I can't use may of that fake-const types functions. On top of that, in many cases, getting a mutable copy would give you completely incorrect behavior - e.g. if a range is a range over a container, you need that range to point to the elements in the container, and if the range refers to those elements as const, then getting a mutable copy of those elements would mean that they're no longer necessarily the same elements which are in the container (they might be at the point that the copy is made, but that won't necessarily stay true, whereas it would if the elements aren't copied). Ranges are a bad example, because they really cannot be const. They are completely unusable in a function not modifying them, because reading them is using them up. So a function taking a range as parameter indeed cannot guarantee not to modify it (at least not if it reads that parameters data at all). It's also the case that a lot of code simply avoids using const altogether with user-defined types Fine. Then you won't run into the problem I have. And indeed, as you weren't aware of this problem is an indicator that you are not really using const. Most anyone who tries to use D's const like you would in C++ eventually stops, because D's const is simply too different from C++'s const for that to work. No, so far the C++ code I converted to D is working fine. And it is heavily using const - but it uses it correct, despite C++ doesn't enforce that. Maybe I never used C++ the way it was meant?!? And that's especially true with templated code, since if it has to work with a large range of types, types which don't work with const are going to be on the list. Nope. Constraints work very good in guaranteeing that such types are NOT on the list of types the template is working with. On top of that, some common D idioms (e.g. ranges) can't work with const, because they require mutation (a range can have const elements, but the range itself cannot be const). Jup. If a template takes a range, it should not take it const. But I also won't take a range by value. As whatever I do will modify the range, why should I pretend to work on a copy of it? Take it by ref!
Re: Libraries for Model Loading
On Thursday, 18 July 2024 at 14:02:09 UTC, Ruby The Roobster wrote: Is there a good package available that can load models, Wavefront .obj files in particular? I tried to use the existing bindings to old versions of Assimp, but I could not get Assimp itself to build on my machine. Thanks in advance. I would bind to Assimp using [ImportC](https://dlang.org/spec/importc.html).
Re: copy must be const?!?
On Friday, July 26, 2024 2:17:21 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > On Thursday, 25 July 2024 at 13:07:03 UTC, Jonathan M Davis wrote: > > On Thursday, July 25, 2024 6:00:58 AM MDT Dom DiSc via > > > >> But a parameter given by value is ALWAYS a copy. > > > > It has to be a _full_, independent copy. If you're talking > > about integer types, that's a non-issue, but if you're talking > > about types with any indirections, it becomes a big issue. If > > the type contains any pointers, dynamic arrays, class > > references, etc. then the copy can't be mutable unless you're > > dealing with a struct with a copy constructor that does a deep > > copy of all of the member variables. So, in the general case, > > you cannot copy a value and expect to get a mutable result. > > If you are not able to construct a mutable copy of a type, why on > earth are you handing it over by value?!? Why not? Structs are almost never reference types (since that would mean only holding a single pointer or class reference), but they're often pseudo-reference types. Something as simple as having a dynamic array or string in your struct means that you can't get a mutable copy without duplicating memory (and depending on the types involved, you can't even do that), but such types can often work just fine with const copies, because the data that's shared between objects is const or immutable. > And what do you do with normal assignment with such a type? You can't assign to variables which are const or immutable, so assignment won't work. But plenty of generic code is written which never assigns to a variable and works just fine with const objects being copied. > ```d > immutable MyNonCopyableType x; > MyNonCopyableType y = x; // compile error? > ``` If you can't get a mutable copy of MyNonCopyableType, then yes, you'll get a compiler error. > Also, if you need no writeable copy in your template, why don't > you declare it with const parameter? > Maybe you need this behaviour often and so don't want to type the > 7 extra characters. But I think, it is a bad default to create > const copies of const objects, and to make it worse the language > does not allow you to change this default (would need a new > keyword "mutable" to explicitly request to get a mutable copy). In D, const is pretty much cancer, honestly. You do _not_ want to use it for generic code if you can possible avoid it, because many, many types do not work with it at all. Unlike C++'s const, it's transitive and has no backdoors (at least not without violating the type system), making it very easy to end up in situations where even when a type can be logically const (or which could be const in C++), it cannot be const in D, because D's const is simply too restrictive. When something is const in D, it means it. There are types when those guarantees are useful, but often, the end result is that you're better off avoding const with any user-defined types, because const is simply too restrictive. And if a type has any indirections in it, the odds are extremely low that it's going to be possible to get a mutable copy from a const object. As such, unless you're dealing with a specific subset of types where you know that const will work (e.g. if you're only dealing with integer types), then you usually don't want to use const at all with templates. Templates will often work with const types just fine when those types are designed to work with const, but if the template require const, then you're going to end up with a lot of types that won't work with that template, because they won't work with const (and in many cases, cannot be made to work with const). > > It's most definitely not a bug that IFTI (Implicit Function > > Template Instantiation) instantiates the template with the > > exact type that it's given. In the general case, that's what > > you want - particularly since many, many types (probably the > > vast majority of types) cannot be const or immutable and then > > result in a mutable copy when they're copied. > > If you need this, declare the parameter const. > The default should be a mutable copy (and a compile error if > creating a mutable copy is not possible). If you declare the parameter to be const, then there a lot of types that won't work with the template. D's const is just too restrictive for it to make any sense to use it unless you're specifically restricting your code to a subset of types which are designed to work with it. With generic code, it's usually the case that the decision on whether const should be used needs to be left up to the caller if you want any chance of the code working with a large range of types. Using const parameters with function templates can work quite well with the primitive types, but with user-defined types, it tends to become untenable quite quickly - especially if you're writing library code that will be used by a whole bunch of people writing types that you don't control. > > That really only works
Re: Libraries for Model Loading
On Thursday, 18 July 2024 at 14:02:09 UTC, Ruby The Roobster wrote: Is there a good package available that can load models, Wavefront .obj files in particular? I tried to use the existing bindings to old versions of Assimp, but I could not get Assimp itself to build on my machine. Thanks in advance. Not that I know of, but Wavefront .obj files are pretty simple. You could translate Assimp into D, or make your own simple library for loading them.
Re: copy must be const?!?
On Thursday, 25 July 2024 at 13:07:03 UTC, Jonathan M Davis wrote: On Thursday, July 25, 2024 6:00:58 AM MDT Dom DiSc via But a parameter given by value is ALWAYS a copy. It has to be a _full_, independent copy. If you're talking about integer types, that's a non-issue, but if you're talking about types with any indirections, it becomes a big issue. If the type contains any pointers, dynamic arrays, class references, etc. then the copy can't be mutable unless you're dealing with a struct with a copy constructor that does a deep copy of all of the member variables. So, in the general case, you cannot copy a value and expect to get a mutable result. If you are not able to construct a mutable copy of a type, why on earth are you handing it over by value?!? And what do you do with normal assignment with such a type? ```d immutable MyNonCopyableType x; MyNonCopyableType y = x; // compile error? ``` Also, if you need no writeable copy in your template, why don't you declare it with const parameter? Maybe you need this behaviour often and so don't want to type the 7 extra characters. But I think, it is a bad default to create const copies of const objects, and to make it worse the language does not allow you to change this default (would need a new keyword "mutable" to explicitly request to get a mutable copy). Therefore I consider the current behaviour a bug. It's most definitely not a bug that IFTI (Implicit Function Template Instantiation) instantiates the template with the exact type that it's given. In the general case, that's what you want - particularly since many, many types (probably the vast majority of types) cannot be const or immutable and then result in a mutable copy when they're copied. If you need this, declare the parameter const. The default should be a mutable copy (and a compile error if creating a mutable copy is not possible). That really only works with very simple types with no indirections. Sorry, but no. It is possible to write copy constructors that create mutable copies for pretty much any type. It may for bad designed types be not very fast, but if you are able to create a mutable instance of a type, it should also be possible to create a mutable copy. Now, the fact that code such as ``` void fun(T : const U, U)(U x) if(is(immutable T == immutable U)) { ... } ``` or code like ``` void fun(T)(Unqual!T x) {} ``` doesn't work with IFTI and requires explicit instantation is definitely a deficiency in IFTI's current capabilities. So you basically agree that it is a missing feature (if not a bug). we very much want ``` void fun(T)(T x) {} ``` to be instantiated as fun!(const Foo) if it's passed a const Foo. No. this is a bad default. If you want this, write ```d void fun(T)(const(T) x) {} ``` I know, it's seven characters more to type, but I think they are definitely worth it.
Re: copy must be const?!?
On Friday, 26 July 2024 at 02:34:12 UTC, Andy Valencia wrote: On Thursday, 25 July 2024 at 13:07:03 UTC, Jonathan M Davis wrote: It's most definitely not a bug that IFTI (Implicit Function Template Instantiation) instantiates the template with the exact type that it's given. The "principle of least astonishment" certainly supports this behavior. To check my understanding, I forced the type of instantiation: writeln(test2!int(v)); and that worked as I expected. Andy Yes, it's pretty much the same "solution" but on the caller side instead of the callee. But it works only for types like int or which provides a constructor that generates a mutable copy.
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 15:40:29 UTC, Nick Treleaven wrote: On Thursday, 25 July 2024 at 15:06:35 UTC, IchorDev wrote: I think your function most likely has a safe interface, so it can be marked as `@trusted` as-per [the spec](https://dlang.org/spec/function.html#safe-interfaces). Just to mention that with -dip1000, taking the address of variables is allowed, so the function would be @safe. Thanks for all the good answers. So the solution for me is -dip1000. Marking something @trusted that the compiler should be able to check to be @safe is not so good, as it increases the review effort significantly and unneccessarily.
Re: What is an rvalue constructor?
On Thursday, July 25, 2024 4:48:06 PM MDT Quirin Schroll via Digitalmars-d- learn wrote: > It seems one can’t have one in a struct together with a copy > constructor, but what is it? When is it called? What is it for? An rvalue constructor is a constructor that takes the same type as the struct that it's in, but it takes it as an rvalue (whereas a copy constructor takes it as an lvalue). So, if you have struct MyType { this(MyType rhs) { ... } } then you can do stuff like MyType(getMyType()) where getMyType returns a MyType, whereas if you don't have such a constructor, you can't. This is particularly useful in generic code. For instance, if you have an algebraic type that takes a whole bunch of types, you can do something like this(T)(T rhs) { ... } and then you can happily call MyType(getMyType()) where getMyType() returns a MyType. However, without that rvalue constructor, then MyType(getMyType()) can't be done. So, if MyType has a copy constructor, you're forced to check for MyType with such a templated constructor, e.g. this(T)(T rhs) if(!is(immutable T == immutable MyType)) { ... } and you need to create a wrapper function to be able to generically construct a MyType, e.g. MyType make(T)(T rhs) { static if(is(immutable T == immutable MyType)) return rhs; else return MyType(rhs); } Of course, for most code, you really don't need to be able to construct a struct from its own type, so in many cases, you really don't need an rvalue constructor, but when you do need it, the fact that copy constructors don't allow them is pretty annoying. With the current DIP proposal for move constructors, an rvalue constructor would become a move constructor, though since it's not necessarily obvious that that's what it is, and such constructors already exist as normal constructors, there are some objections to making such a change. But of course, we'll have to see what ultimately happens with that. - Jonathan M Davis
Re: Prevent self-comparison without taking the address
On Thursday, July 25, 2024 4:50:04 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > I have copied some source from C++, where the following pattern > is common (operator== already renamed): > > ```d > @safe: > struct S > { > bool opEquals(const ref S x) const > { >if(==) return true; >... > } > } > ``` > > Can I replace this pattern with ```(x is this)``` or are there > some special cases where this doen't work? If you want to do that, that's basically what you would need to do. However, I've never seen anyone do that with structs in D. They're usually put on the stack and passed around by value. They are of course sometimes passed by reference, but that's usually going to be to a variable on the stack, making comparing addresses kind of pointless, since you'd usually need to be doing something like x == x to end up comparing the same object against itself. Pretty much the only time that something like this might make sense is when you're dealing with pointers to structs, which of course is done sometimes, but it's much less common than it would be in C++, since D separates classes and structs. And classes already do that check with ==, since it's lowered to a free function, opEquals, before calling the class' opEquals, and it does stuff like compare the address of the class reference and compare against null. Either way, the fact that the this member for structs is a reference rather than a pointer means that if you want to compare addresses, you'll need to take the addresses - which won't be @safe without DIP 1000, because taking the address of a local variable is not @safe without the tracking that DIP 1000 adds via scope (since without the extra checks, you could easily take that address and pass it around, letting it escape the lifetime of the reference). - Jonathan M Davis
Re: copy must be const?!?
On Thursday, 25 July 2024 at 13:07:03 UTC, Jonathan M Davis wrote: On Thursday, July 25, 2024 6:00:58 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > And no, in general, you don't want to be casting away const > or immutable. There are cases where it can work (e.g. if the > cast does a copy, which it would with an integer type) But a parameter given by value is ALWAYS a copy. So if a copy is done, the copy should be mutable. I can't see why that should ever be a problem. The compiler should never create new values const or immutable unless explicitly advised to do so. It has to be a _full_, independent copy. If you're talking about integer types, that's a non-issue, but if you're talking about types with any indirections, it becomes a big issue. If the type contains any pointers, dynamic arrays, class references, etc. then the copy can't be mutable unless you're dealing with a struct with a copy constructor that does a deep copy of all of the member variables. So, in the general case, you cannot copy a value and expect to get a mutable result. E.g. ```d void fun(myType x) { } ``` called with immutable object should create a mutable x, because ```d myType x = immutableObject; ``` will also create a mutable x. If I want an immutable x, i can do ```d immutable myType = immutableObject; ``` ```d void fun(T)(T x) if (is(Unqual!T==myType)) { } ``` should also create a mutable x, for the same reason, because if I want an immutable x, I can do ```d void fun(T)(immutable(T) x) if (is(Unqual!T==myType)) { } ``` Therefore I consider the current behaviour a bug. It's most definitely not a bug that IFTI (Implicit Function Template Instantiation) instantiates the template with the exact type that it's given. In the general case, that's what you want - particularly since many, many types (probably the vast majority of types) cannot be const or immutable and then result in a mutable copy when they're copied. That really only works with very simple types with no indirections. In the general case, there is no expectation whatsoever that it's going to be possible to get a mutable copy from a const or immutable variable, and generic code that expects that to work is very likely to run into problems very quickly. Now, the fact that code such as ```d void fun(T : const U, U)(U x) if(is(immutable T == immutable U)) { ... } ``` or code like ```d void fun(T)(Unqual!T x) { } ``` doesn't work with IFTI and requires explicit instantation is definitely a deficiency in IFTI's current capabilities, but in the general case, we very much want ```d void fun(T)(T x) {} ``` to be instantiated as `fun!(const Foo)` if it's passed a `const Foo`. For some types, we _would_ like the ability to tell the compiler to implicitly instantiate function templates with a tail-const version similar to what we get with dynamic arrays, but that really only makes sense for certain types such as ranges. But either way, it would cause quite a few problems if IFTI started instantiating templates in general with mutable instead of the actual type that it's given, because it's extremely common that const and immutable types cannot be converted to mutable. It’s wild how C++ and D disagree on this one. In C++, a copy constructor must produce a mutable copy. Now, C++ and D disagree on what `const` means and therefore what counts as a mutable copy. But, and this is the key takeaway, C++ never infers `const` on a copy. Never. It does infer `const` on a reference, of course. Nothing of this is out of reach for D. A type for which const objects can’t be copied to initialize a mutable one simply isn’t copyable and therefore can’t be passed by value. A type for which const rvalues can’t be used to initialize a mutable variable aren’t movable. C++ solves this by binding values by universal reference: ```cpp template void f(T&&); ``` This `f` eats anything. For rvalues of type `X`, `T` is inferred `X`, the rvalue is materialized in the caller and passed by (rvalue) reference to `f`. For lvalues, `T` is inferred `X&` so that the parameter becomes of type `(T&)&&` which is the same as `T&`, thus `f` ends up binding the value by (lvalue) reference. D doesn’t have that. In that regard, D is approximately where C++ was before C++11. D’s `ref` can’t bind lvalues, which is probably a good thing. In one of my recent DIP Ideas posts, I outlined `@universal ref` and `@rvalue ref`. The best D can do today is this: ```d void f(T)(auto ref T); ``` For lvalues, that’s great. Nothing to complain. Rvalues should be moved into the parameter. For that, the type must support moves, which most types do, but the compiler doesn’t check if the move could give you a mutable object. Even if it can, the compiler will give you a qualified parameter. Because of D’s transitive qualifiers, a mutable copy may not be possible. In that case, we’d have two options: Say the type isn’t copyable, or
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 15:06:35 UTC, IchorDev wrote: I think your function most likely has a safe interface, so it can be marked as `@trusted` as-per [the spec](https://dlang.org/spec/function.html#safe-interfaces). Just to mention that with -dip1000, taking the address of variables is allowed, so the function would be @safe.
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 14:05:50 UTC, Dom DiSc wrote: As he said: no. It's only true for @safe: No they did not, they specifically said that my assertion holds true for all other [function attributes](https://dlang.org/spec/attribute.html#function-attributes). This does not tell me anything about other attributes like `align`, `deprecated`, `@__future`, linkage attributes, visibility attributes, mutability attributes, shared storage attributes, `@system` variables, or UDAs. But that doesn't answer my question. Your question was ‘Can I replace this pattern with `(x is this)`’. The answer is no. You said it is not the same. But then: is there another way to translate the C++ pattern in a @safe way? This is the first time you have mentioned this intention with words. I’m not a mind reader. I think your function most likely has a safe interface, so it can be marked as `@trusted` as-per [the spec](https://dlang.org/spec/function.html#safe-interfaces). Let’s go through the checklist: - undefined behaviour? Nothing undefined about comparing two numbers. - creates unsafe values accessible by safe code? No it only returns a Boolean. - unsafe aliasing accessible by safe code? No aliasing whatsoever.
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 13:20:59 UTC, IchorDev wrote: On Thursday, 25 July 2024 at 13:01:53 UTC, Dennis wrote: That's true for the other function attributes, but `@safe:` actually does penetrate scopes The spec doesn’t mention this at all! Is this the case for any other `AttributeSpecifier` declarations? As he said: no. It's only true for @safe: But that doesn't answer my question. You said it is not the same. But then: is there another way to translate the C++ pattern in a @safe way?
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 13:01:53 UTC, Dennis wrote: That's true for the other function attributes, but `@safe:` actually does penetrate scopes The spec doesn’t mention this at all! Is this the case for any other `AttributeSpecifier` declarations?
Re: copy must be const?!?
On Thursday, July 25, 2024 6:00:58 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > > And no, in general, you don't want to be casting away const or > > immutable. There are cases where it can work (e.g. if the cast > > does a copy, which it would with an integer type) > > But a parameter given by value is ALWAYS a copy. > So if a copy is done, the copy should be mutable. I can't see why > that should ever be a problem. The compiler should never create > new values const or immutable unless explicitly advised to do so. It has to be a _full_, independent copy. If you're talking about integer types, that's a non-issue, but if you're talking about types with any indirections, it becomes a big issue. If the type contains any pointers, dynamic arrays, class references, etc. then the copy can't be mutable unless you're dealing with a struct with a copy constructor that does a deep copy of all of the member variables. So, in the general case, you cannot copy a value and expect to get a mutable result. > E.g. > ```d > void fun(myType x) { } > ``` > > called with immutable object should create a mutable x, because > > ```d >myType x = immutableObject; > ``` > > will also create a mutable x. If I want an immutable x, i can do > > ```d >immutable myType = immutableObject; > ``` > > ```d > void fun(T)(T x) if (is(Unqual!T==myType)) { } > ``` > > should also create a mutable x, for the same reason, because if I > want an immutable x, I can do > > > ```d > void fun(T)(immutable(T) x) if (is(Unqual!T==myType)) { } > ``` > > Therefore I consider the current behaviour a bug. It's most definitely not a bug that IFTI (Implicit Function Template Instantiation) instantiates the template with the exact type that it's given. In the general case, that's what you want - particularly since many, many types (probably the vast majority of types) cannot be const or immutable and then result in a mutable copy when they're copied. That really only works with very simple types with no indirections. In the general case, there is no expectation whatsoever that it's going to be possible to get a mutable copy from a const or immutable variable, and generic code that expects that to work is very likely to run into problems very quickly. Now, the fact that code such as void fun(T : const U, U)(U x) if(is(immutable T == immutable U)) { ... } or code like void fun(T)(Unqual!T x) { } doesn't work with IFTI and requires explicit instantation is definitely a deficiency in IFTI's current capabilities, but in the general case, we very much want void fun(T)(T x) {} to be instantiated as fun!(const Foo) if it's passed a const Foo. For some types, we _would_ like the ability to tell the compiler to implicitly instantiate function templates with a tail-const version similar to what we get with dynamic arrays, but that really only makes sense for certain types such as ranges. But either way, it would cause quite a few problems if IFTI started instantiating templates in general with mutable instead of the actual type that it's given, because it's extremely common that const and immutable types cannot be converted to mutable. - Jonathan M Davis
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 11:46:29 UTC, IchorDev wrote: Also just so you know, placing `@safe:` there will not affect the contents of `S`. It has to be inside the struct declaration to affect its contents. That's true for the other function attributes, but `@safe:` actually does penetrate scopes
Re: copy must be const?!?
On Thursday, 25 July 2024 at 08:42:29 UTC, Jonathan M Davis wrote: It's not a cast. Casts in D use the keyword, cast - e.g. return --(cast(T)x); Rather, Dennis' solution is constructing a value of the given type. For it to work, T must be constructible from an immutable T - which works with integer types but won't actually work with most types. Ah! Good, so at least here I can use it. Fine. Should also wor if the type has an appropriate constructor, e.g. a copy constructor that takes a const parameter and returns a mutable copy (as I would expect every copy constructor to do), so at least in code I write, I will never have a problem. It also won't work with pointer types or reference types, since those would need new when constructing them. Of course. For those that also wouldn't work for functions instead of templates. And no, in general, you don't want to be casting away const or immutable. There are cases where it can work (e.g. if the cast does a copy, which it would with an integer type) But a parameter given by value is ALWAYS a copy. So if a copy is done, the copy should be mutable. I can't see why that should ever be a problem. The compiler should never create new values const or immutable unless explicitly advised to do so. E.g. ```d void fun(myType x) { } ``` called with immutable object should create a mutable x, because ```d myType x = immutableObject; ``` will also create a mutable x. If I want an immutable x, i can do ```d immutable myType = immutableObject; ``` ```d void fun(T)(T x) if (is(Unqual!T==myType)) { } ``` should also create a mutable x, for the same reason, because if I want an immutable x, I can do ```d void fun(T)(immutable(T) x) if (is(Unqual!T==myType)) { } ``` Therefore I consider the current behaviour a bug.
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 10:50:04 UTC, Dom DiSc wrote: ```d @safe: struct S{ ``` Also just so you know, placing `@safe:` there will not affect the contents of `S`. It has to be inside the struct declaration to affect its contents.
Re: Prevent self-comparison without taking the address
On Thursday, 25 July 2024 at 10:50:04 UTC, Dom DiSc wrote: Can I replace this pattern with ```(x is this)``` or are there some special cases where this doen't work? When a parameter is `ref` it is treated as a value type (i.e. it has value semantics), even though it is a reference; therefore an identity expression of `x is this` will check whether the bits in `x` and `this` are identical: https://dlang.org/spec/expression.html#identity_expressions Using the reference operator (`&`) on something that is `ref` returns its pointer form, which is what you want to compare. TL;DR: No, `is` will compare the struct data not the pointers.
Re: copy must be const?!?
On Thursday, July 25, 2024 12:50:04 AM MDT Dom DiSc via Digitalmars-d-learn wrote: > On Wednesday, 24 July 2024 at 15:40:28 UTC, Dennis wrote: > >> Is there a way to tell the compiler that it should discard > >> "const" and "immutable" if it needs to create a copy? > >> Unqual!T doesn't work :-( > > > > When you add `const` or `immutable` before the template type > > parameter, it will infer T as simply `int`: > > > > ```D > > T test2(T)(immutable T x) { return --T(x); } > > ``` > > Woah. Is this @safe? > Ok, I know this is a fresh copy, that hopefully doesn't go to > non-volatile memory, but I'm always sceptical casting away const. It's not a cast. Casts in D use the keyword, cast - e.g. return --(cast(T)x); Rather, Dennis' solution is constructing a value of the given type. For it to work, T must be constructible from an immutable T - which works with integer types but won't actually work with most types. It also won't work with pointer types or reference types, since those would need new when constructing them. And no, in general, you don't want to be casting away const or immutable. There are cases where it can work (e.g. if the cast does a copy, which it would with an integer type), but if you ever cast away const or immutable and mutate the result when the result isn't a fully independent copy, you're violating the type system. Usually, in cases like this one, you'd just require that the caller pass a type that's mutable, forcing the caller to do whatever is appropriate to get a mutable copy rather than trying to do such a copy internally, but Dennis' solution will work with some types. That could be done by just letting the caller get an error (like you were), or the more user-friendly solution is to use a template constraint that checks that the operations that you need to use actually work with the given type, e.g. T test2(T)(T x) if(is(typeof(--x))) { return --x; } So, then you get an error about the template constraint failing rather than the template simply not being able to be instantiated. And aside from the issue of const, that's arguably a better solution anyway, since then it will catch any type which doesn't work with the decrement operator. Then if you wanted to pass a const int, some of the options would be test2(int(i)); test2(cast(int)(i)); test2!int(i); // works, because the compiler will copy i In general though, you can't currently pass a const type to a templated function and then have it instantiated without const. The only types that that currently works with are dynamic arrays. Templated functions which take dynamic arrays are instantiated with the same type you get when slicing them, which means that const gets removed from the array itself but not from the element type, e.g. const int[] arr; static assert(is(typeof(arr) == const(int[]))); static assert(is(typeof(arr[]) == const(int)[])); So, if you have something like immutable string foo = "hello"; and you pass it to a templated function, the type will be treated as string, whereas with a user-defined type - or with any built-in types which aren't dynamic arrays - the templated function is instantiated with exactly the type that you pass it. - Jonathan M Davis
Re: copy must be const?!?
On Wednesday, 24 July 2024 at 15:40:28 UTC, Dennis wrote: Is there a way to tell the compiler that it should discard "const" and "immutable" if it needs to create a copy? Unqual!T doesn't work :-( When you add `const` or `immutable` before the template type parameter, it will infer T as simply `int`: ```D T test2(T)(immutable T x) { return --T(x); } ``` Woah. Is this @safe? Ok, I know this is a fresh copy, that hopefully doesn't go to non-volatile memory, but I'm always sceptical casting away const.
Re: Array concatenation & optimisation
On Monday, 22 July 2024 at 12:03:33 UTC, Quirin Schroll wrote: this has no effect on whether the function is `@nogc`. That is a highly amusing (but obviously understandable) logical contradiction that I’d never considered before. ‘Sometimes you can’t use non-GC code in `@nogc` code.’
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 10:33:38 UTC, Nick Treleaven wrote: On Sunday, 21 July 2024 at 05:43:32 UTC, IchorDev wrote: Does this mean that array literals are *always* separately allocated first, or is this usually optimised out? My understanding is that they do not allocate if used to initialize or assign a static array. That includes passing an array literal as an argument to a static array function parameter. A scope slice can also be initialized from an array literal in @nogc code: https://dlang.org/changelog/2.102.0.html#dmd.scope-array-on-stack Another (related) case that doesn't heap allocate is when passing a literal as a scope parameter: ```d void main() @nogc { f([1,2]); } void f(scope int[]) @nogc; ``` I will look at adding these cases to the spec.
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 05:43:32 UTC, IchorDev wrote: Obviously when writing optimised code it is desirable to reduce heap allocation frequency. With that in mind, I'm used to being told by the compiler that I can't do this in `@nogc` code: ```d void assign(ref int[4] a) @nogc{ a[] = [1,3,6,9]; //Error: array literal in `@nogc` function `assign` may cause a GC allocation } ``` 'may cause' a GC allocation Does this mean that array literals are *always* separately allocated first, or is this usually optimised out? For instance, will this example *always* allocate a new dynamic array for the array literal, and then append it to the existing one, even in optimised builds? Optimization is unrelated to language semantics, except for what optimizations the language semantics allow for. Even if an allocation is optimized away, if the language semantics don’t require this optimization (which means it’s no optimization actually), it must pretend it’s not happening as far as diagnostics etc. are concerned. My mental model of array literals is that array literals have their own, internal type. Think of `__arrayLiteral!(T, n)`. If you ask an array literal its type (e.g. using `typeof`), it’ll say `T[]`. But when you use it to initialize a static array, it simply behaves differently than a `T[]` because it just isn’t one. The madness about this is that even casts don’t affect the typing. ```d void main() @nogc { int x; enum int[] xs = [1,2,3]; int[4] ys = cast(int[])(xs ~ x); // good int[4] zs = (b ? xs : xs) ~ x; // error } ``` Here, neither the explicit type `int[]` for `xs` or the cast (you can remove any subset of them) make it so that the assignment isn’t `@nogc`. The whole `__arrayLiteral!(T, n)` is after some semi-constant folding that only applies to the length. In no way is `xs ~ x` a compile-time constant as `x` is a run-time value. However, if you use `(b ? xs : xs)` instead of plain `xs` with a run-time boolean `b`, the language doesn’t see it as an array with compile-time-known length, and thus requires allocation. In your example, you’re not assigning an array literal to a static array as far as the type system is concerned. The left-hand side is `a[]`, which has type `int[]`. So, as far as the type system is concerned, you assign an array literal to an `int[]`, and that requires allocating the literal on the GC heap, rendering the function non-`@nogc`. If the optimizer figures out that all of this ends up just putting some values in some static array and it removes the allocation, this has no effect on whether the function is `@nogc`.
Re: Using FFI to write a std::string to a buffer passed in from D
On Sunday, 21 July 2024 at 15:31:47 UTC, Johan wrote: On Sunday, 21 July 2024 at 13:35:46 UTC, Troy wrote: void create(void* b) { std::string s = "engineer again"; *(std::string*)(b) = s;// Segfault here } You have to construct an empty string object first in location `b` (emplacement new). Then you can assign to it as you do. The `=` calls `operator=` which assumes that both operands (`b` and `s`) are both fully constructed and valid `std::string` objects. Without emplacement new, `b` is not a valid `std::string` object (random byte buffer returned by `malloc`). Hope that works, Johan Using placement new like you suggested seems to have solved my issue perfectly. I would never have never thought of that on my own. Thanks for the suggestion!
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 15:41:50 UTC, Johan wrote: https://d.godbolt.org/z/sG5Kancs4 The short array is not dynamically allocated (it's allocated on the stack, or for larger arrays it will be a hidden symbol in the binary image), even at `-O0` (i.e. `-O` was not passed). Wow thanks, that's an impressive find! I didn't know LDC was quite so clever either.
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 10:33:38 UTC, Nick Treleaven wrote: Just to mention that if you assign to the static array it works: `a = [1,3,6,9];`. Bonkers. `array[]` is meant to be 'all of `array` as a slice', so you'd think that's how you copy a slice to a static array, but no! My understanding is that they do not allocate if used to initialize or assign a static array. That includes passing an array literal as an argument to a static array function parameter. D is pretty eager to make array literals into slices; thus have I developed a general distrust for using array literals in the vicinity of static arrays. Case and point: A scope slice can also be initialized from an array literal in @nogc code: https://dlang.org/changelog/2.102.0.html#dmd.scope-array-on-stack But assigning a literal to a scope slice is not allowed in @nogc code. If there is enough spare capacity in a's allocation, no allocation will occur. Obviously for a long array literal, the benefit of knowing its length upfront (and the readability) would probably outweigh the allocation; but for small array literals, is splitting them into separate concatenations going to yield faster code, or will I waste my time and screen space? Note that concatenation always allocates: Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array https://dlang.org/spec/arrays.html#array-concatenation Thank you for all this info! P.S. I am mostly addressing LDC2 & GDC's output, since I am aware that DMD's optimisations are usually minimal. While people may say that on the forum, dmd's optimizer does actually do data flow analysis: https://forum.dlang.org/post/uqhgoi$31a7$1...@digitalmars.com People frequently come here to complain that 'D is slow' when they're using DMD, and often not even using `-O`. The responses will then usually contain some version of 'don't use DMD to generate optimised code'.
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 05:43:32 UTC, IchorDev wrote: Does this mean that array literals are *always* separately allocated first, or is this usually optimised out? Not always allocated, see your example below. I don't quite know what the heuristic is for allocation or not... For instance, will this example *always* allocate a new dynamic array for the array literal, and then append it to the existing one, even in optimised builds? ```d void append(ref int[] a){ a ~= [5, 4, 9]; } ``` https://d.godbolt.org/z/sG5Kancs4 The short array is not dynamically allocated (it's allocated on the stack, or for larger arrays it will be a hidden symbol in the binary image), even at `-O0` (i.e. `-O` was not passed). -Johan
Re: Using FFI to write a std::string to a buffer passed in from D
On Sunday, 21 July 2024 at 13:35:46 UTC, Troy wrote: void create(void* b) { std::string s = "engineer again"; *(std::string*)(b) = s;// Segfault here } You have to construct an empty string object first in location `b` (emplacement new). Then you can assign to it as you do. The `=` calls `operator=` which assumes that both operands (`b` and `s`) are both fully constructed and valid `std::string` objects. Without emplacement new, `b` is not a valid `std::string` object (random byte buffer returned by `malloc`). Hope that works, Johan
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 10:33:38 UTC, Nick Treleaven wrote: For instance, will this example *always* allocate a new dynamic array for the array literal, and then append it to the existing one, even in optimised builds? ```d void append(ref int[] a){ a ~= [5, 4, 9]; } ``` If there is enough spare capacity in a's allocation, no allocation will occur. Sorry, I see what you mean. I've compared the -vasm output (without -O) for that function and this one: ```d void append(ref int[] a){ enum e = [5, 4, 9]; a ~= e; } ``` The ASM output is the same. If you use runtime value elements I'm not sure but I think there's still no heap allocation. I'm not good at reading ASM though.
Re: Tuple deconstruction in Phobos
On Sunday, 21 July 2024 at 04:05:52 UTC, IchorDev wrote: On Saturday, 20 July 2024 at 20:48:29 UTC, Nick Treleaven wrote: Instead of the `tie` assignment, you can just do: ```d import std.meta; AliasSeq!(y, x) = tupRetFn().expand; ``` And here I was trying to use comma expressions for this like a buffoon! Of course they didn't work, but I'm pleasantly surprised that using a sequence does. I think The lvalue sequence docs in template.dd were only updated in the last year to mention sequence assignment. I should really PR `std.typecons` to add a couple of examples of this, because I think a lot of people will have overlooked it. Good idea.
Re: Array concatenation & optimisation
On Sunday, 21 July 2024 at 05:43:32 UTC, IchorDev wrote: Obviously when writing optimised code it is desirable to reduce heap allocation frequency. With that in mind, I'm used to being told by the compiler that I can't do this in `@nogc` code: ```d void assign(ref int[4] a) @nogc{ a[] = [1,3,6,9]; //Error: array literal in `@nogc` function `assign` may cause a GC allocation } ``` Just to mention that if you assign to the static array it works: `a = [1,3,6,9];`. 'may cause' a GC allocation Does this mean that array literals are *always* separately allocated first, or is this usually optimised out? My understanding is that they do not allocate if used to initialize or assign a static array. That includes passing an array literal as an argument to a static array function parameter. A scope slice can also be initialized from an array literal in @nogc code: https://dlang.org/changelog/2.102.0.html#dmd.scope-array-on-stack But assigning a literal to a scope slice is not allowed in @nogc code. For instance, will this example *always* allocate a new dynamic array for the array literal, and then append it to the existing one, even in optimised builds? ```d void append(ref int[] a){ a ~= [5, 4, 9]; } ``` If there is enough spare capacity in a's allocation, no allocation will occur. Obviously for a long array literal, the benefit of knowing its length upfront (and the readability) would probably outweigh the allocation; but for small array literals, is splitting them into separate concatenations going to yield faster code, or will I waste my time and screen space? Note that concatenation always allocates: Concatenation always creates a copy of its operands, even if one of the operands is a 0 length array https://dlang.org/spec/arrays.html#array-concatenation P.S. I am mostly addressing LDC2 & GDC's output, since I am aware that DMD's optimisations are usually minimal. While people may say that on the forum, dmd's optimizer does actually do data flow analysis: https://forum.dlang.org/post/uqhgoi$31a7$1...@digitalmars.com
Re: Tuple deconstruction in Phobos
On Saturday, 20 July 2024 at 20:48:29 UTC, Nick Treleaven wrote: Instead of the `tie` assignment, you can just do: ```d import std.meta; AliasSeq!(y, x) = tupRetFn().expand; ``` And here I was trying to use comma expressions for this like a buffoon! Of course they didn't work, but I'm pleasantly surprised that using a sequence does. I should really PR `std.typecons` to add a couple of examples of this, because I think a lot of people will have overlooked it. I honestly thought there was no way to do this in D for the longest time until I saw some C++ code using `std::tie` and I realised that obviously the same thing is doable in D using `opAssign`, and then refined it to use UFCS because the syntax `Tie!(y,x)()` was a bit clunky.
Re: Tuple deconstruction in Phobos
On Saturday, 20 July 2024 at 14:02:21 UTC, IchorDev wrote: Why does Phobos not provide a method to easily deconstruct tuples? Here's a trivial implementation: ... tie!(y, x) = tupRetFn().expand; writeln(x,", ",y); } ``` Not having this is like if Phobos didn't have `AliasSeq`. Yes you can make your own, but it's wasteful boilerplate. Instead of the `tie` assignment, you can just do: ```d import std.meta; AliasSeq!(y, x) = tupRetFn().expand; ```
Re: Unexpected range assignment behaviour
On Friday, July 19, 2024 12:02:55 PM MDT H. S. Teoh via Digitalmars-d-learn wrote: > On Fri, Jul 19, 2024 at 05:48:37PM +, Dennis via Digitalmars-d-learn wrote: > > On Friday, 19 July 2024 at 17:20:22 UTC, matheus wrote: > > > couldn't this case for example be caught during the compiling time? > > > > The RangeError is only thrown when at runtime, the key doesn't exist, > > so that can't be caught. The real problem is implicit slicing of > > static arrays, which I'm not a fan of, but removing it is a breaking > > change. So perhaps Associative Arrays should be enhanced to create > > keys on slice assignment. > > IMO, implicit slicing of static arrays ought to be killed with fire. > This is not the first time it has caused problems. In the past it used > to cause issues with the implicit slice escaping the scope of the > original static array, leading to dangling pointers and subsequent > memory corruption / UB. With -dip1000 the situation has somewhat > improved, but not entirely. It still causes nasty surprises when a slice > was implicitly taken where it was unexpected. This case here is another > example of the problems that it causes. Very, very hot fire. :) IIRC, Atila has indicated that he would like to kill implicit slicing of static arrays (though that's going to require that we have actually started doing Editions first), so we may end up finally getting rid of it. I don't know how much convincing it will take for Walter though. I actually brought this up with Walter years ago at one of the dconfs in Berlin, suggesting that it was a big @safety mistake, but he preferred the idea of improving the language to catch escaping over removing the implicit slicing (which is probably part of why DIP 1000 and the related changes have unfortunately become a thing). Regardless of DIP 1000 though, IMHO, the implicit slicing just causes confusion and invisible behavior simply so that you can avoid using an explicit [] - and some of that isn't even related to bugs per se. For instance, plenty of folks end up trying to pass a static array to a range-based function and get confused when that doesn't work, since if the function took a dynamic array, it would work (and that also makes it more problematic to change a function so that it takes a range instead of a dynamic array). It's one of those features that seems like it's a nice usability improvement at first glance but which ultimately is a footgun. And when you get a more complex example like the one in this thread, it's that much worse, since even if you know enough to suspect that something along those lines might be the problem, I bet that most of us would not immediately come to that conclusion. It's just too subtle. And all to avoid typing a couple of characters. - Jonathan M Davis
Re: Unexpected range assignment behaviour
On Fri, Jul 19, 2024 at 05:48:37PM +, Dennis via Digitalmars-d-learn wrote: > On Friday, 19 July 2024 at 17:20:22 UTC, matheus wrote: > > couldn't this case for example be caught during the compiling time? > > The RangeError is only thrown when at runtime, the key doesn't exist, > so that can't be caught. The real problem is implicit slicing of > static arrays, which I'm not a fan of, but removing it is a breaking > change. So perhaps Associative Arrays should be enhanced to create > keys on slice assignment. IMO, implicit slicing of static arrays ought to be killed with fire. This is not the first time it has caused problems. In the past it used to cause issues with the implicit slice escaping the scope of the original static array, leading to dangling pointers and subsequent memory corruption / UB. With -dip1000 the situation has somewhat improved, but not entirely. It still causes nasty surprises when a slice was implicitly taken where it was unexpected. This case here is another example of the problems that it causes. T -- I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller
Re: Unexpected range assignment behaviour
On Friday, 19 July 2024 at 17:20:22 UTC, matheus wrote: couldn't this case for example be caught during the compiling time? The RangeError is only thrown when at runtime, the key doesn't exist, so that can't be caught. The real problem is implicit slicing of static arrays, which I'm not a fan of, but removing it is a breaking change. So perhaps Associative Arrays should be enhanced to create keys on slice assignment.
Re: Unexpected range assignment behaviour
On Friday, 19 July 2024 at 15:33:34 UTC, Dennis wrote: On Friday, 19 July 2024 at 09:34:13 UTC, Lewis wrote: But the value of $ here is 3. Why do I get a RangeError at runtime even though the slice is the correct size (and the same size as the hardcoded one that works)? The range `0 .. 3` has compile time known length, so it gets converted to string[3]: ```D lookup["test"] = dynArray[0 .. 3]; // becomes lookup["test"] = cast(string[3]) dynArray[0 .. 3]; ``` The key "test" doesn't exist yet, but because it's an assignment, it gets created. However, `0 .. $` depends on a run-time variable here, so it doesn't convert to a static array and does slice assignment: ```D lookup["test"] = dynArray[0 .. $]; // becomes lookup["test"][0 .. $] = dynArray[0 .. $]; ``` Now, you get a range error because "test" doesn't exist in `lookup`, and slice assignment doesn't create a new entry. Hi Dennis, I undestood your explanation, and based on that couldn't this case for example be caught during the compiling time? Thanks, Matheus.
Re: Unexpected range assignment behaviour
On Friday, 19 July 2024 at 09:34:13 UTC, Lewis wrote: ``` string[3][string] lookup; string[] dynArray = ["d", "e", "f"]; lookup["test"] = dynArray[0..$]; ``` This fails at runtime with RangeError. But if I change that last line to: ``` lookup["test"] = dynArray[0..3]; ``` then it works. But the value of $ here is 3. Why do I get a RangeError at runtime even though the slice is the correct size (and the same size as the hardcoded one that works)? I would have expected to only get a RangeError if at runtime the value turned out to be wrong. The simplest solution is to keep them consistent: ``` string[3][string] lookup; string[3] dynArray = ["d", "e", "f"]; ``` or ``` string[][string] lookup; string[] dynArray = ["d", "e", "f"]; ``` Avoid the temptation to mix static and dynamic arrays and your life will be easier. If you run into a situation where it's tough to avoid, use an explicit conversion: ``` lookup["test"] = dynArray.to!(string[3])[0..$]; ``` (I don't know all the complicated under the hood stuff as others do, but I know what works and why.)
Re: Unexpected range assignment behaviour
On Friday, 19 July 2024 at 09:34:13 UTC, Lewis wrote: But the value of $ here is 3. Why do I get a RangeError at runtime even though the slice is the correct size (and the same size as the hardcoded one that works)? The range `0 .. 3` has compile time known length, so it gets converted to string[3]: ```D lookup["test"] = dynArray[0 .. 3]; // becomes lookup["test"] = cast(string[3]) dynArray[0 .. 3]; ``` The key "test" doesn't exist yet, but because it's an assignment, it gets created. However, `0 .. $` depends on a run-time variable here, so it doesn't convert to a static array and does slice assignment: ```D lookup["test"] = dynArray[0 .. $]; // becomes lookup["test"][0 .. $] = dynArray[0 .. $]; ``` Now, you get a range error because "test" doesn't exist in `lookup`, and slice assignment doesn't create a new entry.
Re: Unexpected range assignment behaviour
On Fri, Jul 19, 2024 at 09:34:13AM +, Lewis via Digitalmars-d-learn wrote: > ``` > string[3][string] lookup; > string[] dynArray = ["d", "e", "f"]; > lookup["test"] = dynArray[0..$]; > ``` > > This fails at runtime with RangeError. But if I change that last line to: > > ``` > lookup["test"] = dynArray[0..3]; > ``` > > then it works. But the value of $ here is 3. Why do I get a RangeError > at runtime even though the slice is the correct size (and the same > size as the hardcoded one that works)? I would have expected to only > get a RangeError if at runtime the value turned out to be wrong. Sounds like a bug. First, there's an incompatibility between AA value type and the type being assigned: the value type of `lookup` is a static array, whereas a slice is a dynamic array. But since the compiler allows this assignment, it should work. I suspect there's a frontend bug somewhere in how assignments of slices to static arrays are implemented. T -- MAS = Mana Ada Sistem?
Re: Error: circular reference to variable cause by order (bugs?)
On Thursday, 18 July 2024 at 12:25:37 UTC, Dakota wrote: I am trying to translate some c code into d, get this error: ```d struct A { void* sub; } struct B { void* subs; } __gshared { const A[1] a0 = [ { _ptr }, ]; const A[2] a1 = [ { _ptr }, ]; const B b1 = {a1.ptr}; const b1_ptr = const A[1] a2 = [ { _ptr }, ]; const B b2 = {a2.ptr}; const b2_ptr = } ``` ```sh Error: circular reference to variable `tests.b1_ptr` ``` If I move `a0` after `b2_ptr`, no error any more. The c code has circular reference type, and compile ok. and there is a lot type I am not able to adjust order by hand to guess right order. the translate code still need to work with C interface, so I can not change the struct layout. is this a bug of d? if it was a compiler bug it probably be a crash; and the c code may have had a header file of some sort to make the linker happy that the traslator skipped that is just confusing cyclic code
Re: Recommendations on porting Python to D
On Monday, 15 July 2024 at 19:40:01 UTC, mw wrote: On Friday, 12 July 2024 at 18:07:50 UTC, mw wrote: [...] FYI, now merged into the main branch: https://github.com/py2many/py2many/tree/main/pyd This is great and certainly deserves an own discussion contribution in General. Did you try to convert any of the pystone programs? This would allow for benchmarking comparisons with e.g. nuitka or other approaches of compiled Python.
Re: Recommendations on porting Python to D
On Friday, 12 July 2024 at 18:07:50 UTC, mw wrote: On Friday, 3 May 2024 at 17:38:10 UTC, Chris Piker wrote: On Thursday, 25 April 2024 at 16:57:53 UTC, mw wrote: On Wednesday, 24 April 2024 at 22:07:41 UTC, Chris Piker wrote: Python-AST to D source converter may already exist? https://github.com/joortcom/eiffel_rename/tree/main/yi A rudimentary converter from (extended) Python to D. Maybe you can use it as a starting point. Thanks for the suggestions. I put the question aside for a bit, but yesterday ran across a python transpiler here: https://github.com/py2many/py2many It already has support for C++, Go and others. Since I have mountains of python code created over many years, maybe it would be worth contributing to this project out of self interest. Can you take a look at py2many and see what you think about it? Getting D on the support list might be good. Hi, I have made basic py2many.pyd work at language/syntax level in my dlang fork: https://github.com/mw66/py2many/tree/dlang The following examples works now: https://github.com/mw66/py2many/tree/dlang/tests/expected py2many/ 13:56:23$ ls ./tests/expected/*.d ./tests/expected/bubble_sort.d ./tests/expected/cls.d ./tests/expected/fib.d ./tests/expected/import_tests.d ./tests/expected/classes.d ./tests/expected/dict.d ./tests/expected/hello_world.d ./tests/expected/nested_dict.d I haven't created PR to be merged into the main branch, since it's better to pass all the tests. All the remaining work is to make Python's specific feature (e.g. async), library (e.g. complex number, NamedTemporaryFile) work in D. There are many things need to be done, if you have time, you can pick up from my fork, and work from there. (E.g. you can create PR to my branch, and when everything is ready, we submit to the main py2many all together). HTH. FYI, now merged into the main branch: https://github.com/py2many/py2many/tree/main/pyd
Re: need help to check symbol is static variable or not
On Monday, 15 July 2024 at 11:16:23 UTC, Nick Treleaven wrote: I put `type_s` in a file anonstruct.c, then: ```d import anonstruct; pragma(msg, isStatic!(type_s.c)); ``` That outputs `false`, because the symbol is not a compile-time value. Is that what you meant? No, I am here deal with a lot type and structs, no symbol problem yet. I guess the problem cause by the subtype has a hidden pointer to parent.
Re: need help to check symbol is static variable or not
On Monday, 15 July 2024 at 06:44:12 UTC, Dakota wrote: ```d struct type_s { union { struct { int a; int b; } c; }; }; ``` `type c` will return false with `enum isStatic(alias V) = __traits(compiles, { enum v = V; });` I put `type_s` in a file anonstruct.c, then: ```d import anonstruct; pragma(msg, isStatic!(type_s.c)); ``` That outputs `false`, because the symbol is not a compile-time value. Is that what you meant?
Re: need help to check symbol is static variable or not
On Monday, 1 July 2024 at 11:15:46 UTC, Nick Treleaven wrote: ``` There is a case check will give wrong resutls: ```d struct type_s { union { struct { int a; int b; } c; }; }; ``` `type c` will return false with `enum isStatic(alias V) = __traits(compiles, { enum v = V; });` type_s is from importC with DMD v2.110.0-beta.1.
Re: std.container.rbtree has no search method?! e.g. `contains`, `canFind`
On Sunday, 14 July 2024 at 02:01:44 UTC, Steven Schveighoffer wrote: On Saturday, 13 July 2024 at 17:41:42 UTC, mw wrote: Hi, on doc: https://dlang.org/phobos/std_container_rbtree.html#.RedBlackTree I cannot find any search method?! e.g. `contains`, `canFind`. Is this a over look? Or there are such functions else where? The functions are called `equalRange` (which gives you a range of all the elements that compare equal to the parameter), `lowerBound` (all elements less than the parameter), and `upperBound` (all elements greater than the parameter). This was not my choice, my original dcollections implementation used a `find` function. It was a condition for having the type added to phobos. -Steve I think for containers, it's better to have uniform naming convention, either `contains`, `canFind` or `in`, so writing generic code (e.g. via D template) is easier.
Re: How to build a statically linked executable, before i loose my mind
On Sunday, 14 July 2024 at 06:34:54 UTC, Richard (Rikki) Andrew Cattermole wrote: On 14/07/2024 5:06 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:44:22 UTC, Richard (Rikki) Andrew Cattermole wrote: On 14/07/2024 4:37 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:16:20 UTC, Richard (Rikki) Andrew Cattermole wrote: Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists. `curl -fsS https://dlang.org/install.sh | bash -s ldc` Okay yup, looks like its all there in latest release. Have to dump out what ld is getting passed to it, and what it thinks it is doing next. ``` /usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/ccBV7TjM.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o bin/dls /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o -L/home/runner/dlang/ldc-1.39.0/bin/../lib -L/home/runner/dlang/ldc-1.39.0/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/11 -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/home/runner/dlang/ldc-1.39.0/lib -L/usr/lib/gcc/x ``` https://github.com/ryuukk/dls/actions/runs/9921536908/job/27409615370 It works locally, but not their machine, ubuntu apparently Boom, got it working! https://github.com/rikkimax/dls/blob/master/makefile#L39 It's a link order issue. ``` ldc2 -of=bin/dlsobj.o -c --output-o $(OPTIMIZE) $(PREVIEWS) -Iserver/ -i server/cjson/cJSON.c server/dls/main.d ldc2 -of=bin/dls$(exe) bin/dlsobj.o server/dls/libdcd.a ``` It works!! thanks a lot!!
Re: Wrapper around a recursive data type
On 09.07.2024 06:54, Steven Schveighoffer wrote: On Monday, 8 July 2024 at 08:56:51 UTC, drug007 wrote: How can I "break" this recursion or some other work around to fix it? A few ideas: 1. If it's immediately recursive (that is, contains a pointer to itself), just use the type itself somehow. You may not be able to do this with recursive templates. 2. If the data itself is static, and not actually containing different things, defer the construction of the Meta members until needed. In other words, make them structs with a member which accesses the meta when requested. 3. In a project I have which constructs a parallel type on existing types, I use `opDispatch` to defer instantiation of the members until later. This may or may not work for you depending on the use case (you can't introspect `opDispatch`). -Steve Decided to use untyped array (like void[]) and then a decorator to make it typed one. It seems to be working, testing in progress.
Re: How to build a statically linked executable, before i loose my mind
On 14/07/2024 5:06 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:44:22 UTC, Richard (Rikki) Andrew Cattermole wrote: On 14/07/2024 4:37 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:16:20 UTC, Richard (Rikki) Andrew Cattermole wrote: Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists. `curl -fsS https://dlang.org/install.sh | bash -s ldc` Okay yup, looks like its all there in latest release. Have to dump out what ld is getting passed to it, and what it thinks it is doing next. ``` /usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/ccBV7TjM.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o bin/dls /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o -L/home/runner/dlang/ldc-1.39.0/bin/../lib -L/home/runner/dlang/ldc-1.39.0/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/11 -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/home/runner/dlang/ldc-1.39.0/lib -L/usr/lib/gcc/x ``` https://github.com/ryuukk/dls/actions/runs/9921536908/job/27409615370 It works locally, but not their machine, ubuntu apparently Boom, got it working! https://github.com/rikkimax/dls/blob/master/makefile#L39 It's a link order issue. ``` ldc2 -of=bin/dlsobj.o -c --output-o $(OPTIMIZE) $(PREVIEWS) -Iserver/ -i server/cjson/cJSON.c server/dls/main.d ldc2 -of=bin/dls$(exe) bin/dlsobj.o server/dls/libdcd.a ```
Re: std.container.rbtree has no search method?! e.g. `contains`, `canFind`
On Saturday, 13 July 2024 at 17:41:42 UTC, mw wrote: Hi, on doc: https://dlang.org/phobos/std_container_rbtree.html#.RedBlackTree I cannot find any search method?! e.g. `contains`, `canFind`. Is this a over look? Or there are such functions else where? The functions are called `equalRange` (which gives you a range of all the elements that compare equal to the parameter), `lowerBound` (all elements less than the parameter), and `upperBound` (all elements greater than the parameter). This was not my choice, my original dcollections implementation used a `find` function. It was a condition for having the type added to phobos. -Steve
Re: std.container.rbtree has no search method?! e.g. `contains`, `canFind`
On Saturday, 13 July 2024 at 17:41:42 UTC, mw wrote: I cannot find any search method?! e.g. `contains`, `canFind`. Is this a over look? Or there are such functions else where? It's the `in` operator: https://dlang.org/phobos/std_container_rbtree.html#.RedBlackTree.opBinaryRight But indeed, the documentation can be clearer about that.
Re: How to build a statically linked executable, before i loose my mind
On Saturday, 13 July 2024 at 16:44:22 UTC, Richard (Rikki) Andrew Cattermole wrote: On 14/07/2024 4:37 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:16:20 UTC, Richard (Rikki) Andrew Cattermole wrote: Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists. `curl -fsS https://dlang.org/install.sh | bash -s ldc` Okay yup, looks like its all there in latest release. Have to dump out what ld is getting passed to it, and what it thinks it is doing next. ``` /usr/bin/ld -plugin /usr/lib/gcc/x86_64-linux-gnu/11/liblto_plugin.so -plugin-opt=/usr/lib/gcc/x86_64-linux-gnu/11/lto-wrapper -plugin-opt=-fresolution=/tmp/ccBV7TjM.res -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s -plugin-opt=-pass-through=-lc -plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lgcc_s --build-id --eh-frame-hdr -m elf_x86_64 --hash-style=gnu --as-needed -dynamic-linker /lib64/ld-linux-x86-64.so.2 -pie -z now -z relro -o bin/dls /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/Scrt1.o /usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu/crti.o /usr/lib/gcc/x86_64-linux-gnu/11/crtbeginS.o -L/home/runner/dlang/ldc-1.39.0/bin/../lib -L/home/runner/dlang/ldc-1.39.0/lib/../lib -L/usr/lib/gcc/x86_64-linux-gnu/11 -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../x86_64-linux-gnu -L/usr/lib/gcc/x86_64-linux-gnu/11/../../../../lib -L/lib/x86_64-linux-gnu -L/lib/../lib -L/usr/lib/x86_64-linux-gnu -L/usr/lib/../lib -L/home/runner/dlang/ldc-1.39.0/lib -L/usr/lib/gcc/x ``` https://github.com/ryuukk/dls/actions/runs/9921536908/job/27409615370 It works locally, but not their machine, ubuntu apparently
Re: How to build a statically linked executable, before i loose my mind
On 14/07/2024 4:37 AM, ryuukk_ wrote: On Saturday, 13 July 2024 at 16:16:20 UTC, Richard (Rikki) Andrew Cattermole wrote: Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists. `curl -fsS https://dlang.org/install.sh | bash -s ldc` Okay yup, looks like its all there in latest release. Have to dump out what ld is getting passed to it, and what it thinks it is doing next.
Re: How to build a statically linked executable, before i loose my mind
On Saturday, 13 July 2024 at 16:16:20 UTC, Richard (Rikki) Andrew Cattermole wrote: Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists. `curl -fsS https://dlang.org/install.sh | bash -s ldc`
Re: How to build a statically linked executable, before i loose my mind
Seeing ``_d_arraybounds_slice`` missing sounds like druntime isn't being linked against. It is possible that your distribution of ldc doesn't include a static build of druntime/phobos. You need to verify that ld is trying to link against a static build and that static build exists.
Re: How to build a statically linked executable, before i loose my mind
For anyone curious: https://github.com/ryuukk/dls/tree/master ``make build-dcd-release && make build-dls-release`` i'm giving up for now, i'll never touch druntime/phobos/dub never again
Re: How to build a statically linked executable, before i loose my mind
I'm loosing it Even with dub it doesn't work `"lflags": [ "-static", "--link-defaultlib-shared=false" ],` ``` (cut due to forum's limit) trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd6__ctorMFNaNbNcNfAyaZSQCtQCp__TQClHTyaZQCt+0x1a9): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd6__ctorMFNaNbNcNfAyaZSQCtQCp__TQClHTyaZQCt+0x1c5): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd6__ctorMFNaNbNcNfAyaZSQCtQCp__TQClHTyaZQCt+0x1e3): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd6__ctorMFNaNbNcNfAyaZSQCtQCp__TQClHTyaZQCt+0x1fc): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: server/dls/libdcd.a(dparse.trivia.o): in function `_D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd__T7processTS3std5array__T8AppenderTAyaZQoZQBoMFNaNbNfKQBrZv': trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd__T7processTS3std5array__T8AppenderTAyaZQoZQBoMFNaNbNfKQBrZv+0xfe): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: server/dls/libdcd.a(dparse.trivia.o): in function `_D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv': trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x6c): undefined reference to `_D3std5ascii7isWhiteFNaNbNiNfwZb' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x142): undefined reference to `_D3std5ascii7isWhiteFNaNbNiNfwZb' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x17d): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x196): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x1b1): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x1cd): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd11stripIndentMFNaNbNiNfZv+0x1ee): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: server/dls/libdcd.a(dparse.trivia.o): in function `_D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv': trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0xff): undefined reference to `_d_array_slice_copy' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x13c): undefined reference to `_D3std5ascii7isWhiteFNaNbNiNfwZb' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x16d): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x186): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x1a1): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x1bc): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x1da): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x1f5): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd16processFirstLineMFNaNbNiNfZv+0x20b): undefined reference to `_d_arraybounds_index' /usr/bin/ld: server/dls/libdcd.a(dparse.trivia.o): in function `_D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd15processLastLineMFNaNbNiNfZv': trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd15processLastLineMFNaNbNiNfZv+0xc7): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd15processLastLineMFNaNbNiNfZv+0xe0): undefined reference to `_d_arraybounds_index' /usr/bin/ld: trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd15processLastLineMFNaNbNiNfZv+0xfc): undefined reference to `_d_arraybounds_slice' /usr/bin/ld: server/dls/libdcd.a(dparse.trivia.o): in function `_D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd10unDecorateMFNaNbNiNfZv': trivia.d:(.text._D6dparse6trivia__T22MultiLineCommentHelperHTyaZQBd10unDecorateMFNaNbNiNfZv+0x1d4):
Re: How to build a statically linked executable, before i loose my mind
On 14/07/2024 2:53 AM, ryuukk_ wrote: First of all, i build with `ldmd2` Second of all, i do not use DUB Lastly, it fails with: ``` ldmd2 -L-static ... ``` ``` /usr/bin/ld: cannot find -lphobos2-ldc-shared: No such file or directory /usr/bin/ld: cannot find -ldruntime-ldc-shared: No such file or directory ``` Why does it complain about SHARED when passing STATIC? Doesn't look like the switch does what you are thinking it does. ``` -static On systems that support dynamic linking, this overrides -pie and prevents linking with the shared libraries. On other systems, this option has no effect. ``` https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html Preventing linking against, and swapping two different binaries to link against are different things. Specifying to link against the shared libraries for druntime + phobos is done by the compiler, not the linker. You might want to try ``--link-defaultlib-shared=false`` instead.
Re: How to build a statically linked executable, before i loose my mind
On Saturday, 13 July 2024 at 14:53:41 UTC, ryuukk_ wrote: Why does it complain about SHARED when passing STATIC? It depends on the OS and if Linux - distribution.
Re: Recommendations on porting Python to D
On Wednesday, 24 April 2024 at 19:50:45 UTC, Chris Piker wrote: I can just call my old C code from D, but the old Python is another story. Thanks for any advice you may have, You could also try some AI solution
Re: Recommendations on porting Python to D
On Friday, 12 July 2024 at 18:07:50 UTC, mw wrote: On Friday, 3 May 2024 at 17:38:10 UTC, Chris Piker wrote: ... Hi, I have made basic py2many.pyd work at language/syntax level in my dlang fork: https://github.com/mw66/py2many/tree/dlang The following examples works now: https://github.com/mw66/py2many/tree/dlang/tests/expected py2many/ 13:56:23$ ls ./tests/expected/*.d ./tests/expected/bubble_sort.d ./tests/expected/cls.d ./tests/expected/fib.d ./tests/expected/import_tests.d ./tests/expected/classes.d ./tests/expected/dict.d ./tests/expected/hello_world.d ./tests/expected/nested_dict.d I haven't created PR to be merged into the main branch, since it's better to pass all the tests. All the remaining work is to make Python's specific feature (e.g. async), library (e.g. complex number, NamedTemporaryFile) work in D. There are many things need to be done, if you have time, you can pick up from my fork, and work from there. (E.g. you can create PR to my branch, and when everything is ready, we submit to the main py2many all together). HTH. Please use this Makefile for local setup and run tests: https://github.com/mw66/py2many/blob/dlang/Makefile
Re: Recommendations on porting Python to D
On Friday, 3 May 2024 at 17:38:10 UTC, Chris Piker wrote: On Thursday, 25 April 2024 at 16:57:53 UTC, mw wrote: On Wednesday, 24 April 2024 at 22:07:41 UTC, Chris Piker wrote: Python-AST to D source converter may already exist? https://github.com/joortcom/eiffel_rename/tree/main/yi A rudimentary converter from (extended) Python to D. Maybe you can use it as a starting point. Thanks for the suggestions. I put the question aside for a bit, but yesterday ran across a python transpiler here: https://github.com/py2many/py2many It already has support for C++, Go and others. Since I have mountains of python code created over many years, maybe it would be worth contributing to this project out of self interest. Can you take a look at py2many and see what you think about it? Getting D on the support list might be good. Hi, I have made basic py2many.pyd work at language/syntax level in my dlang fork: https://github.com/mw66/py2many/tree/dlang The following examples works now: https://github.com/mw66/py2many/tree/dlang/tests/expected py2many/ 13:56:23$ ls ./tests/expected/*.d ./tests/expected/bubble_sort.d ./tests/expected/cls.d ./tests/expected/fib.d ./tests/expected/import_tests.d ./tests/expected/classes.d ./tests/expected/dict.d ./tests/expected/hello_world.d ./tests/expected/nested_dict.d I haven't created PR to be merged into the main branch, since it's better to pass all the tests. All the remaining work is to make Python's specific feature (e.g. async), library (e.g. complex number, NamedTemporaryFile) work in D. There are many things need to be done, if you have time, you can pick up from my fork, and work from there. (E.g. you can create PR to my branch, and when everything is ready, we submit to the main py2many all together). HTH.
Re: Being reading a lot about betterC, but still have some questions
On Wednesday, 10 July 2024 at 08:26:56 UTC, kiboshimo wrote: It would take sometime for me to figure how to print to javascript console from a generated .html file from emscripten, this is a small update so nobody gets too caught up that quote. Got it printing quicker than I thought (node and browser with localhost). So stdio works. Any reason why other libraries wouldn't? Just archiving this progress here for anyone reading, but won't pollute the forum further if this thread dies out. I'm very grateful for the help, would have lost a lot of time without the reference frame you guys gave me :)
Re: Being reading a lot about betterC, but still have some questions
On Wednesday, 10 July 2024 at 01:48:54 UTC, kiboshimo wrote: - I though one could write an application with -betterC for WASM, because LDC can target it, then could build it linking to C libraries that already work on WASM and run the resulting build on the browser. That would avoid the JS-WASM bondary since everything would be WASM and I would not need to write my own abstractions. // I'm guessing one can't simply do that, and the toolchain that compiles to WASM is not so flexible/similar to compiling a normal binary. Maybe WASM does not have support for dynamic linking, for example. I was able to generate a .wasm file from hello_world.d (main) and hello_lib.c using LDC for compilation to bytecode, then to webassembly with emscripten. So, in theory it works, just couldn't test it yet since I'm learning Web APIs and nodejs. It would take sometime for me to figure how to print to javascript console from a generated .html file from emscripten, this is a small update so nobody gets too caught up that quote.
Re: Being reading a lot about betterC, but still have some questions
On Tuesday, 9 July 2024 at 20:24:14 UTC, H. S. Teoh wrote: What are you planning to run your wasm on? If in the browser, you could just use the browser's JS math functions. The performance won't be stellar (the wasm-JS boundary is SLOW), but it'd work and you wouldn't have to write your own math functions. This is what I use in my own D/wasm project. (It'd probably still beat any hand-written WASM reimplementation of math functions that you write. Remember, wasm is interpreted, so it won't beat the browser's built-in native math functions, which in all likelihood use the CPU's hardware math instructions.) This cleared up some fundamental misunderstandings I had, thank you. I want to use raylib and betterC to build a small game that runs on the browser. For motivation I though Wasm had many advantages over Js, but now I don't know if that is necessarily the case. If you're planning to run your wasm in a native environment, you could probably just use the C API to interface with the host system's C library functions. That covers native use-case. In the browser I can compile my programs to .js using emscripten/dscripten or I can just use JS API from WASM (but that is slow). I though emscripten could target WASM directly, without conversion to .js first. And, since it supports C, I'm assuming they re-implemented C API to the OS on WASM, without the need for calling JS API or WASI. (that might not serve me still, see bellow) I feel some fundamental misunderstanding remain, but now I have more material to research on my own, so feel free to ignore this if it is "too wrong". - I though one could write an application with -betterC for WASM, because LDC can target it, then could build it linking to C libraries that already work on WASM and run the resulting build on the browser. That would avoid the JS-WASM bondary since everything would be WASM and I would not need to write my own abstractions. // I'm guessing one can't simply do that, and the toolchain that compiles to WASM is not so flexible/similar to compiling a normal binary. Maybe WASM does not have support for dynamic linking, for example. - Is WASI relevant to the browser context? Or just to native apps? I though WASI API could be used on the browser, but comments and blogs about it often bring up the native context only. I tried to reply everyone here, since I think most answers converge. Thank you all for your help :)
Re: Being reading a lot about betterC, but still have some questions
On 09/07/2024 9:58 PM, kiboshimo wrote: On Tuesday, 9 July 2024 at 09:30:18 UTC, Richard (Rikki) Andrew Cattermole wrote: Threads are indeed gone. Oh no. If you want them, you'll have to call out to the system API and do your own thing. I hope "doing my own thing here" could be linking to a C library that interacts with the OS on my behalf. If you don't need to interact with an existing thread abstraction such as druntime, working with pthreads or Windows threading abstraction isn't an issue. These API's are pretty easy to interact with, I've got my own -betterC threading abstraction (I have good reasons not to recommend it here). I cannot comment about web assembly since I haven't done anything there, but some people have so hopefully they'll comment about where to go from here. Some of them might know. And if they know, them I will know. And if I know, then, you know... Oh I've seen them do stuff with it, its just not something I've wanted to learn, I have a lot of other stuff before it.
Re: Being reading a lot about betterC, but still have some questions
On Tuesday, 9 July 2024 at 20:03:15 UTC, kiboshimo wrote: On Tuesday, 9 July 2024 at 14:42:01 UTC, monkyyy wrote: On Tuesday, 9 July 2024 at 07:54:12 UTC, kiboshimo wrote: - betterC can be compiled to WASM, but some of phobos can't, so basically same worries as above. I'm afraid to lose some essential systems stuff that I could not replace. yes, and your not afraid enough Really liked the idea of doing it with betterC to start my systems programming journey Theres nothing even slightly pleasant or easy about d's wasm "support"; I wrote my own cos, sqrt functions, you get *nothing* from phoboes Writing my own math functions is outside of my range, I still have hopes of this not being so hard. So you get another opportunity to crush it. Honestly porting isqrt is easier then trying to get a half baked file io to work but it is *everything* is gone and thats probaly overwhelming unless your prepared for it. You could have used a C library for those things you implemented yourself, right? I suppose you didn't because doing things is cool, or because C is "not ergonomic" to use as foreign code. Because of the quirks. Which would make for a not so pleasant experience when writing a small game. What do you think about using C libraries like that? wasm *in general* breaks libc's fileio "for safety" (arguably the most important part of libc, morons), d's wasm libc in even more broken due to it coming out of no where and there being like 3 guys doing 20 ours of work on the "runtime" or something(ignore ppl who say d supports 7 platforms, it supports 2). While it can be a trivial port, I think you better off sticking to the raylib api as your ground layer as whatever work there seems to carry over.
Re: Being reading a lot about betterC, but still have some questions
On Tue, Jul 09, 2024 at 08:03:15PM +, kiboshimo via Digitalmars-d-learn wrote: > On Tuesday, 9 July 2024 at 14:42:01 UTC, monkyyy wrote: > > On Tuesday, 9 July 2024 at 07:54:12 UTC, kiboshimo wrote: [...] > > > Really liked the idea of doing it with betterC to start my systems > > > programming journey > > > > Theres nothing even slightly pleasant or easy about d's wasm > > "support"; I wrote my own cos, sqrt functions, you get *nothing* > > from phoboes > > Writing my own math functions is outside of my range, I still have > hopes of this not being so hard. So you get another opportunity to > crush it. [...] What are you planning to run your wasm on? If in the browser, you could just use the browser's JS math functions. The performance won't be stellar (the wasm-JS boundary is SLOW), but it'd work and you wouldn't have to write your own math functions. This is what I use in my own D/wasm project. (It'd probably still beat any hand-written WASM reimplementation of math functions that you write. Remember, wasm is interpreted, so it won't beat the browser's built-in native math functions, which in all likelihood use the CPU's hardware math instructions.) If you're planning to run your wasm in a native environment, you could probably just use the C API to interface with the host system's C library functions. Don't reinvent the square wheel unless you're planning to ride it on an inverted catenary road. :-P // On a larger note, if you're planning to write something small that runs in a browser, you might be interested to check out: https://github.com/Ace17/dscripten This is the D equivalent of emscripten. While it's nowhere near the maturity of emscripten itself, it may be Good Enough(tm) for your use. Rather than wrangling with the WASM/JS API (it's still early stage, there are a LOT of bumps currently still in the road), just let LLVM convert your D code straight into JS and run it as JS in the browser. Then you can leverage all the existing JS APIs your browser already supports, instead of having to reinvent yet another square wheel. T -- Some days you win; most days you lose.
Re: Being reading a lot about betterC, but still have some questions
On Tuesday, 9 July 2024 at 14:42:01 UTC, monkyyy wrote: On Tuesday, 9 July 2024 at 07:54:12 UTC, kiboshimo wrote: - betterC can be compiled to WASM, but some of phobos can't, so basically same worries as above. I'm afraid to lose some essential systems stuff that I could not replace. yes, and your not afraid enough Really liked the idea of doing it with betterC to start my systems programming journey Theres nothing even slightly pleasant or easy about d's wasm "support"; I wrote my own cos, sqrt functions, you get *nothing* from phoboes Writing my own math functions is outside of my range, I still have hopes of this not being so hard. So you get another opportunity to crush it. You could have used a C library for those things you implemented yourself, right? I suppose you didn't because doing things is cool, or because C is "not ergonomic" to use as foreign code. Because of the quirks. Which would make for a not so pleasant experience when writing a small game. What do you think about using C libraries like that?
Re: Being reading a lot about betterC, but still have some questions
On Tuesday, 9 July 2024 at 14:38:34 UTC, Lance Bachmeier wrote: If you haven't done so, I'd recommend reading the blog posts from Walter to get an understanding of why BetterC was introduced and how to use it: https://dlang.org/blog/category/betterc/ - betterC does not need glue code to interop with C. Does it achieve this by "gluing" behind the scenes? I've read in a comment somewhere that the ABI is the same, but idk people say lots of things. You're declaring your D code extern(C), as you can see in Walter's blog posts, so yes, you're using the C ABI. The blog post contextualizes evilrat's comment too. It facilities code migration because conversion is also easier (given adequate attention to C's quirks). After that you can start using D features on top of converted code. That won't help much on my Wasm use case, but it might, now that I know more about the ABI thing. Thank you.
Re: Being reading a lot about betterC, but still have some questions
On Tuesday, 9 July 2024 at 07:54:12 UTC, kiboshimo wrote: I'm going to try a project with raylib and WASM. use mine https://github.com/crazymonkyyy/raylib-2024/blob/master/docs/examplecode.md - betterC can be compiled to WASM, but some of phobos can't, so basically same worries as above. I'm afraid to lose some essential systems stuff that I could not replace. yes, and your not afraid enough Really liked the idea of doing it with betterC to start my systems programming journey Theres nothing even slightly pleasant or easy about d's wasm "support"; I wrote my own cos, sqrt functions, you get *nothing* from phoboes