Re: Avoiding const?

2012-02-22 Thread Timon Gehr

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)[]
}
}












Re: Avoiding const?

2012-02-21 Thread Ali Çehreli

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



Re: Avoiding const?

2012-02-21 Thread Jonathan M Davis
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


Re: Avoiding const?

2012-02-21 Thread ixid
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?


Re: Avoiding const?

2012-02-21 Thread Jonathan M Davis
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


Re: Avoiding const?

2012-02-21 Thread ixid

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.


Re: Avoiding const?

2012-02-21 Thread Jonathan M Davis
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


Re: Avoiding const?

2012-02-21 Thread BLM
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.