www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - properly passing strings to functions? (C++ vs D)

reply zack <no-way-zack no-web.de> writes:
A beginner question: How to pass strings properly to functions in 
D?
Is there any allocation going on if just use a function as 
"myPrint"? In C++ I have often seen calls where one just passes a 
reference/const reference to a string to avoid allocation.

C++:
void myPrintCPP(const std::string& input){ ... }

D:
void myPrint(string text){ ... }
void myPrintRef(ref string text) { ... }

So the question is does a function call like (ref string ...) 
(myPrintRef) make any sense in D to avoid additional allocations?

A D-Style String could be seen as "const(char)[]"? So as it is a 
slice it already is a kind of reference to some data elsewhere? 
Which means calling a function like "myPrint" in D wouldn't cause 
any allocation. Is this correct?

Thank's for your help.
Jan 11 2021
next sibling parent rikki cattermole <rikki cattermole.co.nz> writes:
On 12/01/2021 3:12 AM, zack wrote:
 A beginner question: How to pass strings properly to functions in D?
 Is there any allocation going on if just use a function as "myPrint"? In 
 C++ I have often seen calls where one just passes a reference/const 
 reference to a string to avoid allocation.
 
 C++:
 void myPrintCPP(const std::string& input){ ... }
 
 D:
 void myPrint(string text){ ... }
 void myPrintRef(ref string text) { ... }
If you are modifying text the reference and want the caller to see the change, use this.
 So the question is does a function call like (ref string ...) 
 (myPrintRef) make any sense in D to avoid additional allocations?
There are no allocations for this.
 A D-Style String could be seen as "const(char)[]"? So as it is a slice 
 it already is a kind of reference to some data elsewhere? Which means 
 calling a function like "myPrint" in D wouldn't cause any allocation. Is 
 this correct?
alias string = immutable(char)[]; https://github.com/dlang/druntime/blob/master/src/object.d
Jan 11 2021
prev sibling next sibling parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote:
 A beginner question: How to pass strings properly to functions 
 in D?
 Is there any allocation going on if just use a function as 
 "myPrint"? In C++ I have often seen calls where one just passes 
 a reference/const reference to a string to avoid allocation.
C++ strings are reference counted, I think, so it is more to avoid a reference count increment than to avoid a collection.
 A D-Style String could be seen as "const(char)[]"? So as it is 
 a slice it already is a kind of reference to some data 
 elsewhere? Which means calling a function like "myPrint" in D 
 wouldn't cause any allocation. Is this correct?
D strings are backed by GC so they are passed by reference too.
Jan 11 2021
parent reply Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 January 2021 at 15:23:23 UTC, Ola Fosheim Grøstad 
wrote:
 On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote:
 A beginner question: How to pass strings properly to functions 
 in D?
 Is there any allocation going on if just use a function as 
 "myPrint"? In C++ I have often seen calls where one just 
 passes a reference/const reference to a string to avoid 
 allocation.
C++ strings are reference counted, I think, so it is more to avoid a reference count increment than to avoid a collection.
I meant allocation... The following prints "1", so no allocation. #include <iostream> #include <string> std::string a("hello world"); void f(std::string b){ std::cout << (b.data() == a.data()) << std::endl; } int main() { f(a); }
Jan 11 2021
parent reply zack <no-way-zack no-web.de> writes:
On Monday, 11 January 2021 at 15:25:58 UTC, Ola Fosheim Grøstad 
wrote:
 I meant allocation... The following prints "1", so no 
 allocation.
Just tried on Windows with Visual Studio, it prints "0". So I guess this is platform/compiler dependent.
Jan 11 2021
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 1/11/21 8:22 AM, zack wrote:
 On Monday, 11 January 2021 at 15:25:58 UTC, Ola Fosheim Gr=C3=B8stad wr=
ote:
 I meant allocation... The following prints "1", so no allocation.
=20 Just tried on Windows with Visual Studio, it prints "0". So I guess thi=
s=20
 is platform/compiler dependent.
Yes. Earlier C++ string implementations used reference counting, which=20 caused multi-threading complications; so, many implementations switched=20 to copying. Ali
Jan 11 2021
parent Ola Fosheim =?UTF-8?B?R3LDuHN0YWQ=?= <ola.fosheim.grostad gmail.com> writes:
On Monday, 11 January 2021 at 16:40:53 UTC, Ali Çehreli wrote:
 Yes. Earlier C++ string implementations used reference 
 counting, which caused multi-threading complications; so, many 
 implementations switched to copying.
Ah, I guess I've never used std::string for anything that requires speed. Turns out that cpp.sh is outdated.
Jan 11 2021
prev sibling next sibling parent reply IGotD- <nise nise.com> writes:
On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote:
 D:
 void myPrint(string text){ ... }
 void myPrintRef(ref string text) { ... }
In D strings are immutable so there will be no copying when passing as function parameters. Strings are essentially like slices when passing them. I usually use "const string text" because D has no implicit declaration of variables. So using "ref" will not create a variable. This is contrary to C++ where passing as "const std::string &text" has a performance benefit and also C++ creates a unnamed variable for you. ex. void myFunction1(const string text); void myFunction2(const ref string text); myFunction1("test"); myFunction2("test"); -------> error cannot create an implicit reference then you have to do like this string t = "text"; myFunction2(t); This will work but you have to do the extra step by declaring t. Annoying as you cannot write text literals directly in the function parameters, therefore I do not use "ref" and it doesn't have a big benefit in D either.
Jan 11 2021
parent reply Q. Schroll <qs.il.paperinik gmail.com> writes:
On Monday, 11 January 2021 at 16:53:50 UTC, IGotD- wrote:
 I usually use "const string text" because D has no implicit 
 declaration of variables. So using "ref" will not create a 
 variable. This is contrary to C++ where passing as "const 
 std::string &text" has a performance benefit and also C++ 
 creates a unnamed variable for you.
Did you consider `in`? It will do that in some time and do it now with -preview=in. If you're using `const`, in almost all cases, `in` will work, too, and be better (and shorter).
Jan 12 2021
parent IGotD- <nise nise.com> writes:
On Tuesday, 12 January 2021 at 18:12:14 UTC, Q. Schroll wrote:
 Did you consider `in`? It will do that in some time and do it 
 now with -preview=in.
 If you're using `const`, in almost all cases, `in` will work, 
 too, and be better (and shorter).
Has the redesignation of "in" like in the preview been formally accepted as a part of language? I know that it was suggested to make "in" the optimized parameter passing for const which I like. However, if I'm going to use it I need to know if this going to be accepted as I don't want go around and change all the parameters back again if it was not accepted.
Jan 12 2021
prev sibling parent Q. Schroll <qs.il.paperinik gmail.com> writes:
On Monday, 11 January 2021 at 14:12:57 UTC, zack wrote:
 A beginner question: How to pass strings properly to functions 
 in D?
 Is there any allocation going on if just use a function as 
 "myPrint"? In C++ I have often seen calls where one just passes 
 a reference/const reference to a string to avoid allocation.

 C++:
 void myPrintCPP(const std::string& input){ ... }

 D:
 void myPrint(string text){ ... }
 void myPrintRef(ref string text) { ... }
In D, `string` is an abbreviation for the type immutable(char)[], i.e. slice of immutable char. The slice type is a pointer+length pair, a (T*, size_t) tuple, it is very lightweight. Using `ref T[]` (that includes `ref string` aka `ref immutable(char)[]` is the way if you want reassignments or expanding/shrinking of the array to be visible to the caller. Since the cost of copying a pointer and a length is very low, I'd just use this: void myPrint(string text) { ... } It'll be probably what you want. Since you cannot write the immutable characters, if you don't intend to reassign, expand, or shrink the string locally, you can use `in string text`. You can basically only read `in` parameters for information. What `in` buys you is that the compiler will figure out the best way to pass the object. C++'s const T& will reference always, which is worse than a copy for small types. D's `in` will copy if the compiler thinks it's cheaper than referencing. Give https://dlang.org/changelog/2.094.0.html#preview-in a read, if you want details about `in`. Use it when it applies. It also documents intent.
Jan 12 2021