Associated constants vs free constants

I am working on a crate with a musical interval type and a lot of associated constants.

impl Interval {
    pub const DIM_1: Self = Self::Unison(PerfectQuality::DIMINISHED);
    pub const PERF_1: Self = Self::Unison(PerfectQuality::PERFECT);
    pub const AUG_1: Self = Self::Unison(PerfectQuality::AUGMENTED);

    pub const DIM_2: Self = Self::Second(ImperfectQuality::DIMINISHED);
    pub const MIN_2: Self = Self::Second(ImperfectQuality::MINOR);
    pub const MAJ_2: Self = Self::Second(ImperfectQuality::MAJOR);
    pub const AUG_2: Self = Self::Second(ImperfectQuality::AUGMENTED);


I am considering moving these to a submodule as free constants, so that it's easy to import them and just use e.g. MAJ_2 as an interval literal, instead of having to type Interval::MAJ_2 all the time – you also don't type i32::1000 or something if you want a number literal. Then again, I also of the mindset that less typing isn't always a good argument to do something.

Then I realized the standard library does the same with std::f32::consts::PI and friends. But EPSILON got deprecated and is now an associated constant.

So: what are some of the reasons to choose for associated constants vs free ones? Why did the lib team (I assume?) decide to change EPSILON to an associated constant and not PI?

consts aren't literals. I do type i32::MAX if that's what I need.

As to your question, I think it depends somewhat on how it's used. If you only need it in one file and things are well named, a free constant works fine. But if it's used all over the place, one need only import the type instead of doing one of

use path::to::interval::{Interval, Const1, Const2, ConstN};
use path::to::interval::{Interval, self};
// ...
let _ = [interval::DIM_2, interval::MAJ_2];
// module name not type   ^^^^^^^^

And I'd probably go with the assoicated consts in that case.

I didn't take the time to try and understand why the mathematical constants weren't included, but here's the tracking issue for making numeric consts associated if you're curious.

1 Like

Yeah, bit of a misnomer on my end there. I meant it in the sense that those constants represent possible values in the set that is Interval. But from a linguistical perspective it doesn’t make sense. Valid correction. :slight_smile:

Well, here was my initial train of thought: I would put them in a separate consts module. You can then use interval::consts::*. I don't think wildcard imports are usually a great idea, but when working with music you nearly always want all of them available. It's the "alphabet", so to speak.

When they'd be associated constants, you have to prefix them with Interval::.

Thank you for the RFC link (where did you search to find that so quickly?). I quote:

However, although earlier versions of this RFC proposed deprecating std::{f32, f64}::consts (and thereby std::{f32, f64} as well), the current version does not do so, as this was met with mild resistance.

I’ll scour the github thread later to see if I can unearth more.

Happy to hear yours and the opinion of others. :slight_smile:

As a follow-up, I decided to go with associated constants, but under a trait. That way you can just use interval::Scales and get access to all the scales defined for an interval, without cluttering up the type itself. This comes with an added advantage, because I had name clashes between Scales::MAJ_7 and Chords::MAJ_7.

I decided that "you have to prefix every interval and that's cumbersome" is not a good enough reason to write off associated constants. Besides, you can always import as. And maybe, someday, we'll get use-statements for associated constants too.

Aside: What is a diminished unison?

I only know a little bit of music theory, but it seems to me that you can't have two pitches closer together than a perfect unison— That literally means that they're both the same frequency.

You won’t often find one out in the wild, but a diminished unison would be for example g – g flat. It’s more of a theoretical interval, but surely valid.

The raison d’être of the crate is to be able to do music math (adding/subtracting/modulo) intervals, and then you might end up with a dim1 too.

dim8 % perf8 = dim1, for example.

Or: what’s the difference between the fifth note in the major scale and the locrian scale? A diminished unison.

But, good question. :slight_smile:


This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.