Meaning of the dot-function syntax
Hi, What's the meaning of the dot in the call to writeln() below? ```d .writeln("Hello there!"); ``` I haven't found this in the spec or anywhere else. This is used very often in the source code for Phobos. Thanks, dhs
Straight Forward Arrays
Hi, Is there a straight forward Array type in D similar to C++'s vector class? Something along the lines of the tuple: (pointer to elements, length, capacity). I tried two implementations: D's dynamic array and std.container.array. When D creates a dynamic array, it returns a slice. Functions that add or remove elements begin by asking the memory manager for the dynamic array that the slice belongs to. Only then can they go on and add elements. I switched to std.container.array. It is more straight forward, but is also reference counted. Array is basically a pointer to the tuple (pointer to elements, length, capacity, refCount). Functions that add or remove elements begin by checking that the Array is not null, follow the pointer to the actual tuple, then follow the "pointer to elements" to access the actual elements. In C++, this is similar to shared_ptr\. The documentation does not mention nor explain why. Can someone explain? Is there a simpler, more efficient alternative? Thanks in Advance, dhs
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 09:21:37 UTC, Imperatorn wrote: On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: Hi, Is there a straight forward Array type in D similar to C++'s vector class? Something along the lines of the tuple: (pointer to elements, length, capacity). [...] https://dlang.org/spec/simd.html https://dlang.org/phobos/core_simd.html Or if you want to use it, you can check out core.stdcpp.vector. core.stdcpp.vector does look the dynamic array implementation I was looking for. Thank you, dhs
Re: Meaning of the dot-function syntax
On Sunday, 1 October 2023 at 09:20:32 UTC, Anonymouse wrote: On Sunday, 1 October 2023 at 08:22:48 UTC, dhs wrote: Hi, What's the meaning of the dot in the call to writeln() below? ```d .writeln("Hello there!"); ``` I haven't found this in the spec or anywhere else. This is used very often in the source code for Phobos. Thanks, dhs Quote https://dlang.org/spec/module.html#module_scope_operators; A leading dot (`.`) causes the identifier to be looked up in the module scope. ```d int x; int foo(int x) { if (y) return x; // returns foo.x, not global x else return .x; // returns global x } ``` Oh thank you, especially the link to the spec!
Re: Meaning of the dot-function syntax
On Sunday, 1 October 2023 at 09:24:39 UTC, evilrat wrote: On Sunday, 1 October 2023 at 08:22:48 UTC, dhs wrote: Hi, What's the meaning of the dot in the call to writeln() below? ```d .writeln("Hello there!"); ``` I haven't found this in the spec or anywhere else. This is used very often in the source code for Phobos. Thanks, dhs It is either means "use global scope writeln" in cases when there is local writeln in the scope shadowing global one, or simply a chained calls like myarray.filter().sort().map() each on new line. Thanks.
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 11:43:17 UTC, bachmeier wrote: On Sunday, 1 October 2023 at 11:39:11 UTC, bachmeier wrote: On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: Hi, Is there a straight forward Array type in D similar to C++'s vector class? Something along the lines of the tuple: (pointer to elements, length, capacity). I tried two implementations: D's dynamic array and std.container.array. When D creates a dynamic array, it returns a slice. Functions that add or remove elements begin by asking the memory manager for the dynamic array that the slice belongs to. Only then can they go on and add elements. Have you read [this article](https://dlang.org/articles/d-array-article.html)? I'm not sure what you mean with your reference to the memory manager, but consider this program: ``` import std; void main() { int[] x; x.length = 100; foreach(ii; 0..100) { x.ptr[ii] = ii; } x.length = 100; writeln(x); } ``` Or if you want a safer version: ``` import std; void main() { int[] x; x.length = 100; foreach(ii; 0..150) { if (ii < x.length) { x.ptr[ii] = ii; } } writeln(x); } ``` Thanks for the article. When you write x.length = 100, the code looks at x.capacity to see if the allocated memory is big enough for 100 elements. Since 'capacity' is not part of x, the code calculates it by asking the Garbage Collected how much memory was allocated. This is my understanding of the code and what I meant by "asking the memory manager". std.container.array uses a 'capacity' field, but is reference counted. This is not documented and means an additional indirection, which in my case is unnecessary. User 'Imperatorn' suggested using core.stdcpp.vector. Unfortunately, it compile for me (neither using DMD nor LDC). In addition, it looks like it depends on the C++ runtime for 'new' and 'delete'. So I am still in search of a straightforward dynamic array similar to C++ 'vector'.
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 13:05:12 UTC, Steven Schveighoffer wrote: On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: Hi, Is there a straight forward Array type in D similar to C++'s vector class? Something along the lines of the tuple: (pointer to elements, length, capacity). [...] Std::vector uses value semantics. D does not have anything like that. It could be done someone just has to do it. -Steve Yes, and therein lies the problem: writing a dynamic array is not a very difficult task for an old developer like me. I looked at the D runtime and at the Phobos implementation for reference. The code is so extremely difficult to understand and uses so many advanced D features, that I doubt that I am up to the task. For me, the point of switching to D was to use a language that is simpler to read and maintain.
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 13:51:35 UTC, Imperatorn wrote: D can be very readable and maintainable, but since all the advanced features exist, we are tempted to use them, which can cause otherwise normal code to become a bit obfuscated. OK in any case the forum seems to be very helpful. Thanks to all for your help.
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 13:27:37 UTC, Adam D Ruppe wrote: On Sunday, 1 October 2023 at 09:01:53 UTC, dhs wrote: When D creates a dynamic array, it returns a slice. Functions that add or remove elements begin by asking the memory manager for the dynamic array that the slice belongs to. Only then can they go on and add elements. Why is this a problem? It is convenient and usually works fine. I use the built in arrays very very often for a lot of things. It may not be a problem in practice. My concern was performance, because each time we add an element to the array, the garbage collector has to map the slice to the allocation it belongs to.
Re: Straight Forward Arrays
On Sunday, 1 October 2023 at 17:21:32 UTC, Steven Schveighoffer wrote: On 10/1/23 10:34 AM, Steven Schveighoffer wrote: This should give you a reasonable head-start. -Steve It does. Many thanks!
Re: Straight Forward Arrays
On Monday, 2 October 2023 at 02:56:33 UTC, Steven Schveighoffer wrote: FWIW, there is a cache that makes this decently fast, so it doesn't have to go all the way into the GC to get all the information for every append. But it *most definitely* not going to be as fast as reading a local "capacity" variable. -Steve Sure, I saw that, it obviously works pretty good. I think it's worth mentioning that D slices are similar in concept to Go slices. In Python, lists are reference types too but slicing creates a copy (so, 'b = a' shares, while 'b = a[:]' copies.) JavaScript arrays are similar to Python in this sense. C++ and Rust use distinct types for the resizable array and its view, and the view must not outlive the array. D and Go slices have advantages but can be confusing. I don't have a solution, but if anyone is interested, the relevant discussions about slice confusion in the Go community apply to D slices as well.
Re: Straight Forward Arrays
On Thursday, 5 October 2023 at 16:57:00 UTC, Jesse Phillips wrote: On Wednesday, 4 October 2023 at 10:51:46 UTC, dhs wrote: D and Go slices have advantages but can be confusing. I don't have a solution, but if anyone is interested, the relevant discussions about slice confusion in the Go community apply to D slices as well. I don't believe slice confusion in D is the same as God. https://he-the-great.livejournal.com/48672.html D manages to avoid stomping, while Go provides no clear ownership when slices are at play. And here is the slices explained https://dlang.org/articles/d-array-article.html Thanks for the link. It actually demonstrates my point: he gets the same results from D and Go until he appends elements to the slice. It is then that things get confusing. Obviously, the implementations are not exactly the same: for example, in Go 'capacity' is a field whereas in D it is a calculated property. But they are *similar*. Here are some quotes from Go users: "the issue of Go's slices is that they act as both a dynamic array and a slice viewing a portion of one. The two uses conflict with one another, and the interactions are full of traps. " https://news.ycombinator.com/item?id=28344938 "the behaviour is logical based on how Go works. The criticism is instead that it works this way in the first place. The reason it's like this is that slices were attempting to address two separate use cases — growable arrays and subarrays" https://www.reddit.com/r/golang/comments/6qizjq/fucking_go_slices/ Quote: "Welcome to go! This is one of the language quirks." https://www.reddit.com/r/golang/comments/10b4ofx/confused_about_array_and_slices/ Others pointed out that slices work well. My points is: if you're thinking about a change it's worth reading the Go discussions, because their slices are similar in concept.
Struct copy constructor with inout
Hello D experts, I have a question regarding inout in struct copy constructors. From the spec: "The copy constructor can be overloaded with different qualifiers applied to the parameter (copying from a qualified source) or to the copy constructor itself (copying to a qualified destination)" I am using following code: ```d struct S1 { this(ref const S1 s) const { writeln("copy"); } int i; } struct S2 { this(ref inout S2 s) inout { writeln("copy"); } int i; } void test() { const(S1) s1; S1 ss1 = s1; // error, ss1 not qualified as const const(S2) s2; S2 ss2 = s2; // fine, why? } ``` Isn't "inout" supposed to copy the const-ness of its parameter to the constructor's attribute? In other words: why doesn't ss2=s2 fail here? Thanks, dhs
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 09:07:24 UTC, Alexandru Ermicioi wrote: Seems like it isn't called at all, your copy constructor with inout. Could be a bug. My assumption is that default copy constructors are generated alongside inout one, and then picked up for your initialization instead of inout one. Best regards, Alexandru. When I run test() it outputs the string "copy", so I am not sure why you're saying this.
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 13:58:17 UTC, Paul Backus wrote: On Tuesday, 14 November 2023 at 13:41:32 UTC, Steven The error is saying that the copy constructor expects a `const` `this` argument, but you're passing a mutable `this` argument. Thanks you both very much for answering. Just to clarify some more: isn't "s1 = ss1" similar to something like: ```d const(S1) s1; S1 ss1; // ss1 is now S1.init S1_copy_construct_const_in_const_out(ss1, s1); ``` If this is the case, the compile error is expected, but why/how/where do "implicit qualifer conversions" apply here? Thanks again, dhs
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 14:36:57 UTC, dhs wrote: Just to clarify some more: isn't "s1 = ss1" similar to I meant "ss1 = s1" here, sorry.
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 14:58:21 UTC, Paul Backus wrote: ```d struct S2 { int* p; this(const int* p) const { // Ok - counts as initialization this.p = p; } } immutable int answer = 42; void main() { S2 s2; // If this were allowed to compile... s2.__ctor(&answer); // ...then this could happen *s2.p = 12345; } ``` Thanks for this explanation, it all makes perfect sense. Regarding implicit qualifier conversion: in my code, S2 has a copy constructor, so it takes a "ref inout S2" as input. Since the copy constructor is in itself qualified as inout, the implicit "this" parameter is "ref inout S2" too. We then have "const(S2) s2;" and "S2 ss2 = s2;". The implicit qualifier conversions *for references* do not allow conversion from "ref const(S2)" to "ref S2", so I assume that the "inout" in the copy constructor translates to "const". In that case, the copy constructor creates a "const S2", not an S2. Does this "const S2" then get implicitly converted to "S2", before being assigned to "ss2"? I tried adding an opAssign() to S2 - it's not getting called. So I'm not sure what is actually going on here.
Re: Struct copy constructor with inout
On Tuesday, 14 November 2023 at 16:51:07 UTC, Paul Backus wrote: There's no assignment. The value is constructed in-place, in `ss2`'s memory. The reason the compiler allows you to construct a `const(S2)` value inside of an `S2` variable is that `const(S2)` implicitly converts to `S2`. On Tuesday, 14 November 2023 at 16:58:25 UTC, Steven Schveighoffer wrote: That being said, I still consider this a bug, if the inout version works, the const version should work as well. I don't see the difference. Ok so to summarize: - "inout" and "const" behaving differently here is probably wrong, and - in structs without reference fields, a const constructor can be used to construct mutable values, due to "implicit qualifier conversions". Thanks.