You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: articles/d-array-article.dd
+14-1Lines changed: 14 additions & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -38,6 +38,7 @@ $(P So how does D improve things? In many ways, D's arrays are similar to C's a
38
38
39
39
$(P Let's see some D slices in action:)
40
40
41
+
$(RUNNABLE_EXAMPLE
41
42
------
42
43
import std.stdio;
43
44
@@ -69,6 +70,7 @@ void main()
69
70
b = d[0..2]; // slices can point at fixed sized arrays too!
70
71
}
71
72
------
73
+
)
72
74
73
75
$(P You may notice something puzzling about the description of the allocation of the array: "allocate a dynamic array of integers that has at least 5 elements, and give me a slice to the first 5." Why isn't it just "allocate a dynamic array of 5 elements"? Even experienced D coders have trouble with D's array concepts sometimes, and for quite good reason. D's slices are $(I not) proper dynamic array types (at least not under the hood) even though they appear to be. What they do is provide a safe and easy $(I interface) to arrays of any type (dynamic or otherwise). So let's discuss probably the most common misconception of D slices.
74
76
)
@@ -84,6 +86,7 @@ $(P So where is the true dynamic array type in D? It's hidden by the runtime, a
84
86
$(P Another consequence of this is that the length is not an array property, it's a slice property. This means the length field is not necessarily the length of the array, it's the length of the slice. This can be confusing to newcomers to the language. For instance, this code has a large flaw in it:
85
87
)
86
88
89
+
$(RUNNABLE_EXAMPLE
87
90
------
88
91
import std.stdio;
89
92
@@ -100,6 +103,7 @@ void main()
100
103
writeln(arr.length); // outputs 5
101
104
}
102
105
------
106
+
)
103
107
104
108
$(P This might look like you changed the passed $(D arr)'s length to 2, but it actually did not affect anything (as is proven by the output from $(D writeln)). This is because even though the data is passed by reference, the actual pointer and length are passed by value. Many languages have an array type whose properties are all passed by reference. Notably, C# and Java arrays are actually fully referenced Objects. C++'s vector either passes both its data and properties by reference or by value.)
105
109
@@ -117,19 +121,23 @@ $(H2 $(LNAME2 append-on, A Slice You Can Append On))
117
121
118
122
$(P D's slices support appending more data to the end of the slice, much like a true dynamic array type. The language has a specific operator used for concatenation and appending, the tilde ($(D ~)). Here are some operations that append and concatenate arrays:)
119
123
124
+
$(RUNNABLE_EXAMPLE
120
125
------
121
126
int[] a; // an empty slice references no data, but still can be appended to
122
127
a ~= 1; // append some integers, this automatically allocates a new
123
128
a ~= 2; // array to hold the elements.
124
129
125
130
a ~= [3, 4]; // append another array (this time, an array literal)
126
131
a = a ~ a; // concatenate a with itself, a is now [1, 2, 3, 4, 1, 2, 3, 4]
132
+
writeln(a);
127
133
128
134
int[5] b; // a fixed-size array on the stack
129
135
a = b[1..$]; // a is a slice of b
130
136
a ~= 5; // since a was pointing to stack data, appending always reallocates,
131
137
// but works!
138
+
writeln(a); // [0, 0, 0, 0, 5]
132
139
------
140
+
)
133
141
134
142
$(P Anyone who cares about performance will wonder what happens when you append the four elements. The slice does not own its data, so how does one avoid reallocating a new array on each append operation? One of the main requirements of D slices are that they are efficient. Otherwise, coders would not use them. D has solved this problem in a way that is virtually transparent to the programmer, and this is one of the reasons slices seem more like true dynamic arrays.)
135
143
@@ -211,27 +219,32 @@ foreach (int i; 0..50)
211
219
212
220
$(P $(REF1_ALTTEXT $(D size_t capacity), capacity, object): A property which gives you the number of elements the slice can hold via appending. If the slice cannot be appended in place, this returns 0. Note that capacity (if non-zero) includes the current slice elements.)
213
221
222
+
$(RUNNABLE_EXAMPLE
214
223
------
215
224
int[] slice = new int[5];
216
225
assert(slice.capacity == 7); // includes the 5 pre-allocated elements
226
+
217
227
int[] slice2 = slice;
218
228
slice.length = 6;
219
229
assert(slice.capacity == 7); // appending in place doesn't change the capacity.
220
230
assert(slice2.capacity == 0); // cannot append slice2 because it would stomp on
221
231
// slice's 6th element
222
232
------
233
+
)
223
234
224
235
$(P $(REF1_ALTTEXT $(D assumeSafeAppend()), assumeSafeAppend, object): This method forces the runtime to assume it is safe to append a slice. Essentially this adjusts the $(I used) field of the array to end at the same spot the slice ends.)
225
236
237
+
$(RUNNABLE_EXAMPLE
226
238
------
227
239
int[] slice = new int[5];
228
240
slice = slice[0..2];
229
241
assert(slice.capacity == 0); // not safe to append, there is other valid data in the block.
230
242
slice.assumeSafeAppend();
231
243
assert(slice.capacity == 7); // force the used data to 2 elements
232
244
------
245
+
)
233
246
234
-
$(P If D slices' append performance just isn't up to snuff for your performance requirements, there is another alternative. The $(REF Appender, std,array) type will append data to an array as fast as possible, without any need to look up metadata from the runtime. $(REF Appender, std,array) also supports the output range idiom via an append operation (normal slices only support the output range by overwriting their own data).)
247
+
$(P If D slices' append performance just isn't up to snuff for your performance requirements, there is another alternative. The $(REF Appender, std,array) type will append data to an array as fast as possible, without any need to look up metadata from the runtime. $(REF Appender, std,array) also supports the $(REF_ALTTEXT output range, isOutputRange, std,range,primitives) idiom via an append operation (normal slices only support the output range by overwriting their own data).)
0 commit comments