Stricter constraint when performing lookup in a class.
In the last bullet point of Section 5.3.2:
If the class does not satisfy the requirements for a package, the lookup is restricted to encapsulated elements only.
What is meant by package requirement? In particular, must all its base classes satisfy the requirements for a package for a class to satisfy the requirements for a package? Does a class satisfy the requirements for a package if it extends from a model?
Should we just require the class to BE a package, if the rest of the lookup references non-encapsulated elements?
Ideally yes, and it may be the time to do it now.
I don't fully recall the reason for that wording (it seems it was added in 1.3), but my impression was that it was added when package was seen as being a specialized variant of class (so it shouldn't add new possibilities such as different lookup). That is consistent with 1.3 discussing Restricted classes.
I thought that meant the restrictions specified on package in Section 4.6 Specialized Classes:
package - May only contain declarations of classes and constants. Enhanced to allow import of elements of packages. (See also chapter 13 on packages.)
In particularly, this part: "may only contain declarations of classes and constants." I don't know the reason why it was added. My personal interpretation is that it ensures that it can be used without instantiating the class.
Would this be an example of a valid lookup with the current formulation, that would become invalid if a true package is required?
package P
model M
// parameter Real p = 1.0; /* M is like a package as long as this is commented-out. */
type MyReal = Real;
end M;
type OtherReal = M.MyReal; /* Valid, considering that M isn't a package? */
end P;
Would this be an example of a valid lookup with the current formulation, that would become invalid if a true
packageis required?package P model M // parameter Real p = 1.0; /* M is like a package as long as this is commented-out. */ type MyReal = Real; end M; type OtherReal = M.MyReal; /* Valid, considering that M isn't a package? */ end P;
Yes. I guess we should first check if that is actually used - I hope not.
By the way, what is the part about restriction to encapsulated classes actually trying to say? It sounds as if this would be legal:
package P
model M
parameter Real p = 1.0; /* M is not like a package due to this component. */
encapsulated type MyReal = Real;
end M;
type OtherReal = M.MyReal; /* Legal, since MyReal is encapsulated in non-package-like class M. */
end P;
This seems strange to me, so I'm assuming the intention is something else.
Additionally, shouldn't we rewrite without the use of we here (this is on out of three uses of we in the chapter, and one of the others is also about partial)?
The class we look inside shall not be partial in a simulation model.
By the way, what is the part about restriction to encapsulated classes actually trying to say? It sounds as if this would be legal:
package P model M parameter Real p = 1.0; /* M is not like a package deu to this component. */ encapsulated type MyReal = Real; end M; type OtherReal = M.MyReal; /* Legal, since MyReal is encapsulated in non-package-like class M. */ end P;This seems strange to me, so I'm assuming the intention is something else.
That is exactly the intended use (although it is normally an encapsulated function).
Additionally, shouldn't we rewrite without the use of we here (this is on out of three uses of we in the chapter, and one of the others is also about
partial)?The class we look inside shall not be partial in a simulation model.
Possibly, yes.
By the way, what is the part about restriction to encapsulated classes actually trying to say? It sounds as if this would be legal:
package P model M parameter Real p = 1.0; /* M is not like a package deu to this component. */ encapsulated type MyReal = Real; end M; type OtherReal = M.MyReal; /* Legal, since MyReal is encapsulated in non-package-like class M. */ end P;This seems strange to me, so I'm assuming the intention is something else.
That is exactly the intended use (although it is normally an encapsulated function).
Maybe it would be good to add some nonnormative text explaining the reason for this restriction, since it doesn't seem obvious why it exists. Although if we do apply the proposed restriction that the class has to be a package it wouldn't be needed of course, since that part would then be removed anyway.
Would this be an example of a valid lookup with the current formulation, that would become invalid if a true
packageis required?package P model M // parameter Real p = 1.0; /* M is like a package as long as this is commented-out. */ type MyReal = Real; end M; type OtherReal = M.MyReal; /* Valid, considering that M isn't a package? */ end P;Yes. I guess we should first check if that is actually used - I hope not.
I have not seen a case like that. I have seen cases like the following.
model M
parameter Real p = 1;
SomeOtherModel a(some_parameter = M.p);
...
end M;
I have also seen the case where someone copied Mechanics.Multibody.Frames.Orientation from MSL but omitted encapsulated in the definition of equalityConstraint. So it was:
record Orientation
Real T[3,3];
...
function equalityConstraint
...
end equalityConstraint;
end Orientation;
model M
...
equation
Orientation.equalityContraint(...);
...
end M;
The cases I have seen where A.b is used, and A is not a package are usually the cases where A is a record of constants. Such records are commonly used to define some properties of a substance, e.g. oil.
That is exactly the intended use (although it is normally an encapsulated function).
Maybe it would be good to add some nonnormative text explaining the reason for this restriction, since it doesn't seem obvious why it exists. Although if we do apply the proposed restriction that the class has to be a package it wouldn't be needed of course, since that part would then be removed anyway.
I didn't think removing that part was part of the plan. I thought we were considering this formulation instead:
Unless the class (A) is a package, the lookup is restricted to encapsulated elements only.
That is exactly the intended use (although it is normally an encapsulated function).
Maybe it would be good to add some nonnormative text explaining the reason for this restriction, since it doesn't seem obvious why it exists. Although if we do apply the proposed restriction that the class has to be a package it wouldn't be needed of course, since that part would then be removed anyway.
I didn't think removing that part was part of the plan. I thought we were considering this formulation instead:
Unless the class (A) is a package, the lookup is restricted to encapsulated elements only.
Ok, that makes sense. Then I think adding some explanation for why these restrictions are necessary would be a good idea. 5.3.3 (Global Name Lookup) contains the nonnormative text: "The package-restriction ensures that global name lookup of component references can only find global constants.". But if that's the only reason it exists it would be less confusing to just forbid lookup of non-constant components in classes instead.
Ok, that makes sense. Then I think adding some explanation for why these restrictions are necessary. 5.3.3 (Global Name Lookup) contains the nonnormative text: "The package-restriction ensures that global name lookup of component references can only find global constants.". But if that's the only reason it exists it would be less confusing to just forbid lookup of non-constant components in classes instead.
We also want to prevent finding non-encapsulated classes in a similar way, for two reasons:
- If someone has
model A replaceable package B=...it is weird to useA.B, and often an error (you are using A with modifier so you think they would apply here). - You can have
model A parameter Real x=2;model B=B2(y=x);...where usingA.Bindirectly references the componentx(yes, this construct is used - and you can make it weirder still). Encapsulation eliminates that dependency.
* You can have `model A parameter Real x=2;model B=B2(y=x);...` where using `A.B` indirectly references the component `x` (yes, this construct is used - and you can make it weirder still). Encapsulation eliminates that dependency.
That actually works in OpenModelica, having a model with e.g. A.B b is flattened as:
class M
parameter Real A.x = 2.0;
parameter Real b.y = A.x;
end M;
But I'm not entirely sure why we support that, it's possible that it just happens to work and it's not actually something that's used. It shouldn't work of course since A isn't a package or package-like class, but we haven't gotten around to implementing that restriction yet.
Proposal: If the class is not a package, the lookup is restricted to encapsulated elements only.
Some cases of records with constants used as packages? Markus - deprecate it this version? Poll: Favor: Martin, Gerd, Elena, Henrik, Markus, Stephan, Hans, Ben Against: Abstain: Clear result.
Regarding records with constants being used as packages.
One case is Modelica.Electrical.Spice3.Internal.MaterialParameters (and SpiceConstants just before it) which is used in Modelica.Electrical.Spice3.Internal.Bjt.bjtCalcTempDependencies The obvious solution would be to change it to a sub-package instead.
See also #4062
We should also add encapsulated to all functions inside the different Complex operators. Otherwise Modelica.ComplexBlocks.Examples.ShowTransferFunction, in particular, breaks because of the explicit call to Complex.'^'.complexPower inside Complex.'^'.integerPower.
We should also add
encapsulatedto all functions inside the differentComplexoperators. OtherwiseModelica.ComplexBlocks.Examples.ShowTransferFunction, in particular, breaks because of the explicit call toComplex.'^'.complexPowerinsideComplex.'^'.integerPower.
I believe that it highlights another problem: "operator" (in this case Complex.^) is intended to work as a package, and thus the rules should handle that. I pushed a commit for that. The ones with "encapsulated operator function" are already ok.
I happened to look at the Dynawo library of Modelica models today, and they seem to often use fake package lookup. For example, a record is defined with enumerations and parameters. Then in a few places Automaton (one of enumerations in the record) is referred to as if it was inside a package for lookup and for import. Note also, that requirements for the package are: "May only contain declarations of classes and constants. Enhanced to allow import of elements of packages." But the record in question defines parameters and classes. It looks some tools might be interpreting parameters as constants. @sjoelund, would you know anything about it?
Since there are more user libraries that rely on fake packages, should this be reopened and the change reverted?
I happened to look at the Dynawo library of Modelica models today, and they seem to often use fake package lookup. For example, a record is defined with enumerations and parameters. Then in a few places Automaton (one of enumerations in the record) is referred to as if it was inside a package for lookup and for import. Note also, that requirements for the package are: "May only contain declarations of classes and constants. Enhanced to allow import of elements of packages." But the record in question defines parameters and classes. It looks some tools might be interpreting parameters as constants. @sjoelund, would you know anything about it?
Since there are more user libraries that rely on fake packages, should this be reopened and the change reverted?
As I mentioned earlier we just haven't gotten around to implementing the restriction for non-package like classes in OpenModelica. So it's not that we interpret parameters as constants, we just don't check if a class looks like a package or not when doing lookup.
I think the example you pointed out in Dynawo is a pretty clear violation of the previous lookup restrictions and shouldn't have been allowed by any standards compliant tool before this change either. I haven't heard of Dynawo before, but they seem to be using the really old OpenModelica 1.13.2. I assume that's because in 1.14 we introduced our new frontend which is a lot stricter when it comes to error checking, the old frontend allowed a lot of things that shouldn't have been allowed.
I happened to look at the Dynawo library of Modelica models today, and they seem to often use fake package lookup. For example, a record is defined with enumerations and parameters. Then in a few places Automaton (one of enumerations in the record) is referred to as if it was inside a package for lookup and for import. Note also, that requirements for the package are: "May only contain declarations of classes and constants. Enhanced to allow import of elements of packages." But the record in question defines parameters and classes. It looks some tools might be interpreting parameters as constants. @sjoelund, would you know anything about it?
Since there are more user libraries that rely on fake packages, should this be reopened and the change reverted?
The idea with deprecating it instead of just making it illegal was to allow the libraries time to migrate, so I don't think we should re-open this - especially not when it is an obscure old library as @perost found.