Array-of-array constants


#1

Is there some way of writing complex data structures as constants? If not, is this under consideration somewhere (e.g. as part of CTFE)?

I want an array of arrays, however since the length of the internal arrays is not fixed, some kind of abstraction is necessary. This is the best I came up with, though it seems usage of Box isn’t allowed in constants:

/// For each objective (in order), a list of associated scenario numbers:
const OBJECTIVE_SCENARIOS: [Box<[u32]>; NUM_OBJECTIVES as usize] = [
    box [30],       // PREVALENCE_AFTER_INTERVENTION
    box [24, 28, 29, 31, 35, 34],   // PREVALENCE_AGEPATTERN
    box [24,28,29,31,35,34],        // PARASITE_DENSITIES_AGEPATTERN
    box [34],       // MOI_AGEPATTERN
    box [232,233],  // CLINICAL_INCI_AGEPATTERN_A
    box [49],       // CLINICAL_INCI_AGEPATTERN_B
    box [234],      // THRESHOLD_CLINICAL_ATTACK
    box [501,502,503,504,505,506,507,508,509,510,511,512,514,515,516,517,518,
        519, 520,521,522,523,524,525,526,527],  // SEVERE_PRE_PATTERN
    box [158,167,173,176],  // SEVERE_AGEPATTERN
    box [301,302,303,312,316,317,318,326,327],      // MALARIA_MORATALITY
    box [401,402,408,411,414,415,416,417,418,422,426]       // ALL_CAUSE_MORTALITY
];

#2

For your example, I’d use an struct, IMO it seems more readable that way (and you don’t need Box):

struct ObjectiveScenarios {
    prevalence_after_intervention: [u32; 1],
    prevalence_agepattern: [u32; 6],
}

const OBJECTIVE_SCENARIOS: ObjectiveScenarios = ObjectiveScenarios {
    prevalence_after_intervention: [30],
    prevalence_agepattern: [24, 28, 29, 31, 35, 34],
};

fn main() {
    println!("{:?}", OBJECTIVE_SCENARIOS.prevalence_agepattern);
}

Can’t really answer your question about dynamic allocations in constants. My guess is that with CTFE we’ll allow “some” function calls in const/static context, but I’m unsure if we’ll allow dynamic allocation.


#3

Nice idea; shame that it requires repeating all those names.

Ideally I want to be able to take OBJECTIVE_SCENARIOS[some_index] to get one of those lists as a slice &[u32]. Maybe it’s just easier not to use constants for this.

It would also be nice not to have to specify array lengths when writing constant arrays. It seems rather unnecessary.

const LIST: [i32; 6] = [1, 2, 3, 4, 5, 6];

#4

There’s not a concrete proposal (RFC) yet, but we’ll likely allow “untyped constants” in the future, i.e. const LIST = [1, 2, 3], which then can be used where different types are expected: e.g. want_a_fixed_length_array(LIST) and want_a_slice_of_usize(LIST), and the const will be coerced to the expected type: [i32; 6] and &[usize].

For the time being, you could use a const slice to avoid typing/updating the array size: const LIST: &'static [i32] = &[1, 2, 3].

With the struct approach, you could achieve that if you implement Index<Scenario> for ObjectiveScenario where Scenario is an enum with variants PrevalenceAgepattern, PrevalenceAfterIntervention, etc. Then you’ll be able to use OBJECTIVE_SCENARIO[PrevalenceAgepattern] which returns a &[i32], but that’s more work on your part.


I want to throw another idea here (I don’t if it helps in your case): You can also put the consts in the scope of a function rather that having all of them in global scope (which I find cleaner):

fn scenario_one() {
    const MORTALITY: &'static [i32] = &[300, 301, 302];
    const THRESHOLD: i32 = 234;

    // more code here
}

fn scenario_two() {
    const MORTALITY: &'static [i32] = &[200, 201, 202];
    const THRESHOLD: i32 = 232;

    // more code here
}

#5

Oh, those inline rvalue arrays : ) Look at the (unoptimized) IR http://is.gd/uZz9zx I knew const will be a major gotcha. At least it doesn’t (?) affect optimized code.