Re: printf, writeln, writefln

2022-12-18 Thread j via Digitalmars-d-learn

On Sunday, 18 December 2022 at 16:17:40 UTC, Salih Dincer wrote:
On Saturday, 10 December 2022 at 11:13:57 UTC, Nick Treleaven 
wrote:
It was bizarre and confusing that assignment syntax was 
implemented for functions and methods not explicitly marked 
with @property.


Hi Nick, do you think this is confusing?

```d
void main()
{
  struct S
  {
int value;

alias opCall this;
this(int i) {
  value = i;
}

alias opAssign = opCall;
@property opCall(int x) {
  return value = x;
}

@property opCall() inout {
  return value;
}

@property opOpAssign(string op)(int x) {
  mixin("return value"~op~"=x;");
}
  }

  S a = S(10),
b = S(-1);

  import std.stdio;
  writeln(a + b); // 9
  writeln(++a + b); // 10
}
```
Actually, my question to everyone is, for example, is this kind 
of wrapping confusing for you?


SDB@79




Yes


Re: printf, writeln, writefln

2022-12-18 Thread Salih Dincer via Digitalmars-d-learn
On Saturday, 10 December 2022 at 11:13:57 UTC, Nick Treleaven 
wrote:
It was bizarre and confusing that assignment syntax was 
implemented for functions and methods not explicitly marked 
with @property.


Hi Nick, do you think this is confusing?

```d
void main()
{
  struct S
  {
int value;

alias opCall this;
this(int i) {
  value = i;
}

alias opAssign = opCall;
@property opCall(int x) {
  return value = x;
}

@property opCall() inout {
  return value;
}

@property opOpAssign(string op)(int x) {
  mixin("return value"~op~"=x;");
}
  }

  S a = S(10),
b = S(-1);

  import std.stdio;
  writeln(a + b); // 9
  writeln(++a + b); // 10
}
```
Actually, my question to everyone is, for example, is this kind 
of wrapping confusing for you?


SDB@79


Re: printf, writeln, writefln

2022-12-10 Thread Nick Treleaven via Digitalmars-d-learn

On Thursday, 8 December 2022 at 17:39:58 UTC, Ali Çehreli wrote:

On 12/8/22 08:21, Salih Dincer wrote:

> void stringCopy(Chars)(string source,
>  ref Chars target)

>sample.stringCopy = cTxt;  // disappeared ? char

Nothing disappeared on my system. (?)

Going off-topic, I find the expression above extremely 
confusing. I am used to assignment expression changing the 
value of the left hand side, but that expression changes cTxt. 
Very confusing...


Such obfuscations make it very hard for me to understand what 
the code is trying to demonstrate.


Yes, with function call syntax it's more understandable if an 
argument is modified.


It was bizarre and confusing that assignment syntax was 
implemented for functions and methods not explicitly marked with 
@property.




Re: printf, writeln, writefln

2022-12-08 Thread Salih Dincer via Digitalmars-d-learn

On Thursday, 8 December 2022 apt 17:39:58 UTC, Ali Çehreli wrote:

> ```d
> void stringCopy(Chars)(string source,
>  ref Chars target)
>
>sample.stringCopy = cTxt;  // disappeared ? char
> ```
I find the expression above extremely confusing. I am used to 
assignment expression changing the value of the left hand side, 
but that expression changes cTxt.


You're right, it's my fault. Copy commands are always used as 
source on the left and target on the right. I have to get rid of 
this habit. Immediately I'm swapping parameters and fixing...


```d

  stringCopy(cText, sample); // or
  cText.stringCopy(sample):  // or
  cText.stringCopy = sample; // tricky 
```

@SDB79


Re: printf, writeln, writefln

2022-12-08 Thread Ali Çehreli via Digitalmars-d-learn

On 12/8/22 08:21, Salih Dincer wrote:

> void stringCopy(Chars)(string source,
>  ref Chars target)

>sample.stringCopy = cTxt;  // disappeared ? char

Nothing disappeared on my system. (?)

Going off-topic, I find the expression above extremely confusing. I am 
used to assignment expression changing the value of the left hand side, 
but that expression changes cTxt. Very confusing...


Such obfuscations make it very hard for me to understand what the code 
is trying to demonstrate.


Ali



Re: printf, writeln, writefln

2022-12-08 Thread Salih Dincer via Digitalmars-d-learn

On Tuesday, 6 December 2022 at 23:41:09 UTC, H. S. Teoh wrote:
On Tue, Dec 06, 2022 at 11:07:32PM +, johannes via 
Digitalmars-d-learn wrote:

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 
delimited c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));

[...]

In D, strings are not the same as char*.  You should use 
std.conv.fromStringZ to convert the C char* to a D string.




Well, if we think the other way around, in the example below we'd 
copy string, right?


```d
void stringCopy(Chars)(string source,
ref Chars target)
{
  import std.algorithm : min;
  auto len = min(target.length - 1,
 source.length);
  target[0 .. len] = source[0 .. len];
  target[len] = '\0';
}

import std.stdio;
void main()
{ //  |- 21 chars --| |-- 8 --|
  string sample = "bu bir deneme olmakta\0gizlimi?";
  char[30] cTxt; // 29 + 1'\0'

  sample.stringCopy = cTxt;  // disappeared ? char
  cTxt.writeln;  // appeared 28 chars

  printf("%s\n", cTxt.ptr);  // appeared 21 chars
  printf("%s\n", [22]); // appeared 7 chars
  writefln!"%(%02X %)"(cast(ubyte[])cTxt);
}
```

Attention, the method used is again a slicing...

SDB@79


Re: printf, writeln, writefln

2022-12-08 Thread Salih Dincer via Digitalmars-d-learn

On Tuesday, 6 December 2022 at 23:41:09 UTC, H. S. Teoh wrote:
On Tue, Dec 06, 2022 at 11:07:32PM +, johannes via 
Digitalmars-d-learn wrote:

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 
delimited c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));

[...]

In D, strings are not the same as char*.  You should use 
std.conv.fromStringZ to convert the C char* to a D string.




Well, if we think the other way around, in the example below we'd 
copy string, right?


```d
void stringCopy(Chars)(string source,
ref Chars target)
{
  import std.algorithm : min;
  auto len = min(target.length - 1,
 source.length);
  target[0 .. len] = source[0 .. len];
  target[len] = '\0';
}

import std.stdio;
void main()
{ //  |- 21 chars --| |-- 8 --|
  string sample = "bu bir deneme olmakta\0gizlimi?";
  char[30] cTxt; // 29 + 1'\0'

  sample.stringCopy = cTxt;  // disappeared ? char
  cTxt.writeln;  // appeared 28 chars

  printf("%s\n", cTxt.ptr);  // appeared 21 chars
  printf("%s\n", [22]); // appeared 7 chars
  writefln!"%(%02X %)"(cast(ubyte[])cTxt);
}
```

Attention, the method used is again a slicing...

SDB@79


Re: printf, writeln, writefln

2022-12-08 Thread johannes via Digitalmars-d-learn

Thank you all for those explanations. Helps a lot!


Re: printf, writeln, writefln

2022-12-07 Thread Ali Çehreli via Digitalmars-d-learn

On 12/6/22 15:07, johannes wrote:

> 'write' prints out the address
> of the first byte. This is odd to me because printf does the job
> correctly.

printf behaves as what you expect because %s means dereferencing the 
pointer values and printing the char contents until printf sees '\0'.


> But I think to understand that write in D interpretes char*
> as a pointer to a byte.

Because it is. :) char* is nothing but a pointer to char. ('byte' exists 
as well, so I user 'char'.)


> it seems the
> formatting "%s" has another meaning in D ?

Yes. %s means the string representation of the variable. Sring 
representation of a pointer happens to be the hexadecimal representation 
of its value.


User-defined types can define a toSring() member function to decide how 
their string representation should be.


%s is the default: write(x) or writeln(x) would print like %s would.

This all works because these functions are templates, taking advantage 
of type deduction: They know the exact type of what they are printing. 
So, %s is known for that type.


printf that came from C is not templatized, so the programmer has to 
tell it what to do like with %s.


Ali



Re: printf, writeln, writefln

2022-12-06 Thread ag0aep6g via Digitalmars-d-learn

On 07.12.22 01:35, ryuukk_ wrote:

On Tuesday, 6 December 2022 at 23:41:09 UTC, H. S. Teoh wrote:

[...]
In D, strings are not the same as char*.  You should use 
std.conv.fromStringZ to convert the C char* to a D string.

[...]

no, you don't "need" to use std conv


Here is an alternative that doesn't allocate

[...]
     // now we got a len, we can build a D string, remember, it's just a 
slice


     string str = cast(string) ret[0 .. len];


Slicing is exactly what std.string.fromStringz does.

:
"The returned array is a slice of the original buffer. The original data 
is not changed and not copied."


Re: printf, writeln, writefln

2022-12-06 Thread ryuukk_ via Digitalmars-d-learn
On Wednesday, 7 December 2022 at 01:46:21 UTC, Siarhei Siamashka 
wrote:

On Tuesday, 6 December 2022 at 23:07:32 UTC, johannes wrote:

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 
delimited c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));
writefln("%s",sqlite3_column_text(res, i));
writefln(std.conv.to!string(sqlite3_column_text(res, i)));

//-- the result :
the sun is shining
55B504B3CE98
55B504B3CE98
the sun is shining

=> without 'std.conv.to!string' I presume 'write' prints out 
the address of the first byte. This is odd to me because 
printf does the job correctly. But I think to understand that 
write in D interpretes char* as a pointer to a byte. So it 
prints the address that the pointer points to.(?)
So the question : for every c funtion returning char* I will 
have to use std.conv.to!string(..) or is there another way. 
Also it seems the formatting "%s" has another meaning in D ?


What you are posting here is a perfect example of unsafe code. 
Let's looks at it:


```D
import std;

char *sqlite3_column_text() @system {
return cast(char *)"the sun is shining".ptr;
}

void main() {
printf("%s\n",sqlite3_column_text());
writeln(sqlite3_column_text());
writefln("%s",sqlite3_column_text());
writefln(std.conv.to!string(sqlite3_column_text()));
}
```

Unsafe code has a lot of rules, which have to be carefully 
followed if you want to stay out of troubles. It's necessary to 
check the [sqlite3 
documentation](https://www.sqlite.org/c3ref/column_blob.html) 
to see who is responsible for deallocating the returned 
c-string and what is its expected lifetime (basically, the 
sqlite3 library takes care of managing the returned memory 
buffer and it's valid only until you make some other sqlite3 
API calls).


So the use of "printf" is fine.

Direct "writeln"/"writefln" prints the pointer value, which 
also fine (but not what you expect).


Doing "std.conv.to!string" allocates a copy of the string, 
managed by the garbage collector (and this may be undesirable 
for performance reasons).


Doing 
[std.conv.fromStringz](https://dlang.org/library/std/string/from_stringz.html) as suggested by H. S. Teoh would avoid allocation, but you need to be careful with it:


```D
char[] s1 = fromStringz(sqlite3_column_text());

writeln(s1); // everything is fine

char[] s2 = fromStringz(sqlite3_column_text()); // some 
other sqlite3 API call


writeln(s1); // oops, sqlite3 may have already messed up s1
```

Depending on what sqlite3 is doing under the hood, this may be 
a good example of "use after free" security issue discussed [in 
another forum 
thread](https://forum.dlang.org/post/mailman.2828.1670270281.31357.digitalmar...@puremagic.com).



But hold on! Isn't D a safe language, supposed to protect you 
from danger? The answer is that it is safe, but the compiler 
will only watch your back if you explicitly annotate your code 
with a [@safe 
attribute](https://dlang.org/spec/memory-safe-d.html) (and use 
the "-dip1000" compiler command line option too). If you do 
this, then the compiler will start complaining a lot. Try it:


```D
@safe:
import std;

char *sqlite3_column_text() @system {
return cast(char *)"the sun is shining".ptr;
}

string trusted_sqlite3_column_text() @trusted {
return std.conv.to!string(sqlite3_column_text());
}

void main() {
printf("%s\n",sqlite3_column_text());// Nay!
writeln(sqlite3_column_text());  // Nay!
writefln("%s",sqlite3_column_text());// Nay!
writefln(std.conv.to!string(sqlite3_column_text())); // Nay!
writeln(trusted_sqlite3_column_text());  // Yay!
}
```

The "trusted_sqlite3_column_text" wrapper function does a 
memory allocation and it's up to you to decide whether this is 
acceptable. You are always free to write unsafe code tuned for 
best performance (annotated as @system or @trusted), but it's 
your own responsibility if you make a mistake.


BTW, maybe it's even more efficient to use 
sqlite3_column_blob() and sqlite3_column_bytes() for retrieving 
the column text as a string?


That's a good point, but there also no error checking for the 
sqlite return, but that's not the point, ``std.conv.to!string`` 
doesn't teach about the difference between c string and d string, 
it hides the magic


Doing it manually teaches it, that was the point


Re: printf, writeln, writefln

2022-12-06 Thread Siarhei Siamashka via Digitalmars-d-learn

On Tuesday, 6 December 2022 at 23:07:32 UTC, johannes wrote:

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 
delimited c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));
writefln("%s",sqlite3_column_text(res, i));
writefln(std.conv.to!string(sqlite3_column_text(res, i)));

//-- the result :
the sun is shining
55B504B3CE98
55B504B3CE98
the sun is shining

=> without 'std.conv.to!string' I presume 'write' prints out 
the address of the first byte. This is odd to me because printf 
does the job correctly. But I think to understand that write in 
D interpretes char* as a pointer to a byte. So it prints the 
address that the pointer points to.(?)
So the question : for every c funtion returning char* I will 
have to use std.conv.to!string(..) or is there another way. 
Also it seems the formatting "%s" has another meaning in D ?


What you are posting here is a perfect example of unsafe code. 
Let's looks at it:


```D
import std;

char *sqlite3_column_text() @system {
return cast(char *)"the sun is shining".ptr;
}

void main() {
printf("%s\n",sqlite3_column_text());
writeln(sqlite3_column_text());
writefln("%s",sqlite3_column_text());
writefln(std.conv.to!string(sqlite3_column_text()));
}
```

Unsafe code has a lot of rules, which have to be carefully 
followed if you want to stay out of troubles. It's necessary to 
check the [sqlite3 
documentation](https://www.sqlite.org/c3ref/column_blob.html) to 
see who is responsible for deallocating the returned c-string and 
what is its expected lifetime (basically, the sqlite3 library 
takes care of managing the returned memory buffer and it's valid 
only until you make some other sqlite3 API calls).


So the use of "printf" is fine.

Direct "writeln"/"writefln" prints the pointer value, which also 
fine (but not what you expect).


Doing "std.conv.to!string" allocates a copy of the string, 
managed by the garbage collector (and this may be undesirable for 
performance reasons).


Doing 
[std.conv.fromStringz](https://dlang.org/library/std/string/from_stringz.html) as suggested by H. S. Teoh would avoid allocation, but you need to be careful with it:


```D
char[] s1 = fromStringz(sqlite3_column_text());

writeln(s1); // everything is fine

char[] s2 = fromStringz(sqlite3_column_text()); // some other 
sqlite3 API call


writeln(s1); // oops, sqlite3 may have already messed up s1
```

Depending on what sqlite3 is doing under the hood, this may be a 
good example of "use after free" security issue discussed [in 
another forum 
thread](https://forum.dlang.org/post/mailman.2828.1670270281.31357.digitalmar...@puremagic.com).



But hold on! Isn't D a safe language, supposed to protect you 
from danger? The answer is that it is safe, but the compiler will 
only watch your back if you explicitly annotate your code with a 
[@safe attribute](https://dlang.org/spec/memory-safe-d.html) (and 
use the "-dip1000" compiler command line option too). If you do 
this, then the compiler will start complaining a lot. Try it:


```D
@safe:
import std;

char *sqlite3_column_text() @system {
return cast(char *)"the sun is shining".ptr;
}

string trusted_sqlite3_column_text() @trusted {
return std.conv.to!string(sqlite3_column_text());
}

void main() {
printf("%s\n",sqlite3_column_text());// Nay!
writeln(sqlite3_column_text());  // Nay!
writefln("%s",sqlite3_column_text());// Nay!
writefln(std.conv.to!string(sqlite3_column_text())); // Nay!
writeln(trusted_sqlite3_column_text());  // Yay!
}
```

The "trusted_sqlite3_column_text" wrapper function does a memory 
allocation and it's up to you to decide whether this is 
acceptable. You are always free to write unsafe code tuned for 
best performance (annotated as @system or @trusted), but it's 
your own responsibility if you make a mistake.


BTW, maybe it's even more efficient to use sqlite3_column_blob() 
and sqlite3_column_bytes() for retrieving the column text as a 
string?


Re: printf, writeln, writefln

2022-12-06 Thread ryuukk_ via Digitalmars-d-learn

On Tuesday, 6 December 2022 at 23:41:09 UTC, H. S. Teoh wrote:
On Tue, Dec 06, 2022 at 11:07:32PM +, johannes via 
Digitalmars-d-learn wrote:

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 
delimited c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));

[...]

In D, strings are not the same as char*.  You should use 
std.conv.fromStringZ to convert the C char* to a D string.



T



no, you don't "need" to use std conv


Here is an alternative that doesn't allocate

Make sure to read the comments


```D

// here notice where the functions are comming from
import std.stdio : writeln, writefln;

import core.stdc.stdio : printf;
import core.stdc.string : strlen;

const(char)* sqlite3_column_text(void*, int iCol)
{
return "hello world";
}

void main()
{
// printf is a libc function, it expects a null terminated 
string (char*)

printf("%s\n", sqlite3_column_text(null, 0));

// writeln is a d function, it expects a string (immutable 
slice of char aka immutable(char)[], a slice is T* + len)


// so here we get the string from sqlite
const(char)* ret = sqlite3_column_text(null, 0);


// then we need to determine the length of the null 
terminated string from c

// we can use strlen from libc

size_t len = strlen(ret);

// now we got a len, we can build a D string, remember, it's 
just a slice


string str = cast(string) ret[0 .. len];

writeln(str);
writefln("%s", str);
}
```


Re: printf, writeln, writefln

2022-12-06 Thread H. S. Teoh via Digitalmars-d-learn
On Tue, Dec 06, 2022 at 11:07:32PM +, johannes via Digitalmars-d-learn 
wrote:
> //-- the result should be f.i. "the sun is shining"
> //-- sqlite3_column_text returns a constant char* a \0 delimited c-string
> printf("%s\n",sqlite3_column_text(res, i));
> writeln(sqlite3_column_text(res, i));
[...]

In D, strings are not the same as char*.  You should use
std.conv.fromStringZ to convert the C char* to a D string.


T

-- 
For every argument for something, there is always an equal and opposite 
argument against it. Debates don't give answers, only wounded or inflated egos.


printf, writeln, writefln

2022-12-06 Thread johannes via Digitalmars-d-learn

//-- the result should be f.i. "the sun is shining"
//-- sqlite3_column_text returns a constant char* a \0 delimited 
c-string

printf("%s\n",sqlite3_column_text(res, i));
writeln(sqlite3_column_text(res, i));
writefln("%s",sqlite3_column_text(res, i));
writefln(std.conv.to!string(sqlite3_column_text(res, i)));

//-- the result :
the sun is shining
55B504B3CE98
55B504B3CE98
the sun is shining

=> without 'std.conv.to!string' I presume 'write' prints out the 
address of the first byte. This is odd to me because printf does 
the job correctly. But I think to understand that write in D 
interpretes char* as a pointer to a byte. So it prints the 
address that the pointer points to.(?)
So the question : for every c funtion returning char* I will have 
to use std.conv.to!string(..) or is there another way. Also it 
seems the formatting "%s" has another meaning in D ?