modelica / ModelicaSpecification

Specification of the Modelica Language
https://specification.modelica.org
Creative Commons Attribution Share Alike 4.0 International
98 stars 41 forks source link

What does an empty annotation mean, if anything? #2852

Open maltelenz opened 3 years ago

maltelenz commented 3 years ago

There seem to be interpretations that adding an empty annotation like annotation(Dialog) means something different than having no annotation at all, see https://github.com/modelica/ModelicaStandardLibrary/issues/3726#issuecomment-762823785 and the discussion following it.

If this is the intended interpretation, should it be made explicit in the specification:

henrikt-ma commented 3 years ago

I don't believe it's the most central question being asked here, but I'd expect annotation(Dialog) to be rejected as malformed, just like this model:

model NoRecordArgumentList
  record R
    Real x = 1.0;
  end R;
  R r = R; /* Missing record constructor argument list! */
end NoRecordArgumentList;

I hope that this is clear enough that it doesn't even require further clarification.

maltelenz commented 3 years ago

I'd expect annotation(Dialog) to be rejected as malformed

I would agree.

I hope that this is clear enough that it doesn't even require further clarification.

It is used in MSL, so it wasn't clear to at least one person/tool: https://github.com/modelica/ModelicaStandardLibrary/blob/403e7c1e9c9399fe0481e593815deb4bae094203/Modelica/Mechanics/MultiBody/Visualizers/Advanced/Arrow.mo#L21

henrikt-ma commented 3 years ago

Regarding an empty argument list, I'm afraid this becomes a separate issue for each annotation.

Defining semantics of an annotation often requires a mix of grammar or pseudo-code record, and a textual description of valid use and special defaults that can't be expressed in grammar or pseudo-code. Note also that it is standard to have semantics depending on the presence of a value.

When designing the new annotations for figures we put much effort into making handling of defaults as explicit as possible, by specifying defaults in the pseudo-code record definitions, rather than relying on textual descriptions of what it means to omit a member in the record constructor. However, it didn't take me long now to see that we failed already at Figure.caption, which doesn't have a default in the pseudo-code record definition, and no textual description of what it means to leave it out. Just like this deserves its own issue being opened (#2851), I'm afraid there is no better solution at this point than also opening issues for any other annotation with unclear defaults – a complete redesign of annotation semantics is probably as unlikely to happen as the proposal to formalize annotation types using algebraic data types.

henrikt-ma commented 3 years ago

Technically, I don't see that it would be necessary for the default behavior to be the same as the behavior given by an annotation with empty argument list. However, it still seems like a pretty natural assumption to make that they would be equal unless anything else is stated, and I think it would be great if we could make this a general rule about annotations defined by pseudo-code records. (Then, it would be good if we made use of pseudo-code records as often as possible, to avoid special case-by-case semantics for annotations with structure described by grammar.)

Edit: For an example of sometimes needing to define an exception to this rule, see #2854.

HansOlsson commented 3 years ago

I don't believe it's the most central question being asked here, but I'd expect annotation(Dialog) to be rejected as malformed, just like this model:

It's sort of a modifier, not a call, so both should be ok, similarly as below:

model NoRecordModifierList
  record R
     Real x = 1.0;
   end R;
   R r1(x(unit="m"));
   R r2(final x);
   R r3(x);
end NoRecordModifierList;
maltelenz commented 3 years ago

It's sort of a modifier, not a call, so both should be ok

You are right, that is actually what the specification says in the intro of the annotation chapter:

The structure of the annotation content is the same as a class modification

It does add another case that needs to be decided then. Does annotation(Dialog) mean the same things as annotation(Dialog())? Intuitively for me, it weakens the case for either of them to mean anything, since you are not even "calling a constructor of a record" anymore.

HansOlsson commented 3 years ago
  • For which annotations does an empty annotation mean something?

The ones where it doesn't mean anything would be the simple ones with possible values (as there is no value), and the structured ones where empty contents logically means nothing.

So as far as I can see the remaining ones are (except for Figure) just: experiment Dialog Dialog.loadSelector Dialog.saveSelector

For experiment it requires that we have full set of defaults as in #2251 (to give a meaning for it). If we leave stopTime without default we don't have a problem with empty experiment.

For the selectors I think it makes sense to require caption and/or filter; we could make that clearer by removing one or both of the defaults. Thus the only remaining one is thus Dialog. If we don't like empty ones we can suggest (or require) annotation Dialog(enable=true) to ensure that it isn't empty (seems safest - no misspellings).

henrikt-ma commented 3 years ago

It's sort of a modifier, not a call, so both should be ok

You are right, that is actually what the specification says in the intro of the annotation chapter:

The structure of the annotation content is the same as a class modification

It does add another case that needs to be decided then. Does annotation(Dialog) mean the same things as annotation(Dialog())? Intuitively for me, it weakens the case for either of them to mean anything, since you are not even "calling a constructor of a record" anymore.

I agree. Just that it is syntactically allowed by the grammar doesn't mean it has any semantics. To me, the fact that the x in

   R r3(x);

doesn't make a difference says nothing about the meaning of annotation(Dialog). I think the analogy with (pseudo-code) record constructor calls is serving us quite well for the structured annotations, so I think we should be careful to not destroy this analogy by allowing something like a record constructor call without argument list.

henrikt-ma commented 3 years ago
  • For which annotations does an empty annotation mean something?

The ones where it doesn't mean anything would be the simple ones with possible values (as there is no value), and the structured ones where empty contents logically means nothing.

For experiment it requires that we have full set of defaults as in #2251 (to give a meaning for it). If we leave stopTime without default we don't have a problem with empty experiment.

Instead of defining strange things that "doesn't mean anything" I think we should specify that these things are invalid. For example, as long as StopTime doesn't have a default, annotation(experiment()) should simply be illegal.

henrikt-ma commented 3 years ago

So as far as I can see the remaining ones are (except for Figure) just: experiment Dialog Dialog.loadSelector Dialog.saveSelector

For the selectors I think it makes sense to require caption and/or filter; we could make that clearer by removing one or both of the defaults. Thus the only remaining one is thus Dialog. If we don't like empty ones we can suggest (or require) annotation Dialog(enable=true) to ensure that it isn't empty (seems safest - no misspellings).

Here's a trick we could use for the file dialog selectors:

record Dialog
  …
  Selector loadSelector = Selector(enable = false);
  Selector saveSelector = Selector(enable = false);
  …
end Dialog;

record Selector
  Boolean enable = true "Enable file dialog selector";
  String filter = "";
  String caption = "";
end Selector;

That is, loadSelector and saveSelector have defaults, and can be trivially omitted from a Dialog annotation. The default makes it explicit that the selectors are not enabled, but when a selector is desired, the annotation takes the same form as before since enable = true by default when using the record constructor.

HansOlsson commented 3 years ago

So as far as I can see the remaining ones are (except for Figure) just: experiment Dialog Dialog.loadSelector Dialog.saveSelector For the selectors I think it makes sense to require caption and/or filter; we could make that clearer by removing one or both of the defaults. Thus the only remaining one is thus Dialog. If we don't like empty ones we can suggest (or require) annotation Dialog(enable=true) to ensure that it isn't empty (seems safest - no misspellings).

Here's a trick we could use for the file dialog selectors:

I find that 'too cute', and note that the current selectors in MSL use:

parameter String fileName="NoName" "File where matrix is stored"
    annotation (Dialog(
      group="Table data definition",
      enable=tableOnFile,
      loadSelector(filter="Text files (*.txt);;MATLAB MAT-files (*.mat)",
          caption="Open file in which table is present")));
henrikt-ma commented 3 years ago

To make further progress here, it seems like we should revisit #2251 regarding experiment defaults, and perhaps have a poll on the deprecation of pseudo-code record constructors without argument list (as in annotation(Dialog).

For experiment, the situation is further complicated by the inheritance discussed in #2314. Consider a pseudo-code record like this:

record experiment
  Real StartTime(final unit = "s") = 0.0 "Simulation start time";
  Real StopTime(final unit = "s") "Simulation stop time";
  Real Interval(final unit = "s", final min = 0.0) "Time resolution of result grid"; /* Tool-dependent default */
  Real Tolerance(final min = 0.0) "Relative integration tolerance"; /* Tool-dependent default */
end experiment;

Would you then not be allowed to specify an experiment with just Tolerance in a base class? We should be careful to not make this illegal by mistake.