Re: Passing a derived class where base class is defined as ref parameter
On Tuesday, 14 December 2021 at 20:58:21 UTC, Adam D Ruppe wrote: nice. You might want to look at my terminal.d (arsd-official:terminal on dub) too which has pretty comprehensive functionality for tons of things. Prolly more than you need looking at your interface tho but it includes the output functions then mouse and real time key inputs, get line input, even scrollable areas and more. Always a pleasure to check your great libs, I will have a look and learn probably a lot. But I wont use an external lib because it's a demo where all the code must be under contract / covered, to meet some strict coding standard. So in worst case I copy the code and add unittest / contract / invariant, etc. But original authors are always quoted and licences respected ;)
Re: Passing a derived class where base class is defined as ref parameter
On Tuesday, 14 December 2021 at 17:27:13 UTC, Stanislav Blinov wrote: Simple. Don't take a `ref`. Just take a `Console`. Classes in D are reference types, you're not making a copy as you would in C++ if you were to write `updateFoodToken(Console c)`. Ah, ok, Reference types! That's great. Definitely my C++ bias working against me, good you read my mind :)
Re: Immutability and arrays
On Tuesday, 14 December 2021 at 16:21:03 UTC, Steven Schveighoffer wrote: On 12/14/21 11:19 AM, Steven Schveighoffer wrote: Er... scratch that, this isn't construction, it should use opAssign. Again, probably because memcpy+postblit is used by the runtime. If not reported, it should be. Simple proof that it is a bug: ```d immutable (ComplexStruct)[] arr; ComplexStruct[] arr2; arr2[0] = arr[0]; // ok arr2[] = arr[]; // error ``` If you can copy one element, you should be able to copy all the elements. -Steve Thank you everybody, especially to Steve for the detailed explanation. It seems that every post I put in the learn forum, results in a bug report :) https://issues.dlang.org/show_bug.cgi?id=22601 https://issues.dlang.org/show_bug.cgi?id=22600
Re: Why code failed to compile for foo2?
On Tuesday, 14 December 2021 at 15:14:40 UTC, Steven Schveighoffer wrote: On 12/14/21 12:04 AM, Tejas wrote: Is there anything wrong with the answer I posted? Can you please tell me if there's anything dissatisfactory about it? I feel like it does everything the OP wants. Also, am I wrong in using `Unconst` over `Unqual`? Isn't `Unqual` overkill if you just want to cast away `const`? Unqual is fine for value types, it should work in all cases. The OP's problem is that it's entirely possible to build an overload set with *just* the unqualified types specified (in this case, an integral type), but there's not a way to express that and still have it work with IFTI. In other words, if you have a call like: ```d const int x; foo2(x); ``` You want to have the parameter be mutable inside foo2. There currently isn't a way to express that if `foo2` is an IFTI template. The opposite is actually easily expressable: ```d void foo2(T)(const(T) val) { // only one instantiation of foo2 per const(int), immutable(int), int, // and now val is const, even if the argument is not } ``` With a standard function it works just fine due to implicit conversion, but with IFTI, there's no way to express it because it goes through an alias. The closest you can come is to write a wrapper shim that calls the right instantiation. This should be OK as long as inlining is happening, but it seems like extra work for the optimizer, when it should be easy to express in the language somehow. BTW, there is a related issue: https://issues.dlang.org/show_bug.cgi?id=1807 -Steve Yeah, now I understand he's trying to reduce number of instantiations. In that case, I'd use `inout`, but it'd be the same as your case : can't modify the argument anymore. But we can pass that to another function that accepts `ulong` (as that seems to be the OP's usecase anyways), which can then modify it :D ```d import std.traits : Unconst; import std.stdio : writeln; void foo2(T)(inout(T) x) if(is(Unconst!(T) : ulong)) {//You don't need Unqual for this pragma(msg, T.stringof); foo3(x); } void foo3(ulong param){ writeln(param, " before"); param +=10; writeln(param, " after"); // can also modify params now } void main(){ import std.math; const int ci = -3; int i = -2; immutable int ii = 24342; foo2(abs(ci)); foo2(abs(i)); foo2(ii); byte b = 0; const byte cb; immutable byte ib; foo2(b); foo2(cb); foo2(ib); const long cl = 4554; long l = 12313; immutable long il = 3242343; foo2(cl); foo2(l); foo2(il); } ```
Re: Why code failed to compile for foo2?
On Tuesday, 14 December 2021 at 13:25:04 UTC, apz28 wrote: On Tuesday, 14 December 2021 at 05:04:46 UTC, Tejas wrote: Is there anything wrong with the answer I posted? Can you please tell me if there's anything dissatisfactory about it? I feel like it does everything the OP wants. Also, am I wrong in using `Unconst` over `Unqual`? Isn't `Unqual` overkill if you just want to cast away `const`? 1. A template function should behave as to replace 4 overload functions There is special logic for parameter type (2 vs 4...) 2. Your implementation does not remove 'const' as below import std.traits : Unconst; import std.stdio : writeln; void foo2(T)(T x) if(is(Unconst!(T) : ulong)) {//You don't need Unqual for this pragma(msg, T.stringof); writeln(x); } void main() { import std.math; const int s1 = -3; int s2 = -2; foo2(abs(s1)); foo2(abs(s2)); enum byte b1 = 0; const byte b2; byte b3; foo2(b1); foo2(b2); foo2(b3); } --Output const(int) int byte const(byte) 3 2 0 0 0 Then I suggest using `inout`, if you're trying to reduce number of template instantiations ```d import std.traits : Unconst; import std.stdio : writeln; void foo2(T)(inout(T) x) if(is(Unconst!(T) : ulong)) {//You don't need Unqual for this pragma(msg, T.stringof); writeln(x); } void main(){ import std.math; const int ci = -3; int i = -2; immutable int ii = 24342; foo2(abs(ci)); foo2(abs(i)); foo2(ii); byte b = 0; const byte cb; immutable byte ib; foo2(b); foo2(cb); foo2(ib); const long cl = 4554; long l = 12313; immutable long il = 3242343; foo2(cl); foo2(l); foo2(il); } Output(Compile-time): int byte long Output(Runtime): 3 2 24342 0 0 0 4554 12313 3242343 ```
Re: Passing a derived class where base class is defined as ref parameter
On Tuesday, 14 December 2021 at 17:20:18 UTC, chopchop wrote: I am using the "ref" here (I put tinyurl to avoid over-referencing the post instead of the github page itself): https://tinyurl.com/bdddkmub yeah D classes are automatically ref unlike c++ so you don't need the second level of it most often. Using plain `Object` is what you want most the time, maybe `in Object` sometimes. But `ref Object` or `Object*` both very rare in D. Adam, I am actually using your code :) nice. You might want to look at my terminal.d (arsd-official:terminal on dub) too which has pretty comprehensive functionality for tons of things. Prolly more than you need looking at your interface tho but it includes the output functions then mouse and real time key inputs, get line input, even scrollable areas and more.
Re: template ctor overload Segmentation fault
On Tuesday, 14 December 2021 at 14:40:00 UTC, RazvanN wrote: On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped) PR: https://github.com/dlang/dmd/pull/13427 Thanks, I got it to work for now: ```d struct Foo(T){ this(Rhs, this This)(auto ref scope Rhs rhs) if(__traits(isRef, rhs) == false){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ```
Re: Passing a derived class where base class is defined as ref parameter
On Tuesday, 14 December 2021 at 17:20:18 UTC, chopchop wrote: I am using the "ref" here (I put tinyurl to avoid over-referencing the post instead of the github page itself): https://tinyurl.com/bdddkmub I would like to be able to pass any kind of console to updateFoodToken ( Console c ), ie either a winconsole or a nixconsole, which are derived from Console. I mean I probably have a cognitive bias of being a c++ dev. Let me explain. If I was coding in C++ I would pass "A&". Not "const A&", because I do two function calls with console - for example console.gotoxy(...) - but those 2 members functions are not suffixed "const". Since it is work in progress, I dont even know if I am going to modify those functions at the end or do something else with console... Simple. Don't take a `ref`. Just take a `Console`. Classes in D are reference types, you're not making a copy as you would in C++ if you were to write `updateFoodToken(Console c)`.
Re: Passing a derived class where base class is defined as ref parameter
On Monday, 13 December 2021 at 22:30:59 UTC, Adam D Ruppe wrote: On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote: If I remove the ref, it works as expected, that is to say I can give a derived class as parameter. Why are you using the ref to begin with? What the logic here? Consider this: class C : A {} void incr(ref A a) { a = new C; } B b = new B; incr(b); // oops b now got rebound to a C instead of to a B, which breaks everything Hi Adam, I am using the "ref" here (I put tinyurl to avoid over-referencing the post instead of the github page itself): https://tinyurl.com/bdddkmub I would like to be able to pass any kind of console to updateFoodToken ( Console c ), ie either a winconsole or a nixconsole, which are derived from Console. I mean I probably have a cognitive bias of being a c++ dev. Let me explain. If I was coding in C++ I would pass "A&". Not "const A&", because I do two function calls with console - for example console.gotoxy(...) - but those 2 members functions are not suffixed "const". Since it is work in progress, I dont even know if I am going to modify those functions at the end or do something else with console... But well, what do you guys think? The documentation does not even say if an "in" param is passed by value or reference ("may be passed by reference" it says). I don't really see how a copy of a console would work... Kind of eery in my minde. Adam, I am actually using your code :) You and anyone else are welcome to review / send some Pull Request, deal with the console code, comment, etc
Re: Passing a derived class where base class is defined as ref parameter
On Tuesday, 14 December 2021 at 05:38:17 UTC, Tejas wrote: On Monday, 13 December 2021 at 22:30:59 UTC, Adam D Ruppe wrote: On Monday, 13 December 2021 at 22:06:45 UTC, chopchop wrote: If I remove the ref, it works as expected, that is to say I can give a derived class as parameter. Why are you using the ref to begin with? What the logic here? Consider this: class C : A {} void incr(ref A a) { a = new C; } B b = new B; incr(b); // oops b now got rebound to a C instead of to a B, which breaks everything But `B` is not a child of `A`, why should it be accepted in a function that accepts `A` as a parameter? It's not implicitly convertible to `A` Tejas, I think you should not read Adam's example as standalone, obviously he is implicitly reusing the definition of B in my first post, so B is indeed a child of A.
Re: Immutability and arrays
On 12/14/21 11:19 AM, Steven Schveighoffer wrote: Er... scratch that, this isn't construction, it should use opAssign. Again, probably because memcpy+postblit is used by the runtime. If not reported, it should be. Simple proof that it is a bug: ```d immutable (ComplexStruct)[] arr; ComplexStruct[] arr2; arr2[0] = arr[0]; // ok arr2[] = arr[]; // error ``` If you can copy one element, you should be able to copy all the elements. -Steve
Re: Immutability and arrays
On 12/14/21 11:14 AM, Steven Schveighoffer wrote: On 12/14/21 10:53 AM, Stanislav Blinov wrote: Now, since we have copy ctors, slice assignment should, ostensibly, attempt to copy-assign elements (i.e. absent opAssign, try the copy ctor first). I agree slice-assign should work here with a copy ctor. What I think is happening is that it's still very much built on memcpy + postblit (so much of the array runtime is still magic functions). postblit doesn't work because it first makes a copy of the data AS-IS, which means it's still immutable, and only after the postblit would it be mutable. Er... scratch that, this isn't construction, it should use opAssign. Again, probably because memcpy+postblit is used by the runtime. If not reported, it should be. -Steve
Re: Immutability and arrays
On 12/14/21 10:53 AM, Stanislav Blinov wrote: Now, since we have copy ctors, slice assignment should, ostensibly, attempt to copy-assign elements (i.e. absent opAssign, try the copy ctor first). I agree slice-assign should work here with a copy ctor. What I think is happening is that it's still very much built on memcpy + postblit (so much of the array runtime is still magic functions). postblit doesn't work because it first makes a copy of the data AS-IS, which means it's still immutable, and only after the postblit would it be mutable. -Steve
Re: Immutability and arrays
On Tuesday, 14 December 2021 at 15:28:30 UTC, Steven Schveighoffer wrote: All the other problems you are having are deriving from this problem. Not exactly. One of the problems seems to be a genuine bug: ```d struct S { int[] x; // doesn't even participate here, neither would postblit this(ref return scope inout S other) { x = other.x.dup; } void opAssign(ref return scope inout S other) { x = other.x.dup; } } void main() { immutable(S)[] src = [S([1, 2]), S([3, 4])]; auto dst = new S[src.length]; //dst[0 .. $] = src[0 .. $]; // this fails to compile even with opAssign defined // this works: foreach (i, ref it; dst) it = src[i]; } ``` Spec: https://dlang.org/spec/arrays.html#array-copying ...contents of the array are the target of the assignment... Per that wording, slice assignment should perform the equivalent of that foreach loop (after overlap checks, etc.). It doesn't, just tries implicit conversion, and fails. Now, since we have copy ctors, slice assignment should, ostensibly, attempt to copy-assign elements (i.e. absent opAssign, try the copy ctor first).
Re: Immutability and arrays
On 12/14/21 3:44 AM, rumbu wrote: I am trying to understand why in this two different cases (Simple and Complex), the compiler behaviour is different. ```d struct SimpleStruct { int x;} struct ComplexStruct { int[] x; } void main() { SimpleStruct[] buf1; immutable(SimpleStruct)[] ibuf1; buf1[0 .. 10] = ibuf1[0 .. 10]; //this works ComplexStruct[] buf2; immutable(ComplexStruct)[] ibuf2; buf2[0 .. 10] = ibuf2[0 .. 10]; //error cannot implicitly convert expression `ibuf2[0..10]` of type `immutable(ComplexStruct)[]` to `ComplexStruct[]` } ``` I know there have been several answers as to what the rules are, I want to answer why the rules are there. In the first case, you have a simple struct which has a single integer in it. When copying that struct, you have no indirections (pointers), which means that adjusting the mutability is allowed: ```d immutable s = SimpleStruct(5); SimpleStruct s2 = s; // ok, we are making a copy of everything ``` In the second case, the `int[]` contains a pointer. So if you made a copy of that, you cannot change the mutability of the type, because now it would have a mutable pointer to immutable data: ```d immutable s = ComplexStruct([5]); ComplexStruct s2 = s; // error, cannot implicitly convert, there is an indirection ``` The WHY is this: let's say the above was allowed, `s2` is mutable, which means `s2.x` is mutable. Now I can do: ```d s2.x[0] = 6; ``` And all of a sudden, immutable data has changed! This cannot be allowed, which is why you can't copy the struct. All the other problems you are having are deriving from this problem. -Steve
Re: Why code failed to compile for foo2?
On 12/14/21 12:04 AM, Tejas wrote: Is there anything wrong with the answer I posted? Can you please tell me if there's anything dissatisfactory about it? I feel like it does everything the OP wants. Also, am I wrong in using `Unconst` over `Unqual`? Isn't `Unqual` overkill if you just want to cast away `const`? Unqual is fine for value types, it should work in all cases. The OP's problem is that it's entirely possible to build an overload set with *just* the unqualified types specified (in this case, an integral type), but there's not a way to express that and still have it work with IFTI. In other words, if you have a call like: ```d const int x; foo2(x); ``` You want to have the parameter be mutable inside foo2. There currently isn't a way to express that if `foo2` is an IFTI template. The opposite is actually easily expressable: ```d void foo2(T)(const(T) val) { // only one instantiation of foo2 per const(int), immutable(int), int, // and now val is const, even if the argument is not } ``` With a standard function it works just fine due to implicit conversion, but with IFTI, there's no way to express it because it goes through an alias. The closest you can come is to write a wrapper shim that calls the right instantiation. This should be OK as long as inlining is happening, but it seems like extra work for the optimizer, when it should be easy to express in the language somehow. BTW, there is a related issue: https://issues.dlang.org/show_bug.cgi?id=1807 -Steve
Re: template ctor overload Segmentation fault
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped) PR: https://github.com/dlang/dmd/pull/13427
Re: template ctor overload Segmentation fault
On Tuesday, 14 December 2021 at 13:02:16 UTC, Tejas wrote: On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote: [...] Then why did my modification work? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T and ref with pointer. Code still works if I retain typeof(this) } } struct Bar{ Foo!int foo; } void main(){ import std.stdio:writeln; Bar bar = Bar(); auto BAR = new Bar(); writeln(bar, "\t", BAR, "\t", *BAR); } ``` Did my modifications ensure that this is not treated as a copy constructor? Yes, the copy constructor needs to be explicitly defined by passing a ref parameter. Since you are expecting an explicit pointer, the compiler does not see it as a copy constructor and therefore does not try to generate one for Bar.
Re: Why code failed to compile for foo2?
On Tuesday, 14 December 2021 at 05:04:46 UTC, Tejas wrote: Is there anything wrong with the answer I posted? Can you please tell me if there's anything dissatisfactory about it? I feel like it does everything the OP wants. Also, am I wrong in using `Unconst` over `Unqual`? Isn't `Unqual` overkill if you just want to cast away `const`? 1. A template function should behave as to replace 4 overload functions There is special logic for parameter type (2 vs 4...) 2. Your implementation does not remove 'const' as below import std.traits : Unconst; import std.stdio : writeln; void foo2(T)(T x) if(is(Unconst!(T) : ulong)) {//You don't need Unqual for this pragma(msg, T.stringof); writeln(x); } void main() { import std.math; const int s1 = -3; int s2 = -2; foo2(abs(s1)); foo2(abs(s2)); enum byte b1 = 0; const byte b2; byte b3; foo2(b1); foo2(b2); foo2(b3); } --Output const(int) int byte const(byte) 3 2 0 0 0
Re: Immutability and arrays
On Tuesday, 14 December 2021 at 12:13:23 UTC, Stanislav Blinov wrote: Because is(typeof(immutable(ComplexStruct).x) == immutable(int[])). Can't bind an array of immutable to array of mutable. This would require a deep copy, i.e. copy constructor. This means that the only way to write a generic function which copies an array of immutable elements to another array is this: ```d void copy10(T)(T[] dst, immutable(T)[] src) { static if (is(immutable(T): T)) dst[0..10] = src[0..10]; else dst[0..10] = cast(T[])src[0..10]; // or better a deep copy } ``` Btw, tried to give ComplexStruct a some copy constructors (casting away immutable is just for the example, I know it's not the way to do it). ```d struct ComplexStruct { int[] x; this(ref return scope ComplexStruct another) { this.x = another.x; } this(ref return scope immutable(ComplexStruct) another) { this.x = cast(int[])(another.x); } } ``` Still slice assignment does not work. I think I will drop immutability, it's too complicated to work with.
Re: template ctor overload Segmentation fault
On Tuesday, 14 December 2021 at 12:04:36 UTC, RazvanN wrote: On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: [...] The problem is that the compiler will try to generate an inout copy constructor for Bar that looks roughly like this: ``` this(ref scope inout(Bar) p) inout { this.foo = p; } ``` The idea behind this lowering is to try and call the copy constructor for Foo object if possible. One issue here is that copy constructors have the same symbol name as constructors (__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`. Since both the instance and the parameter are inout, the copy constructor of Foo cannot be called, so the templated constructor is called. After generating the template instance of the constructor, you end up with `this(scope inout(Foo)) inout` ; that is basically an rvalue constructor. This is not valid code; if you write: ``` struct Foo(T){ //this(Rhs, this This)(scope Rhs rhs){} this(scope inout(Foo!int) rhs) inout {} this(ref scope typeof(this) rhs){ } } ``` You will get an error stating that you cannot define both an rvalue constructor and a copy constructor. However, since the constructor is templated it is impossible for the compiler to issue this error before actually instantiating the constructor. I see 2 possible fixes for this: (1) either we rename the copy constructor symbol to __cpCtor so that it does not clash with the normal constructor overload set or (2) when a templated constructor is instantiated, we can check whether it is an rvalue constructor and issue an error if a copy constructor exists. When I implemented the copy constructor I thought that it would better to have the copy constructor on a different overload set than the normal constructors, however, Walter insisted that they have the same name. So, I guess (2) is the way to go. Cheers, RazvanN Then why did my modification work? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(scope Foo!(T)* rhs){ //replaced typeof(this) with Foo!T and ref with pointer. Code still works if I retain typeof(this) } } struct Bar{ Foo!int foo; } void main(){ import std.stdio:writeln; Bar bar = Bar(); auto BAR = new Bar(); writeln(bar, "\t", BAR, "\t", *BAR); } ``` Did my modifications ensure that this is not treated as a copy constructor?
Re: Immutability and arrays
On Tuesday, 14 December 2021 at 08:44:02 UTC, rumbu wrote: I am trying to understand why in this two different cases (Simple and Complex), the compiler behaviour is different. ```d struct SimpleStruct { int x;} struct ComplexStruct { int[] x; } void main() { SimpleStruct[] buf1; immutable(SimpleStruct)[] ibuf1; buf1[0 .. 10] = ibuf1[0 .. 10]; //this works ComplexStruct[] buf2; immutable(ComplexStruct)[] ibuf2; buf2[0 .. 10] = ibuf2[0 .. 10]; //error cannot implicitly convert expression `ibuf2[0..10]` of type `immutable(ComplexStruct)[]` to `ComplexStruct[]` } ``` Because is(typeof(immutable(ComplexStruct).x) == immutable(int[])). Can't bind an array of immutable to array of mutable. This would require a deep copy, i.e. copy constructor.
Re: Immutability and arrays
On Tuesday, 14 December 2021 at 08:44:02 UTC, rumbu wrote: I am trying to understand why in this two different cases (Simple and Complex), the compiler behaviour is different. ```d struct SimpleStruct { int x;} struct ComplexStruct { int[] x; } void main() { SimpleStruct[] buf1; immutable(SimpleStruct)[] ibuf1; buf1[0 .. 10] = ibuf1[0 .. 10]; //this works ComplexStruct[] buf2; immutable(ComplexStruct)[] ibuf2; buf2[0 .. 10] = ibuf2[0 .. 10]; //error cannot implicitly convert expression `ibuf2[0..10]` of type `immutable(ComplexStruct)[]` to `ComplexStruct[]` } ``` there are special cases in the compiler for values that have no mutable indirections: https://dlang.org/spec/const3.html#implicit_qualifier_conversions Values that have no mutable indirections (including structs that don't contain any field with mutable indirections) can be implicitly converted across mutable, const, immutable, const shared, inout and inout shared. so that first struct may be implicitly converted between mutable/immutable/const because it doesn't contain any mutable indirections (mutable arrays/pointers/references)
Re: template ctor overload Segmentation fault
On Sunday, 12 December 2021 at 11:57:43 UTC, vit wrote: Hello, why does this code fail to compile? ```d struct Foo(T){ this(Rhs, this This)(scope Rhs rhs){ } this(ref scope typeof(this) rhs){ } } struct Bar{ Foo!int foo; } void main(){ } ``` error: Segmentation fault (core dumped) The problem is that the compiler will try to generate an inout copy constructor for Bar that looks roughly like this: ``` this(ref scope inout(Bar) p) inout { this.foo = p; } ``` The idea behind this lowering is to try and call the copy constructor for Foo object if possible. One issue here is that copy constructors have the same symbol name as constructors (__ctor), so `this.foo = p` gets lowered to `foo.__ctor(p)`. Since both the instance and the parameter are inout, the copy constructor of Foo cannot be called, so the templated constructor is called. After generating the template instance of the constructor, you end up with `this(scope inout(Foo)) inout` ; that is basically an rvalue constructor. This is not valid code; if you write: ``` struct Foo(T){ //this(Rhs, this This)(scope Rhs rhs){} this(scope inout(Foo!int) rhs) inout {} this(ref scope typeof(this) rhs){ } } ``` You will get an error stating that you cannot define both an rvalue constructor and a copy constructor. However, since the constructor is templated it is impossible for the compiler to issue this error before actually instantiating the constructor. I see 2 possible fixes for this: (1) either we rename the copy constructor symbol to __cpCtor so that it does not clash with the normal constructor overload set or (2) when a templated constructor is instantiated, we can check whether it is an rvalue constructor and issue an error if a copy constructor exists. When I implemented the copy constructor I thought that it would better to have the copy constructor on a different overload set than the normal constructors, however, Walter insisted that they have the same name. So, I guess (2) is the way to go. Cheers, RazvanN
Re: A debug class has started
On Tuesday, 14 December 2021 at 08:07:43 UTC, WebFreak001 wrote: The best way would be not doing this at all - when you manipulate strings/arrays in D you can do so by just assigning the elements like this: ```d immutable(char)[] replaceChar(char[] str, char ch1, char ch2) { for (ulong i = 0; i < len; i++) { if (str[i] == ch1) { writefln("Found %c at str[%d]", ch1, i); // fine str[i] = ch2; } } return str.idup; } ``` then when you call it: ```d replaceChar(str.dup, ';', 'X'); ``` or the function more idiomatically: ```d string replaceChar(scope char[] str, char ch1, char ch2) { // ref makes the `c` variable an l-value / assignable and modifies the character when assigned foreach (i, ref c; str) { if (c == ch1) { writefln("Found %s at str[%s]", c, i); c = ch2; } } return str.idup; // you could also not .idup and return char[] and let the caller .idup it when needed } ``` You only really need to work with pointers when you interface with a C library that needs them. This was of course just me 'playing around with pointer casting in D', and not code that I would have deployed. Debugging that code used up an hour of my life .. that I cannot get back I might try out @safe instead ;-)
Immutability and arrays
I am trying to understand why in this two different cases (Simple and Complex), the compiler behaviour is different. ```d struct SimpleStruct { int x;} struct ComplexStruct { int[] x; } void main() { SimpleStruct[] buf1; immutable(SimpleStruct)[] ibuf1; buf1[0 .. 10] = ibuf1[0 .. 10]; //this works ComplexStruct[] buf2; immutable(ComplexStruct)[] ibuf2; buf2[0 .. 10] = ibuf2[0 .. 10]; //error cannot implicitly convert expression `ibuf2[0..10]` of type `immutable(ComplexStruct)[]` to `ComplexStruct[]` } ```
Re: How to define property type to Array!struct?
On Tuesday, 14 December 2021 at 08:12:04 UTC, zoujiaqing wrote: My code: ```D module http.HttpRequest; import std.container; import std.array : Appender; struct HttpRequest { struct Header() { Appender!string name; Appender!string value; } string method; string uri; int versionMajor = 0; int versionMinor = 0; Array!Header headers; ubyte[] content; bool keepAlive = false; } ``` Error code: ```D source/http/HttpRequest.d(18,5): Error: struct `std.container.array.Array` does not match any template declaration ``` the problem is that your header is a template, so you need to instantiate it: ```d Array!(Header!()) headers; ``` the error message is kinda poor here. Alternatively, remove the template `()` from your `struct Header`
How to define property type to Array!struct?
My code: ```D module http.HttpRequest; import std.container; import std.array : Appender; struct HttpRequest { struct Header() { Appender!string name; Appender!string value; } string method; string uri; int versionMajor = 0; int versionMinor = 0; Array!Header headers; ubyte[] content; bool keepAlive = false; } ``` Error code: ```D source/http/HttpRequest.d(18,5): Error: struct `std.container.array.Array` does not match any template declaration ```
Re: A debug class has started
On Monday, 13 December 2021 at 22:43:14 UTC, forkit wrote: [...] //char* w = cast(char*)str; // nope. a pointer to a string constant is // (supposed to be) immutable, so expect undefined behaviour. note: //char* w = cast(char*)str.toStringz; // also ok this is also undefined behavior (toStringz returns an immutable(char)* which you cast away) char* w = strdup(cast(char*)str); // ok this is a C library function - this is risky if your string is not a string literal (may copy too much or segfault) - I would recommend not using this. This will only work properly when you have string literals (strings that are created using `""` in code, no other strings like those that are for example read from user input, from files or dynamically created) //char* w = cast(char*)str.dup; // also ok //char* w = str.dup.ptr; // also ok [...] the last two here are equivalent, I personally prefer the last one. I think these are the idiomatic way how to duplicate a string into writable memory and get the pointer to it. The best way would be not doing this at all - when you manipulate strings/arrays in D you can do so by just assigning the elements like this: ```d immutable(char)[] replaceChar(char[] str, char ch1, char ch2) { for (ulong i = 0; i < len; i++) { if (str[i] == ch1) { writefln("Found %c at str[%d]", ch1, i); // fine str[i] = ch2; } } return str.idup; } ``` then when you call it: ```d replaceChar(str.dup, ';', 'X'); ``` or the function more idiomatically: ```d string replaceChar(scope char[] str, char ch1, char ch2) { // ref makes the `c` variable an l-value / assignable and modifies the character when assigned foreach (i, ref c; str) { if (c == ch1) { writefln("Found %s at str[%s]", c, i); c = ch2; } } return str.idup; // you could also not .idup and return char[] and let the caller .idup it when needed } ``` You only really need to work with pointers when you interface with a C library that needs them.