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

[FEEDBACK] Possible simplification of the data model #786

Open
tomasr8 opened this issue May 11, 2024 · 5 comments · May be fixed by #799
Open

[FEEDBACK] Possible simplification of the data model #786

tomasr8 opened this issue May 11, 2024 · 5 comments · May be fixed by #799
Labels
data model Issues related with MF data Model Preview-Feedback Feedback gathered during the technical preview

Comments

@tomasr8
Copy link

tomasr8 commented May 11, 2024

I am currently working on implementing the mf2 spec in Python and I'm trying to understand why FunctionExpression and UnsupportedExpression are two separate entities in the data model. Could we simply combine them similar to LiteralExpression and VariableExpression?

This is what I mean:

interface FunctionExpression {
  type: "expression";
  arg?: never;
- annotation: FunctionAnnotation;
+ annotation: FunctionAnnotation | UnsupportedAnnotation;
  attributes: Attribute[];
}

- interface UnsupportedExpression {
-   type: "expression";
-   arg?: never;
-   annotation: UnsupportedAnnotation;
-   attributes: Attribute[];
- }

This should not introduce any ambiguity because you can always tell which expression you're working with based on the annotation type.

@tomasr8 tomasr8 added the Preview-Feedback Feedback gathered during the technical preview label May 11, 2024
@alerque
Copy link
Contributor

alerque commented May 11, 2024

No, implementing this in type safe languages would be a nightmare if the same types needed to be able to hold valid usable data and and invalid/partially invalid data. It makes the outer type nearly useless and you have to implement a ton of code just to figure out what you have and handle different cases vs. just having the right type up front.

@tomasr8
Copy link
Author

tomasr8 commented May 11, 2024

Agreed, but from my understanding that is currently the case with VariableExpression and LiteralExpression anyway. You need to inspect the annotation to know if you're dealing with an unsupported expression. Only with FunctionExpression can you tell immediately by the type itself.

@alerque
Copy link
Contributor

alerque commented May 11, 2024

Good catch. In which case I'd argue those should be reworked to match this one, not the other way around. 😉

@tomasr8
Copy link
Author

tomasr8 commented May 11, 2024

Good catch. In which case I'd argue those should be reworked to match this one, not the other way around. 😉

Indeed, that would be better :) In that case, I'd propose something like this:

interface LiteralExpression {
  type: "expression";
  arg: Literal;
- annotation?: FunctionAnnotation | UnsupportedAnnotation;
+ annotation?: FunctionAnnotation;
  attributes: Attribute[];
}

interface VariableExpression {
  type: "expression";
  arg: VariableRef;
- annotation?: FunctionAnnotation | UnsupportedAnnotation;
+ annotation?: FunctionAnnotation;
  attributes: Attribute[];
}

interface FunctionExpression {
  type: "expression";
  arg?: never;
  annotation: FunctionAnnotation;
  attributes: Attribute[];
}

interface UnsupportedExpression {
  type: "expression";
- arg?: never;
+ arg?: Literal | VariableRef;
  annotation: UnsupportedAnnotation;
  attributes: Attribute[];
}

@aphillips aphillips added data model Issues related with MF data Model Agenda+ and removed Agenda+ labels May 12, 2024
@eemeli
Copy link
Collaborator

eemeli commented May 14, 2024

I am currently working on implementing the mf2 spec in Python and I'm trying to understand why FunctionExpression and UnsupportedExpression are two separate entities in the data model. Could we simply combine them similar to LiteralExpression and VariableExpression?

Sure, we could, but that wouldn't really change anything. Note that these are TypeScript interface definitions, so a value matching the current definition would also match your proposed alternative.

There are two main reasons why Expression is split up the way it is:

  1. We need a VariableExpression definition, because it's used in InputDeclaration.
  2. We want to represent the requirement of having at least arg or annotation be non-empty in the data model.

So when implementing your internal data model, you may want to see if you can drop those requirements, which allows for a single, simpler Expression:

interface Expression {
  type: "expression";
  arg?: Literal | VariableRef;
  annotation?: FunctionAnnotation | UnsupportedAnnotation;
  attributes: Attribute[];
}

To use that, you'll need to separately verify that either arg or annotation is present, and you'll need to collapse the declarations into a single definition:

interface Declaration {
  name: string;
  value: Expression;
}

This is all possible because the TS representation of the data model is not really intended to support interchange between systems; that's what the JSON Schema and DTD definitions are for.

For an example Python datamodel that applies the above simplifications, see message.py in the moz.l10n package that I'm currently working on.

@eemeli eemeli linked a pull request May 22, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
data model Issues related with MF data Model Preview-Feedback Feedback gathered during the technical preview
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants