www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Avoiding const?

reply "ixid" <nuaccount gmail.com> writes:
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
next sibling parent reply BLM <blm768 gmail.com> writes:
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
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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
parent reply "ixid" <nuaccount gmail.com> writes:
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
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
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:
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;
_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;
 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
parent reply "ixid" <nuaccount gmail.com> writes:
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
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
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
prev sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
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.html
 I'm a little worried that the very basic level of my posts is spamming
 the forum
Not at all! We are all learning from all sorts of questions and answers here. :) Ali
Feb 21 2012
prev sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
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