How to initialize a static array literal of struct elements

This code works (v0.13.0):

const std = @import("std");

const NoteEvent = struct {
    pitch: u8,
    velocity: u8,
    note_position: f32,
    duration: f32,

    pub fn debugPrint(self: @This()) void {
        std.debug.print("NoteEvent{{ .pitch = {[pitch]}, .velocity: {[velocity]}, .note_position: {[note_position]}, .duration: {[duration]} }}\n", self);
    }
};

const Measure = struct {
    notes: []const NoteEvent, // added const here
};

const Track = struct {
    name: []const u8, // added const here
    measures: []const Measure, // added const here
};

const SongSection = struct {
    tempo: u32 = 120,
    time_signature: [2]u8 = .{ 4, 4 },
    tracks: []const Track, // added const here

    pub fn getMeasureDurationMs(self: SongSection) u32 { // removed * here
        return self.time_signature[0] * self.getBeatDurationMs();
    }

    pub fn getBeatDurationMs(self: SongSection) u32 { // removed * here
        return 60000 / self.tempo;
    }
};

fn printNotes(notes: []const NoteEvent) void {
    for (notes) |note| note.debugPrint();
}

fn printMeasure(measure: Measure) void {
    printNotes(measure.notes);
}

pub fn main() !void {
    const notes = [_]NoteEvent{
        .{ .pitch = 60, .velocity = 127, .note_position = 0, .duration = 1 },
        .{ .pitch = 62, .velocity = 127, .note_position = 1, .duration = 3 },
    };
    printNotes(&notes);

    // this works:
    const measure = Measure{ .notes = &notes };
    printMeasure(measure);

    // this too :)
    const measure2 = Measure{
        .notes = &.{
            .{ .pitch = 60, .velocity = 127, .note_position = 0, .duration = 1 },
            .{ .pitch = 62, .velocity = 127, .note_position = 1, .duration = 3 },
        },
    };
    printMeasure(measure2);
}

I think the big lesson here (as I’ve seen recommended by many others) is to always start out with const and if you get an error because you need mutability, then make it non-const. As you can see, by just making all those slices and function parameters const, all the errors went away and you can create slices from literals (as in measure2) since literals are always const.

Always keep in mind, you can go from non-const to const safely with no problems, so you could pass in that slice from ArrayList as you mentioned. Going from const to non-const, however, is unsafe (that’s why it requries an explicit @constCast) and thus will make your functions and struct fields more restrictive instead of more general.

2 Likes