Open casella opened 3 years ago
I would say that it is covered by 4.2 Double Declaration Not Allowed. If you load two versions of the same library you would have two packages with the same name in the global scope. But I can see how it can be argued that they are not declared but loaded, so the rule may not technically apply.
I'm with the first option: it's not allowed.
I'm thinking that having this would make conversion script less mandatory. Today, when you convert a library, you need to create a new conversion script and anything using your library also needs to be converted, creating a huge chain of conversions. Some of these libraries might not be maintained anymore and you then get the problem that you are referring to some converted version of the library that no-one else has access to.
By allowing multiple versions of a library to be loaded, you could simply keep on using libraries without updating them. But it would be quite confusing to a user of a GUI to have multiple MSL versions open and depending on which diagram you are in, only one version would be possible to use.
I like @casella's original idea of targeting rules for flattening a given class, rather than entering the domain of how tools should manage available versions of libraries between model translations.
By allowing multiple versions of a library to be loaded, you could simply keep on using libraries without updating them. But it would be quite confusing to a user of a GUI to have multiple MSL versions open and depending on which diagram you are in, only one version would be possible to use.
This is true in principle. In practice, using stale libraries that create multiple-version dependencies is something I would not leave to a fully automated systems, but rather to experts, which may be able to untangle the dependencies.
I'm also in favour of allowing only one version. BTW, I guess that is what other languages which heavily rely on package management like Python or Julia do, isn't it?
With Python in particular you are recommended to have one virtualenv with all the packages you need for one particular library in one location since the libraries typically break a lot on update... It's not a very good example and it's sometimes difficult to upgrade a certain package if it has the same dependencies as something else that your code depends on. So you are often stuck with 1-2 year old (or older) libraries since Python only works if all libraries are actively maintained and updated to the latest dependencies...
If we do the same, we will be stuck with requiring our models to use old MSL and not able to upgrade because a library we depend on isn't upgraded to the newer MSL versions.
TL;DR: Having multiple versions together should be forbidden. I would say that it is already forbidden (but we can make it more explicit) as the used libraries in MODELICAPATH are loaded in the global scope, and the global scope can only contain one version of each library, https://specification.modelica.org/maint/3.5/scoping-name-lookup-and-flattening.html#static-name-lookup
Longer: As I understand having multiple versions of libraries would be somewhat easier if they are only used internally in other libraries, and not directly exposed to the user. I've heard that Lua has that (using internal tables), but I cannot find any link at the moment.
However, since we want libraries to expose Interfaces for interoperability I don't see that internal use inside libraries will be overly useful for Modelica. Thus if we want handle multiple versions of a library we also need to handle:
If there are any issues with converting libraries I think we should work on that instead.
BTW: Dymola can support the similar scenarios as the one in original post (except that libraries should be ordered), but the classes using outdated versions will be read-only (as I recall we can do it even if there are conversions in the case they wouldn't impact your library). The read-only part is needed because even if no conversion is needed to convert to the new version it might have introduced a new class or parameter, that didn't exist in the older version and keeping track of that would be too complicated.
However, since we want libraries to expose Interfaces for interoperability I don't see that internal use inside libraries will be overly useful for Modelica.
There is no nominal typing except for external objects, right? The interfaces should be compatible since they just boil down to the type and unit.
The most problematic part would be modifications on components (like redeclaring Media).
If there are any issues with converting libraries I think we should work on that instead.
The problem isn't converting the libraries as much as it is making people convert their libraries...
However, since we want libraries to expose Interfaces for interoperability I don't see that internal use inside libraries will be overly useful for Modelica.
There is no nominal typing except for external objects, right?
There's also for operator overloading. However, my point was slightly different:
The interfaces should be compatible since they just boil down to the type and unit.
In many cases, but I could see that a new version renamed some connector-variables; and/or changed their type.
The problem isn't converting the libraries as much as it is making people convert their libraries...
Well, similar issue. To me one of main issues is that people are hesitant to do it - and also hesitant to use the new possibilities to simplify their work-flow.
I suppose one thing we could specify and recommend would be specifying how to handle older libraries where a conversion script is available for these older libraries. Basically if we have uses OldLibrary which uses MSL 3.2.3 and a model with
uses(Modelica(version="4.0.0"), OldLibrary(version="1.0.0", conversions(Modelica(version="4.0.0")))
This would make it easier to use newer libraries without having write access to their repositories.
Based on the discussion so far, could we agree on the following scenario:
I think this is the most reasonable compromise in terms of being comprehensible to end users, while being reasonably easy to implement for tool vendors.
Do you agree?
It would be easier to answer if the question was clarified with a clear separation of what is intended as:
My gut feeling is that we (the specification) should not elaborate too much on this beyond what is normative.
Language group: Already restricted (to only one version of a library at the time) - but make it clearer. @eshmoylova where?
I am afraid that my looking into where to add the restriction raised more questions, as it often happens. The following are the places that I think need to be updated (but may need some discussion).
In Section 18.8.2, it says that one or more uses
annotations are allowed. But it does not say if more than one uses annotation can specify the same library with different versions. I think it should be specified if it is allowed and, if it is, what it means:
"Global scope" is used in many places in the specification, but I cannot find a clear definition of what constitutes the global scope. In Section 13.3, it says (the emphasis is mine): "The top-level scope implicitly contains a number of classes stored externally. If a top-level name is not found at global scope...." I think we need to define "global scope" in Chapter 5. After Enclosing Classes, we can have a section Global Scope, saying, for example, that the global scope contains built-in operators (defined in the specification and tool internal), loaded libraries using MODELICAPATH (link to 13.3), and loaded models and classes via File Open or other tool-specific mechanism. Then either here or in 13.3 we need to say explicitly that only one version of a library is loaded into the global scope per simulation or translation. @casella's suggestions was "When flattening a given class...." But that might imply that we can/should rebuild the global scope when we flatten a new class. For example,
model M
A a;
B b;
equation
b = someFunction(a);
...
end M;
When flattening M we need to flatten A and B. We want to have just one scope that applies to all those flattenings. Also, evaluation of equations happens after flattening. When we evaluate equations we need to flatten someFunction
. Technically, it can be viewed as flattening a different class. So only limiting loading of only one version of a library, when flattening a given class, leaves a way out of the restriction.
Also we have The Class Tree and it should be tied to the global scope. Right now it says, for example, "The builtin classes are put into the unnamed root of the class tree." The unnamed root of the class tree represent the global scope. So maybe it should say so explicitly. Also where would the Instance Tree go? Does it matter?
@eshmoylova
Consider the following scenario
In principle, a tool could load both versions x and y of D, and have packages B and C use the corresponding ones while flattening classes in A. AFAIK, there is no explicit provision in the Modelica Specification barring this option.
In practice
As @sjoelund argues here, the fact that the capability of handling multiple versions of the same library is not explicitly mentioned means that a library developer should avoid relying on it, to ensure maximum compatibility.
However, I believe it would be better to explicitly bar this option in the language spec, because this could be a serious hurdle to ensure cross-tool compatibility of future Modelica libraries, which is the whole point of having an open standard.
For example, we could add to the normative part in the preamble of Section 13.3 the following statement:
We can leave it to the tools how to figure out what is the best or most appropriate version they should consider, but at least we should make clear it has to be only one.
@HansOlsson, @sjoelund, @mtiller, @dietmarw, what do you think?