Jump to page: 1 2
Thread overview
properly passing strings to functions? (C++ vs D)
Jan 11
zack
Jan 11
zack
Jan 11
IGotD-
6 days ago
Q. Schroll
5 days ago
IGotD-
6 days ago
Q. Schroll
January 11
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.

January 12
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

January 11
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.


January 11
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);
}


January 11
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.
January 11
On 1/11/21 8:22 AM, zack wrote:
> 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.

Yes. Earlier C++ string implementations used reference counting, which caused multi-threading complications; so, many implementations switched to copying.

Ali

January 11
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.

January 11
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.

6 days ago
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.
6 days ago
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).
« First   ‹ Prev
1 2