-
-
Notifications
You must be signed in to change notification settings - Fork 3.1k
Description
One of the best simple changes Zig gives us over C is the ability to have actual arrays/slices (not just pointers) in our code. However, after playing with these arrays, I found that the type checking did not make sense to me. I hope that this issue will either:
- Explain exactly what the rules are for slices and arrays in the type system (Hopefully even get this information in the documentation).
- Or, if it needs to change, discuss what should change.
Ok, so let me explain why I have a problem understanding the type system behind arrays and slices. First, the documentation doesn't seem to explain the use of const in types such as pointers and slices. This means, I kinda have to go by what I think it means, which is: []const i64 means a slice, whose elements cannot be changed or a slice of const i64.
With this in mind, let's go use arrays and slices.
// A slice, whose elements can be changed
var slice: []i64 = undefined;
// A slice, whose elements can't be changed
var sliceOfConstElements: []const i64 = undefined;
// An array, whose elements can be changed
var arrayOfSize: [4]i64 = undefined;
// An array, whose elements can't be changed
// NOTE: This will not compile.
// var arrayOfSizeWithConstElements: [4]const i64 = undefined; // error: const qualifier invalid on array type
slice[0] = 1;
sliceOfConstElements[0] = 1; // error: cannot assign to constant
arrayOfSize[0] = 1;
// arrayOfSizeWithConstElements[0] = 1;
Ok, so far so good. I seems I'm not totally misunderstanding it since sliceOfConstElements[0] = 1; gave an error. I wonder why we can't have arrays of constant elements though...
Next, we ofcourse want to be able to assign our variables to values, instead of undefined:
var slice: []i64 = []i64{ 1, 2, 3, 4 }; // error: expected type '[]i64', found '[4]i64'
var sliceOfConstElements: []const i64 = []i64{ 1, 2, 3, 4 };
var arrayOfSize: [4]i64 = []i64{ 1, 2, 3, 4 };
Ooh, so I can't assign a slice to an array literal? But I can if the slice is const? Why? My best guess is, that apparently [4]i64 actually implicitly is const. Why not call the type [4]const i64?
Well, ok. Let's test something then. Can I declare const in the literal?
var slice: []i64 = []const i64{ 1, 2, 3, 4 }; // error: expected type '[]i64', found '[4]i64'
var sliceOfConstElements: []const i64 = []const i64{ 1, 2, 3, 4 };
var arrayOfSize: [4]i64 = []const i64{ 1, 2, 3, 4 };
I can? Ooook? So what is the difference between []const i64{ 1, 2, 3, 4 } and []i64{ 1, 2, 3, 4 }?
// Test 1/1 Array literal types...reached unreachable code
test "Array literal types" {
if (@typeOf([]i64{ 1, 2, 3 }) == @typeOf([]const i64{ 2, 4, 6 })) {
unreachable;
}
}
No difference? So I guess the compiler does not respect const in array literals.
I could go on with my story format like this, but I think you all get that this is confusing me a little. Here is a bigger piece of code, that outlines more things that confuse me:
fn useSlice(slice: []i64) { }
fn useSliceConst(slice: []const i64) { }
pub fn main() -> %void {
var varArray = []i64 { 1, 2, 3 };
const constArray = []i64 { 1, 2, 3 };
var varArrayConst = []const i64 { 1, 2, 3 };
const constArrayConst = []const i64 { 1, 2, 3 };
var varArrayExplicit : []i64 = []i64 { 1, 2, 3 }; // error: expected type '[]i64', found '[3]i64'. Why?
const constArrayExplicit : []i64 = []i64 { 1, 2, 3 }; // error: expected type '[]i64', found '[3]i64'. Why?
var varArrayConstExplicit : []const i64 = []i64 { 1, 2, 3 }; // No error? Why?
const constArrayConstExplicit: []const i64 = []i64 { 1, 2, 3 }; // No error? Why?
var varArrayExplicitLiteralConst : []i64 = []const i64 { 1, 2, 3 }; // error: expected type '[]i64', found '[3]i64'
const constArrayExplicitLiteralConst : []i64 = []const i64 { 1, 2, 3 }; // error: expected type '[]i64', found '[3]i64'. Ok, so we can see here, that the const declartion does not make the type const
var varArrayConstExplicitLiteralConst : []const i64 = []const i64 { 1, 2, 3 };
const constArrayConstExplicitLiteralConst: []const i64 = []const i64 { 1, 2, 3 };
//
// Reassign
//
varArray = []i64 { 2, 4, 6 };
constArray = []i64 { 2, 4, 6 }; // error: cannot assign to constant
varArrayConst = []i64 { 2, 4, 6 }; // No error? Why? Does the compile no respect the const in []const i64{ ... }?
constArrayConst = []i64 { 2, 4, 6 }; // error: cannot assign to constant
// I guess these all make sense
varArray = []i64 { 2, 4 }; // error: expected type '[3]i64', found '[2]i64'
constArray = []i64 { 2, 4 }; // error: cannot assign to constant
varArrayConst = []i64 { 2, 4 }; // error: expected type '[3]i64', found '[2]i64'
constArrayConst = []i64 { 2, 4 }; // error: cannot assign to constant
varArray = []const i64 { 2, 4, 6 }; // No error? Why?
constArray = []const i64 { 2, 4, 6 }; // error: cannot assign to constant
varArrayConst = []const i64 { 2, 4, 6 };
constArrayConst = []const i64 { 2, 4, 6 }; // error: cannot assign to constant
// I guess these all make sense
varArray = []const i64 { 2, 4 }; // error: expected type '[3]i64', found '[2]i64'
constArray = []const i64 { 2, 4 }; // error: cannot assign to constant
varArrayConst = []const i64 { 2, 4 }; // error: expected type '[3]i64', found '[2]i64'
constArrayConst = []const i64 { 2, 4 }; // error: cannot assign to constant
//
// Assign element
//
varArray [0] = 5;
constArray [0] = 5; // error: cannot assign to constant. Why? I guess const declared arrays have const elements?
varArrayConst [0] = 5; // No error? Why?
constArrayConst[0] = 5; // error: cannot assign to constant
//
// Func taking non const element slice
//
useSlice(varArray); // error: expected type '[]i64', found '[3]i64'. Why no implicit convertion to slice?
useSlice(constArray); // error: expected type '[]i64', found '[3]i64'. If implicit convertion happend here, this probably still shouldn't work, because of the implicit const elements.
useSlice(varArrayConst); // error: expected type '[]i64', found '[3]i64'. This should still give error after an implicit convertion to slice.
useSlice(constArrayConst); // error: expected type '[]i64', found '[3]i64'. This should still give error after an implicit convertion to slice.
useSlice([]i64{ 1, 2, 3 }); // error: expected type '[]i64', found '[3]i64'. Should this be allowed if we have implicit slice convertion?
useSlice([]const i64{ 1, 2, 3 }); // error: expected type '[]i64', found '[3]i64'. This probably shouldn't.
//
// Func taking const element slice
//
// So if we mark a func to take const element slices, then we get the implicit convertion to slice always?
useSliceConst(varArray);
useSliceConst(constArray);
useSliceConst(varArrayConst);
useSliceConst(constArrayConst);
useSlice([]i64{ 1, 2, 3 }); // No error? Isn't this a type missmatch?
useSlice([]const i64{ 1, 2, 3 });
}