digitalmars.D.learn - trying to understand in, inout, and ref...
- mark (27/27) Jan 22 2020 I have these code snippets:
- Paul Backus (6/15) Jan 22 2020 For parameters that shouldn't be changed, use const. So it should
- mark (17/32) Jan 22 2020 That single change produces (using LDC 1.19.0 - D 2.089.1):
- Adam D. Ruppe (15/18) Jan 22 2020 They are pointers passed by value.
- mark (4/22) Jan 22 2020 Thanks - that's exactly what I needed to know!
- Steven Schveighoffer (31/38) Jan 22 2020 So just to clarify this a bit for AAs. Adding or removing elements from
I have these code snippets: alias WordList = string[]; alias WordSet = int[string]; // key = word; value = 0 WordList generate(WordSet allWords, int steps) { WordList ladder; // will be changed in update() auto words = allWords.dup; // will be changed in update() auto compatibles = allWords.dup; // will be changed in this function auto prev = update(ladder, words, compatibles); // TODO return ladder; } string update(WordList ladder, WordSet words, WordSet compatibles) { auto word = ""; // TODO random string from compatibles // TODO remove word from words; add word to ladder return word; } Regarding generate(): allWords should never be changed (generate is called in a loop with the same allWords every time) -- so should it be `in WordSet allWords`? Regarding update(): ladder and words are both modified in update -- so should they be `ref WordList ladder` and `ref WordSet words`? And if so, do I need to change the update() call in the generate() function? compatibles is (will be) modified in generate() but not in update(), so should it be `in WordSet compatibles`?
Jan 22 2020
On Wednesday, 22 January 2020 at 10:49:07 UTC, mark wrote:Regarding generate(): allWords should never be changed (generate is called in a loop with the same allWords every time) -- so should it be `in WordSet allWords`?For parameters that shouldn't be changed, use const. So it should be `const WordSet allWords`.Regarding update(): ladder and words are both modified in update -- so should they be `ref WordList ladder` and `ref WordSet words`? And if so, do I need to change the update() call in the generate() function?Yes, they should be `ref`. No, you do not have to change the update() call.compatibles is (will be) modified in generate() but not in update(), so should it be `in WordSet compatibles`?It should be `const WordSet compatibles`.
Jan 22 2020
On Wednesday, 22 January 2020 at 14:23:53 UTC, Paul Backus wrote:On Wednesday, 22 January 2020 at 10:49:07 UTC, mark wrote:That single change produces (using LDC 1.19.0 - D 2.089.1): ./wordladder.d(52): Error: function wordladder.update(string[] ladder, int[string] words, const(int[string]) compatibles) is not callable using argument types (string[], const(int)[string], const(int)[string]) ./wordladder.d(52): cannot pass argument words of type const(int)[string] to parameter int[string] words Failed: ["/home/mark/opt/ldc2-1.19.0-linux-x86_64/bin/ldmd2", "-v", "-o-", "./wordladder.d", "-I."] So I've rolled it back.Regarding generate(): allWords should never be changed (generate is called in a loop with the same allWords every time) -- so should it be `in WordSet allWords`?For parameters that shouldn't be changed, use const. So it should be `const WordSet allWords`.I've done this but my impression from the docs is that passing slices and associative arrays is already done by reference so these aren't needed? (I can't tell yet because I haven't written the modifying code.)Regarding update(): ladder and words are both modified in update -- so should they be `ref WordList ladder` and `ref WordSet words`? And if so, do I need to change the update() call in the generate() function?Yes, they should be `ref`. No, you do not have to change the update() call.Done that and it compiles fine. Thanks.compatibles is (will be) modified in generate() but not in update(), so should it be `in WordSet compatibles`?It should be `const WordSet compatibles`.
Jan 22 2020
On Wednesday, 22 January 2020 at 15:26:06 UTC, mark wrote:I've done this but my impression from the docs is that passing slices and associative arrays is already done by reference so these aren't needed?They are pointers passed by value. If you're familiar with C, think of passing struct Array { size_t length; element* ptr; } The elements are passed by ref there; they aren't copied to the function and any changes to them will be visible outside. BUT if you change the length of it or reallocate it in any way those changes are NOT seen outside. So with AAs and slices, if you just want to work with existing elements, no need for ref. But if you are going to do any kind of resizing - adding or removing elements - ref is likely what you want.
Jan 22 2020
On Wednesday, 22 January 2020 at 15:33:44 UTC, Adam D. Ruppe wrote:On Wednesday, 22 January 2020 at 15:26:06 UTC, mark wrote:Thanks - that's exactly what I needed to know! (I'm also very much enjoying your D Cookbook.)I've done this but my impression from the docs is that passing slices and associative arrays is already done by reference so these aren't needed?They are pointers passed by value. If you're familiar with C, think of passing struct Array { size_t length; element* ptr; } The elements are passed by ref there; they aren't copied to the function and any changes to them will be visible outside. BUT if you change the length of it or reallocate it in any way those changes are NOT seen outside. So with AAs and slices, if you just want to work with existing elements, no need for ref. But if you are going to do any kind of resizing - adding or removing elements - ref is likely what you want.
Jan 22 2020
On 1/22/20 10:33 AM, Adam D. Ruppe wrote:BUT if you change the length of it or reallocate it in any way those changes are NOT seen outside. So with AAs and slices, if you just want to work with existing elements, no need for ref. But if you are going to do any kind of resizing - adding or removing elements - ref is likely what you want.So just to clarify this a bit for AAs. Adding or removing elements from an AA DOES get seen outside, even if you don't pass by ref, except for one case -- the AA is in its initial state. The reason is because an AA is actually a pointer-to-implementation (pImpl) struct, which is initialized to null, but allocated on first element added. So if you don't add any elements, and pass it by value, you are passing null by value, and adding elements will allocate it. But the result doesn't get seen back at the parameter you passed. However, if you add one element, and then pass it, the implementation is already allocated and does not change locations. So then you can add more elements even if you pass by value, and the implementation stays at the same location. example: void foo(int[int] p) { p[1] = 1; p[2] = 2; } int[int] aa; foo(aa); assert(aa.length == 0); // new allocation in foo not seen aa[0] = 0; // first initialization, no longer null foo(aa); assert(aa.length == 3); // now, you see the changes aa.clear(); // remove all elements, but don't deallocate. assert(aa.length == 0); foo(aa); assert(aa.length == 2); // was already preallocated, so impl stays the same. This aspect is very confusing to many people. -Steve
Jan 22 2020