Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modifier/Note Mixin Classes (Discussion) #1515

Closed
mscuthbert opened this issue Jan 1, 2023 · 1 comment
Closed

Modifier/Note Mixin Classes (Discussion) #1515

mscuthbert opened this issue Jan 1, 2023 · 1 comment

Comments

@mscuthbert
Copy link
Collaborator

In #1513 at the (current) bottom, I noticed a bug that is a little bit hard to fix in TimeSigNote (because its glyph is stored pretty far down in the system). And I've realized that the same bugs take place anywhere there is a lot of shared code between a Modifier (or StaveModifier) and a Note. (For instance, Clef and ClefNote; KeySignature and KeySignatureNote). And the difficulty of writing a new Note is probably why we don't have XNote versions of every modifier/stavemodifier.

In other languages, like Python, the answer would be pretty simple: Create something like ClefBase which has all the information that is currently in the Clef (StaveModifier), and then do:

class Clef(ClefBase, StaveModifier)...
class ClefNote(ClefBase, Note)...

and voila! two related classes deriving from different superclasses but with their shared guts in one place.

The problem of course is that JS does not have multiple inheritance. It is possible to do so with Mixin functions that return classes:

function ClefBase(baseClass) {
     return class ClefBase extends baseClass {
            setType(...) { }
     }
}

export class Clef extends ClefBase(StaveModifier) {}
export class ClefNote extends ClefBase(Note) {}

I did this in a lot of projects in the past, and it was really helpful (especially in music21j where I had to port a lot of ideas from Python which has multiple inheritance).

I think that such mixin interfaces would go a long way to avoiding bugs in computing widths, collisions, etc.

It is, however, harder in TypeScript, so just in case we go in this direction, just to note how to set up a TypeScript happy mixin.

  1. make sure that the assumed class to be mixed into is specified as the minimum base. Here, it'd be Element.
  2. Specify that the class passed into the mixin must be the constructor for that base class.
  3. There may be a need for a class between Element and Tickable(Note)/Modifier/StaveModifier that takes care of some of the similarities between them that we assume exists (setXShift()) -- this might be a good thing even if we don't go this route.

TypeScript version:

type GConstructor<T = {}> = new (...args: any[]) => T;
type ElementDerived = GConstructor<Element>;
export function ClefMixin<TBase extends ElementDerived>(Base: TBase)  {
    return class ClefMixin extends Base {
           setType(...) { }
    }
}

thoughts?

@mscuthbert
Copy link
Collaborator Author

Didn't realize that there was a separate tab for discussions -- closing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant