digitalmars.D.learn - Avoiding const?
- ixid (9/9) Feb 21 2012 I apologize for what I'm sure is a very basic question. How
- BLM (16/16) Feb 21 2012 If you have a const array, you can create a non-const copy of the array ...
- Jonathan M Davis (13/33) Feb 21 2012 The inner characters are going to need to be immutable anyway.
- ixid (27/31) Feb 21 2012 BLM:
- Jonathan M Davis (36/80) Feb 21 2012 1. Don't use the built-in sort. It's going to be deprecated. Use
- ixid (9/9) Feb 21 2012 Thank you, I'll read those articles. Is there a more elegant way
- Jonathan M Davis (16/26) Feb 21 2012 Sort returns a SortedRange, so if you passed it to a function which coul...
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (7/10) Feb 21 2012 May I shamelessly recommend the Ranges chapter of my
- Timon Gehr (58/67) Feb 22 2012 Use bool set[string]. You cannot index an AA with a mutable array. The
I apologize for what I'm sure is a very basic question. How should I do this elegantly? bool set[char[]]; //Stuff char[][] words = set.keys; It gives the error: Error: cannot implicitly convert expression (set.keys()) of type const(char)[][] to char[][] and I'm not sure why I can't copy const data to normal data.
Feb 21 2012
If you have a const array, you can create a non-const copy of the array using the .dup property of the array. The reason that you need this is that dynamic-length arrays share data when you assign them between variables, and you can't have a non-const variable using something else's const data without running into some really nasty problems. In your specific case, though, the .dup property might not convert the inner levels of the nested array. If it doesn't work, you could try something like this: char[][] words; words.length = set.keys.length; foreach(size_t i, const char[] text; set.keys) { words[i] = text.dup; } If you don't really need to modify the individual characters in the array, you might just want to stick with const; it will be more efficient. You might also want to define the set as bool[string] because associative arrays prefer const/immutable keys for some reason.
Feb 21 2012
On Wednesday, February 22, 2012 01:25:12 BLM wrote:If you have a const array, you can create a non-const copy of the array using the .dup property of the array. The reason that you need this is that dynamic-length arrays share data when you assign them between variables, and you can't have a non-const variable using something else's const data without running into some really nasty problems. In your specific case, though, the .dup property might not convert the inner levels of the nested array. If it doesn't work, you could try something like this: char[][] words; words.length = set.keys.length; foreach(size_t i, const char[] text; set.keys) { words[i] = text.dup; } If you don't really need to modify the individual characters in the array, you might just want to stick with const; it will be more efficient. You might also want to define the set as bool[string] because associative arrays prefer const/immutable keys for some reason.The inner characters are going to need to be immutable anyway. bool[char[]] set; doesn't work, because the key isn't immutable. When he tries to use it the compiler will scream at him (though ideally, it wouldn't even let him declare it - there's a bug report on that). So, his AA is going to need to be bool[string] set; Then there's not need to dup the inner array unless he really insists on having the chars be mutable. But it would be far more normal to leave them as immutable - i.e. as string. So, all he should need is auto words = set.keys.dup; and he'll get a string[]. - Jonathan M Davis
Feb 21 2012
BLM: const(char)[][] words = set.keys.sort; Converting the function's return type to const and doing this did what I wanted elegantly, I didn't realise I could apply sort to a const like this. Trying to use .dup like this: char[][] words = set.keys.dup; gives this error message: Error: cannot implicitly convert expression (_adSort(_adDupT(& D13TypeInfo_AAxa6__initZ,set.keys()),& D11TypeInfo_Aa6__initZ)) of type const(char)[][] to char[][] Isn't there any sort of cast(nonconst) equivalent? char[][] words; words.length = set.keys.length; foreach(size_t i, const char[] text; set.keys) { words[i] = text.dup; } This also worked, thank you for the suggestion. Jonathan M Davies:bool[char[]] set;doesn't work, because the key isn't immutable. When he tries to use it the compiler will scream at him (though ideally, it wouldn't even let him declare it - there's a bug report on that).When I use a key with it I use: set[cast(immutable) key] = true; This doesn't generate any compiler errors. auto words2 = set.keys.sort; auto words2 = set.keys.dup.sort; both did what I wanted using string. Thank you, I'll convert everything to strings. I guess I created my own difficulties by using char arrays.
Feb 21 2012
On Wednesday, February 22, 2012 03:07:38 ixid wrote:BLM: const(char)[][] words = set.keys.sort; Converting the function's return type to const and doing this did what I wanted elegantly, I didn't realise I could apply sort to a const like this. Trying to use .dup like this: char[][] words = set.keys.dup; gives this error message: Error: cannot implicitly convert expression (_adSort(_adDupT(& D13TypeInfo_AAxa6__initZ,set.keys()),& D11TypeInfo_Aa6__initZ)) of type const(char)[][] to char[][] Isn't there any sort of cast(nonconst) equivalent?1. Don't use the built-in sort. It's going to be deprecated. Use std.algorithm.sort. 2. You should pretty much _never_ cast away const or immutable in D unless you really know what you're doing. Casting away const or immutable and then modifying a variable is undefined (unlike in C++). It violates the compiler's guarantees and risks segfaulting and the like.char[][] words; words.length = set.keys.length; foreach(size_t i, const char[] text; set.keys) { words[i] = text.dup; } This also worked, thank you for the suggestion. Jonathan M Davies:_Don't_ cast to immutable unless you can _guarantee_ that there are no other references to the variable being cast. You're going to get bugs otherwise. In general, if you're doing any casts to or from const or immutable, you're doing something wrong (there are exceptions - primarily involving passing stuff across threads - but again, you have to know what you're doing). If the key is not already immutable (or has immutable elements in the case of an array), then you need to actually get an immutable version, not cast it. In the case of an array, that would mean using idup. However, even better would be to use std.conv.to. That way, if the array or its elements are already immutable, you don't end up needlessly copying the array. For instance, bool[string] set; set[to!string(key)] = value;bool[char[]] set; doesn't work, because the key isn't immutable. When he tries to use it the compiler will scream at him (though ideally, it wouldn't even let him declare it - there's a bug report on that).When I use a key with it I use: set[cast(immutable) key] = true; This doesn't generate any compiler errors. auto words2 = set.keys.sort; auto words2 = set.keys.dup.sort;both did what I wanted using string. Thank you, I'll convert everything to strings. I guess I created my own difficulties by using char arrays.Yes. In general, you should be using string (which is immutable(char)[]) rather than char[]. In general, modifying an array of char just doesn't make sense (particularly in light of unicode), and you'll generally run into fewer difficulties. It also helps avoid duplication, because you never need to copy arrays of immutable elements unless you need a mutable copy, whereas you tend to have to copy arrays of mutable elements to avoid having stuff modify them. Also, more functions in the standard library support string than char[]. This question on stackoverflow would be good to look at for a more detailed explanation with regards to AAs and immutability: http://stackoverflow.com/questions/4611477/why-cant-i-store-string-keys-in-an- associative-array Also, if you haven't read it yet, you should read this article on arrays: http://www.dsource.org/projects/dcollections/wiki/ArrayArticle It should help you understand how they work, which will hopefully help you avoid some headaches. - Jonathan M Davis
Feb 21 2012
Thank you, I'll read those articles. Is there a more elegant way than this to get the string[] out of a range after using the algorithms sort? Ranges are a bit of a mystery. string[] temp; foreach(i;sort(set.keys)) temp ~= to!string(i); I'm a little worried that the very basic level of my posts is spamming the forum, is there a D community forum for absolute beginners?
Feb 21 2012
On Wednesday, February 22, 2012 04:42:05 ixid wrote:Thank you, I'll read those articles. Is there a more elegant way than this to get the string[] out of a range after using the algorithms sort? Ranges are a bit of a mystery. string[] temp; foreach(i;sort(set.keys)) temp ~= to!string(i);Sort returns a SortedRange, so if you passed it to a function which could take advantage of that (such as find), it would be more efficient to use the result of sort, but sort sorts in place. So, if you want a new array, what you should probably do is simply auto temp = set.keys.dup; sort(temp); However, I think that .keys returns a newly allocated array such that you don't need to dup it at all if you don't want to, which means that you'd do something more like auto temp = set.keys; sort(temp);I'm a little worried that the very basic level of my posts is spamming the forum, is there a D community forum for absolute beginners?This pretty much _is_ the forum for absolute beginners. The whole point of this forum is to answer questions for those learning D. It's digitalmars.D which is for general discussion on D. You're in the right place. - Jonathan M Davis
Feb 21 2012
On 02/21/2012 07:42 PM, ixid wrote:Ranges are a bit of a mystery.May I shamelessly recommend the Ranges chapter of my about-30%-translated book: http://ddili.org/ders/d.en/ranges.htmlI'm a little worried that the very basic level of my posts is spamming the forumNot at all! We are all learning from all sorts of questions and answers here. :) Ali
Feb 21 2012
On 02/22/2012 02:13 AM, ixid wrote:I apologize for what I'm sure is a very basic question. How should I do this elegantly? bool set[char[]];Use bool set[string]. You cannot index an AA with a mutable array. The declaration you give will be rejected by the compiler soon.//Stuff char[][] words = set.keys; It gives the error: Error: cannot implicitly convert expression (set.keys()) of type const(char)[][] to char[][] and I'm not sure why I can't copy const data to normal data.Assuming you change the declaration to bool set[string], your error will look like: Error: cannot implicitly convert expression (set.keys()) of type string[] to char[][]. (string is the same as immutable(char)[]) The reason for the immutable key requirement is that associative arrays are impossible to be implemented efficiently if their keys can be changed randomly from outside the data structure. Here is why the assignment would make this possible: Dynamic arrays are reference types. This means that they don't contain the data. They just point to it. This means that multiple dynamic array variables can point to the same data. This is called aliasing: import std.stdio; void main() { int[] x = [1,2,3]; // a [...] literal creates a new array writeln(x); // "[1,2,3]" int[] y = x; // y now refers to ('aliases') the same array y[0] = 2; // this therefore changes the data x refers to writeln(x); // "[2,2,3]" } Now assume assigning immutable data to a mutable reference would succeed: import std.stdio; void main() { immutable int[] x = [1,2,3]; // creates a new immutable array int[] y = x; // creates mutable-immutable aliasing (compile error) y[0] = 2; // this would then change x, which is illegal because it is immutable } import std.stdio; void main() { immutable int[] x = [1,2,3]; // create a new array int[] y = x.dup;// make a mutable copy of it; this actually copies the data y[0]=2; writeln(x); // "[1,2,3]" (x is unchanged, good) } The general issue is still there if immutable is burried two references deep. import std.stdio; void main(){ immutable(int)[][] x = [[1],[2],[3]]; int[][] y = x; // error y[0][0] = 2; } However, there is no built-in functionality to copy all the immutable data that is reachable from the top. import std.stdio; void main(){ immutable(int)[][] x = [[1],[2],[3]]; auto y = new int[][](x.length); // create an array of the appropriate length foreach(i,e; x){ y[i] = e.dup; // e is of type immutable(int)[] } }
Feb 22 2012