www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - dChar Error

reply Salih Dincer <salihdb hotmail.com> writes:
Hi All,

What is causing the error in the code snippet below?

```d
void replaceRight(S)(ref S[] str, S[] slc)
{
   size_t len1 = slc.length,
          len2 = str[len1..$].length;
   assert(len1 == len2);
   str[len1..$] = slc;
}

import std.stdio;

void main()
{
   // example one:
   char[] str1 = "cur:€_".dup;
   str1.length.write(": "); // 8:
   str1[4..$].writefln!"[%s]"; // [€_]
     
   str1.replaceRight("$  _".dup);
   str1.writefln!"[%s]"; // [cur:$  _]

   // example two:
   dchar[] str2 = cast(dchar[])"cur:€_"d;
   str2.length.write(": "); // 6:
   str2[4..$].writefln!"[%s]"; // [€_]
   
   str2.replaceRight(cast(dchar[])"$ _"d);
   str2.writefln!"[%s]"; // Error--^
} /* Prints:
   8: [€_]
   [cur:$  _]
   6: [€_]
   Error: program killed by signal 11
*/
```
Why does replaceRight() work fine with a char array, but not a 
dchar array?  Whereas, rvalue and lvalue lengths are equal to 
each other!

SDB 79
Dec 29 2022
next sibling parent reply "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Because, string literals are in Read Only Memory (or should be anyway).

If you write to ROM, it'll of course error by the CPU.

So when you duplicated it, it was no longer in ROM, and therefore writable.
Dec 29 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 30 December 2022 at 04:54:39 UTC, Richard (Rikki) 
Andrew Cattermole wrote:
 
 So when you duplicated it, it was no longer in ROM, and 
 therefore writable.
There is no such thing as a ROM within a function. Because str is a reference and slc is a local copy, right? Have you tried running the code? Okay, no string literals: ```d void main() {  // example one:  char[] str1 = "cur:€_".dup;  str1.length.write(": "); // 8:  str1[4..$].writefln!"[%s]"; // [€_]      char[] slc1 = "$ _".dup;  str1.replaceRight(slc1);  str1.writefln!"[%s]"; // [cur:$  _]  // example two: dchar[] str2 = cast(dchar[])"cur:€_"d;  str2.length.write(": "); // 6:  str2[4..$].writefln!"[%s]"; // [€_]    dchar[] slc2 = cast(dchar[])"$ _"d;  str2.replaceRight(slc2);  str2.writefln!"[%s]"; } ``` SDB 79
Dec 29 2022
parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
On 30/12/2022 6:37 PM, Salih Dincer wrote:
 On Friday, 30 December 2022 at 04:54:39 UTC, Richard (Rikki) Andrew 
 Cattermole wrote:
 So when you duplicated it, it was no longer in ROM, and therefore 
 writable.
There is no such thing as a ROM within a function.
But a function can reference things in ROM, and a function itself can and should be held within ROM.
 Because str is a 
 reference and slc is a local copy, right?
It is a reference to memory that is in ROM. No, it is not a copy of the memory, only of the reference. You shouldn't be casting away immutable btw, (which is what string is!).
 Have you tried running the 
 code?  Okay, no string literals:
Of course; I cannot see anything else that could cause this in the assembly either.
Dec 29 2022
prev sibling parent reply novice2 <sorry noem.ail> writes:
On Friday, 30 December 2022 at 04:43:48 UTC, Salih Dincer wrote:
   ...
   // example one:
   char[] str1 = "cur:€_".dup;
   ...
   // example two:
   dchar[] str2 = cast(dchar[])"cur:€_"d;
   ...
 SDB 79
why you use .dup it example one, but not use in example two? dchar[] str2 = cast(dchar[])"cur:€_"d.dup;
Dec 30 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 30 December 2022 at 09:29:16 UTC, novice2 wrote:
 On Friday, 30 December 2022 at 04:43:48 UTC, Salih Dincer wrote:
   ...
   // example one:
   char[] str1 = "cur:€_".dup;
   ...
   // example two:
   dchar[] str2 = cast(dchar[])"cur:€_"d;
   ...
 SDB 79
why you use .dup it example one, but not use in example two? dchar[] str2 = cast(dchar[])"cur:€_"d.dup;
If I do not use .dup in the 1st example and convert as cast(char[]), it gives an error. However, in the 2nd example using .dup does nothing. It's not working anyway! On Friday, 30 December 2022 at 05:46:32 UTC, Richard (Rikki) Andrew Cattermole wrote:
 Of course; I cannot see anything else that could cause this in 
 the assembly either.
I'm not sure I understand this issue. SDB 79
Dec 30 2022
parent reply matheus <matheus gmail.com> writes:
On Friday, 30 December 2022 at 10:03:20 UTC, Salih Dincer wrote:
 On Friday, 30 December 2022 at 09:29:16 UTC, novice2 wrote:
 On Friday, 30 December 2022 at 04:43:48 UTC, Salih Dincer 
 wrote:
   ...
   // example one:
   char[] str1 = "cur:€_".dup;
   ...
   // example two:
   dchar[] str2 = cast(dchar[])"cur:€_"d;
   ...
 SDB 79
why you use .dup it example one, but not use in example two? dchar[] str2 = cast(dchar[])"cur:€_"d.dup;
If I do not use .dup in the 1st example and convert as cast(char[]), it gives an error. However, in the 2nd example using .dup does nothing. It's not working anyway! ...
Are you sure about that? Because replacing this: dchar[] str2 = cast(dchar[])"cur:€_"d; with this: dchar[] str2 = (cast(dchar[])"cur:€_").dup; Worked for me: 8: [€_] [cur:$ _] 6: [€_] [cur$ _] A small example of the problem: import std.stdio; void main(){ dchar[] str1 = (cast(dchar[])"cur:€_").dup; dchar[] str2 = (cast(dchar[])"cur:€_"); str1[0] = '1'; //str2[0] = '1'; // this will give: Error: program killed by signal 11 } Matheus.
Dec 30 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 30 December 2022 at 11:05:07 UTC, matheus wrote:
 Are you sure about that?
Thank you for your answer. You contributed to the project I was working on. In this case, std.conv.to can be used for mutable dchars, right? For example, is this solution the right approach? ```d auto toDchar(S)(inout S str) { import std.conv : to; return str.to!(dchar[]); } void main() { auto str3 = "ÜÇ ON "d; auto str4 = "BİR İKİ BEŞ "d.dup; auto str5 = "DÖRT ALTI YEDİ ".toDchar; //str5.fun(5); } ``` SDB 79
Dec 30 2022
parent reply matheus <matheus gmail.com> writes:
On Friday, 30 December 2022 at 15:28:05 UTC, Salih Dincer wrote:
 ... In this case, std.conv.to can be used for mutable dchars, 
 right? For example, is this solution the right approach?

 ```d
 auto toDchar(S)(inout S str) {
   import std.conv : to;
   return str.to!(dchar[]);
 }

 void main() {
   auto str3 = "ÜÇ ON "d;
   auto str4 = "BÄ°R Ä°KÄ° BEÅž "d.dup;
   auto str5 = "DÖRT ALTI YEDİ ".toDchar;

   //str5.fun(5);
 }
 ```
Unfortunately I can't say because I'm not a skilled D programmer, I use mostly as a C on steroids. But yes I think it will generate a copy (mutable) based on this test: void main(){ import std.stdio; import std.conv; auto str1 = "BÄ°R Ä°KÄ° BEÅž "; auto str2 = str1; auto str3 = str2.to!(dchar[]); writeln(str1, ", ", str1.ptr); writeln(str2, ", ", str2.ptr); writeln(str3, ", ", str3.ptr); str3[0] = 'A'; writeln(str3, ", ", str3.ptr); } It prints: BÄ°R Ä°KÄ° BEÅž , 5641226D8200 BÄ°R Ä°KÄ° BEÅž , 5641226D8200 BÄ°R Ä°KÄ° BEÅž , 7FB466EAE000 AÄ°R Ä°KÄ° BEÅž , 7FB466EAE000 So for str2 = str1 it is just a case of passing the reference, and both are pointing to the same address, while in the case of: "str3 = str2.to!(dchar[]);", the address is different, and accepts changing its content (str3[0] = 'A'). In the docs: https://dlang.org/phobos/std_conv.html#to "String to string conversion works for any two string types having (char, wchar, dchar) character widths and any combination of qualifiers (mutable, const, or immutable)." But I couldn't find if the target will be mutable, but I think it will be, unless explicitly otherwise with a cast I believe. Anyway I would wait and see if someone more skilled could shed a light. Matheus.
Dec 30 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/30/22 13:54, matheus wrote:

 But yes I think it will generate a copy (mutable) based on this test:
In this case it does copy but in the case of dchar[] to dchar[], there will be no copy. Similarly, there is no copy from immutable to immutable.
 the address is different
Good test. :)
 But I couldn't find if the target will be mutable, but I think it will
 be,
The target will always be the type the programmer specifies explicitly. (dchar[] in this case.) Ali
Dec 30 2022
next sibling parent matheus <matheus gmail.com> writes:
On Friday, 30 December 2022 at 22:02:41 UTC, Ali Çehreli wrote:
 On 12/30/22 13:54, matheus wrote:

 But yes I think it will generate a copy (mutable) based on
this test: In this case it does copy but in the case of dchar[] to dchar[], there will be no copy. Similarly, there is no copy from immutable to immutable.
Very interesting I did some testing and you are right. So better to stick with .dup! Thanks for the info, Matheus.
Dec 30 2022
prev sibling parent reply Salih Dincer <salihdb hotmail.com> writes:
On Friday, 30 December 2022 at 22:02:41 UTC, Ali Çehreli wrote:
 But I couldn't find if the target will be mutable, but I
think it will
 be,
The target will always be the type the programmer specifies explicitly. (dchar[] in this case.)
I have one more little question! Is it possible to infer the string without the type the programmer specifies explicitly in the template below? ```d template Fun(dstring str)/* template Fun(T)(T str)/* like this */ { import std.traits : Unconst;  alias T = Unconst!(typeof(str[0]));  auto Fun() { import std.conv : to; auto result = Result();    result.data = str.to!(T[]);    return result;  }   struct Result { union { T[str.length] data; ubyte[T.sizeof * str.length] bytes; } string toString() { import std.format; return format("%s: %(%02X-%)", data, bytes); } } } void main() {  import std.stdio : writeln;  Fun!"β€Ş"w.writeln; // type1: wstring  Fun!"β€Ş"d.writeln; // type2: dstring } ``` That is, the compiler can/must infer between type 1-2 or type 3(string) that it knows at compile time, right? SDB 79
Dec 30 2022
parent reply Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 31 December 2022 at 00:42:50 UTC, Salih Dincer wrote:
 ... it possible to infer
Let me save you the torment of code duplication 😀 Thanks everyone. Yes, I guess there is no other way but to overload. This is both the safest and the fastest. It's also short enough like this: ```d // D 2.0.83 or higher import std.stdio : writeln; import std.conv : to; auto Fun(string str)() { auto result = Values!(char, str.length)(); result.data = str.to!(char[]); return result; } auto Fun(wstring str)() { auto result = Values!(wchar, str.length)(); result.data = str.to!(wchar[]); return result; } auto Fun(dstring str)() { auto result = Values!(dchar, str.length)(); result.data = str.to!(dchar[]); return result; } struct Values(T, size_t len) { union { T[len] data; ubyte[T.sizeof * len] bytes; } string toString() { import std.format; return format("%s: %(%02X-%)", data, bytes); } } void main() { Fun!"β€Ş".writeln; // β€Ş: CE-B2-E2-82-AC-C5-9E Fun!"β€Ş"w.writeln; // β€Ş: B2-03-AC-20-5E-01 Fun!"β€Ş"d.writeln; // B2-03-00-00-AC-20-00-00-5E-01-00-00 } ``` SDB 79
Dec 30 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 12/30/22 17:22, Salih Dincer wrote:

 I guess there is no other way but to overload.
Since the bodies of all three overloads are the same except some types, they can easily be templatized.
 This is both the safest and the fastest.
I didn't think Values is fast with string copies that it makes. ;) I think it was only for showing the byte values but you can do the same by casting to ubyte[] as well. Also, your Fun could work only with string literals; so I used function parameters. import std.traits : isSomeString; // isSomeString may or may not be useful below. (?) auto Fun(S)(S str) if (isSomeString!S) { import std.traits : Unqual; import std.conv : to; alias T = Unqual!S; // Note: The following may or may not copy the string // depending on whether S is the same as T. return str.to!T; } void printBytes(S)(S str) { import std.stdio : writefln; import std.conv : to; // The following cast does not copy anything. writefln!"%(%02X-%)"(cast(ubyte[])str); } void main() { printBytes(Fun("β€Ş")); // CE-B2-E2-82-AC-C5-9E printBytes(Fun("β€Ş"w)); // B2-03-AC-20-5E-01 printBytes(Fun("β€Ş"d)); // B2-03-00-00-AC-20-00-00-5E-01-00-00 } Ali
Dec 30 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Saturday, 31 December 2022 at 02:15:56 UTC, Ali Çehreli wrote:
 On 12/30/22 17:22, Salih Dincer wrote:

 I guess there is no other way but to overload.
Since the bodies of all three overloads are the same except some types, they can easily be templatized.
You took the trouble, thanks, but there is a special reason why I use union. If we want, we can write dynamic version without using std.traits: ```d struct Values(T, size_t len = 1) { union { T[len] data; ubyte[T.sizeof * len] bytes; } string toString() { import std.format; return format("%s: %(%02X-%)", data, bytes); } } alias Char = Values!char; alias Wchar = Values!wchar; alias Dchar = Values!dchar; void main() { import std.stdio : writeln; Char[] str1; str1 ~= Char('B'); str1 ~= Char('E'); str1 ~= Char('$'); str1.writeln; Wchar[] str2; str2 ~= Wchar('β'); str2 ~= Wchar('€'); str2 ~= Wchar('Ş'); str2.writeln; Dchar[] str3; str3 ~= Dchar('β'); str3 ~= Dchar('€'); str3 ~= Dchar('$'); str3.writeln("\n"); Fun!"β€$".writeln; } /* [B: 42, E: 45, $: 24] [β: B2-03, €: AC-20, Ş: 5E-01] [β: B2-03-00-00, €: AC-20-00-00, $: 24-00-00-00] β€$: CE-B2-E2-82-AC-24 */ ``` However, I would like to draw your attention to the last line. Yeah, I won't be able to do that because it's New Year's Eve. But the line is like mixed mode because of the non-char data it contains, right? Happy New Year...
Dec 30 2022