Open qlambert-pro opened 3 years ago
Unfortunately, @qlambert-pro has been exposed to a tool-specific tweak made to the 3.2.3 version of this function in order to ensure certain translation time simplifications based phase indices. It's probably best to close this as an invalid issue.
Related to this, I must also warn that Evaluate = true
has been added inside a function by mistake in this commit: https://github.com/modelica/ModelicaStandardLibrary/commit/6bd7d95ad5aa598b4942d514847ec8a20d109308
The 4.0.0 declaration looks like this, and I'll open a PR for fixing this:
parameter Integer m=size(x, 1) "Number of phases" annotation(Evaluate=true);
Actually, before I jump to a PR on the MSL, could we take the opportunity to discuss the meaning of Evaluate
inside an inlined function?
In the particular case at hand, I'd say that the Evaluate = true
on m
shouldn't be needed, but the reasons for this is a bit technical: After inlining ToSpacePhasor
in a non-function context, the size(x, 1)
will become a parameter expression (even though the effective variability is that of 1
, that is, constant). Since the declaration equation for the inlined protected parameter m
should not be exposed to overriding after translation, the declaration equation can effectively be seen as final. That is, the inlined m
is a parameter with final binding to a constant parameter expression, showing that one doesn't need Evaluate = true
as an excuse for evaluating it. It can be argued that adding Evaluate = true
would express a clear desire that it should really be evaluated, but most tools will probably take the opportunity to do so anyway.
The question becomes more interesting when the binding isn't constant:
model InlineAndEvaluate
function f
input Real x;
output Boolean y;
protected
parameter Real p = x annotation(Evaluate = true); /* Special variability rules inside functions allow this. */
algorithm
b := p > 0.5;
annotation(Inline = true);
end f;
parameter Real p1 = true; /* Should this become evaluated? */
Boolean y1 = f(p1);
Boolean y2 = f(time); /* Is the Evaluate = true even legal in this case? */
end InlineAndEvaluate;
Actually, before I jump to a PR on the MSL, could we take the opportunity to discuss the meaning of
Evaluate
inside an inlined function?
The proposed handling of variables inside functions in the PR for evaluable variables (or parameters) makes it redundant: https://github.com/modelica/ModelicaSpecification/pull/2754
The proposed handling of variables inside functions in the PR for evaluable variables (or parameters) makes it redundant:
2754
Even though I've been very involved in #2754, I don't see that it answers any questions related to inlining, hence the question. If we need a reason to not answer the question, I suggest calling it esoteric rather than a duplicate of #2754.
The proposed handling of variables inside functions in the PR for evaluable variables (or parameters) makes it redundant:
2754
Even though I've been very involved in #2754, I don't see that it answers any questions related to inlining, hence the question. If we need a reason to not answer the question, I suggest calling it esoteric rather than a duplicate of #2754.
How and when to implement inlining is an internal implementation detail in tools and shouldn't impact the semantics.
The idea with evaluable variables (or parameters) in #2754 is that a function behaves as if all inputs etc have actual values and then evaluate the body (etc); and without any variability requirements. (A function call preserves the variability of the arguments.)
Sounds like you would be in favor of forbidding the use of Evaluate
inside functions?
Sounds like you would be in favor of forbidding the use of
Evaluate
inside functions?
That's one way of viewing it - or expressed as function calls are always fully evaluated when used; so internally in functions everything is evaluated.
If we want to have a function where parts are evaluated in advance the question is what benefit it brings. Evaluating a function call with a literal value before translation is obvious, and similarly only evaluating a parametric function call once. But trying to track dependency from one literal input is messier, especially as people expect an algorithm to be executed in order.
Sounds like you would be in favor of forbidding the use of
Evaluate
inside functions?That's one way of viewing it - or expressed as function calls are always fully evaluated when used; so internally in functions everything is evaluated.
If we want to have a function where parts are evaluated in advance the question is what benefit it brings. Evaluating a function call with a literal value before translation is obvious, and similarly only evaluating a parametric function call once. But trying to track dependency from one literal input is messier, especially as people expect an algorithm to be executed in order.
Note that the original question about Evaluate
inside a function was formulated in the context of inlining, in which case it's a bit odd to consider the body as fully evaluated. The point of Evaluate = true
would be to force evaluation of parameters passed to the function, just like one could do if the function was inlined manually. I must say myself that even though I can see this possibility, I don't see a need for it, and would much rather just forbid Evaluate
inside functions. I believe forbidding it would make our functions be more like functions and less like macros, which would be a good thing for my conceptual understanding of Modelica.
I believe forbidding it would make our functions be more like functions and less like macros, which would be a good thing for my conceptual understanding of Modelica.
Yes, forbidding Evaluate in functions would be one possibility.
I think the issue of variability of size
inside functions was not addressed in this issue so far. In 3.8.2 it only says:
• Some function calls are parameter expressions even if the arguments are not: ... – end in A[ end ] if A is variable declared in a non-function class. – size(A) (including size(A, j) where j is parameter expression) if A is variable declared in a non-function class. ...
I have not find an explanation of how size
should be interpreted in functions. I only looked through every mention of "size" in the chapter on functions. It is possible it is mentioned somewhere else but then it should perhaps moved closer to 3.8.2.
In functions there can be arrays that change sizes during the function execution (12.4.2). But arrays of inputs would stay constant for the duration of the function execution.
size(A) (including size(A, j) where j is parameter expression) if A is variable declared in a non-function class.
I think this says implicitly that within the context of a function, size
is handled as a user defined function. That is, it is as variable as its inputs.
Maybe some non-normative text would be helpful to highlight that aspect of the variability of size
?
size(A) (including size(A, j) where j is parameter expression) if A is variable declared in a non-function class.
I think this says implicitly that within the context of a function,
size
is handled as a user defined function. That is, it is as variable as its inputs.
Yes.
I am surprised that
m
is a constant here, since its value clearly depends on the size of the input which is not constant for functions.At the same time the specs don´t really cover this case, and I think it should. Section 3.8.2, talks about the variability of
size
and makes an exception for the case of functions. I think a non-normative text pointing out the error made inToSpacePhasor
could be useful.