CVS difference for ai05s/ai05-0177-1.txt
--- ai05s/ai05-0177-1.txt 2011/02/04 07:04:48 1.10
+++ ai05s/ai05-0177-1.txt 2011/02/16 06:15:23 1.11
@@ -6550,3 +6550,200 @@
****************************************************************
+From: Randy Brukardt
+Date: Saturday, November 20, 2010 1:49 AM
+
+At the Fairfax meeting, we decided that all subprogram completions, including
+null procedures and expression function have to be freezing (under 13.14(3/3)).
+I tried to explain the reasons for this in the !discussion of the AI:
+
+
+Note that both null subprograms and expression functions are freeze when they
+are used as completions. There are a number of reasons for this:
+
+(1) This is consistent with the behavior of explicit bodies. If the null
+ procedure or expression function replace the equivalent explicit body, the
+ freezing will not change.
+
+(2) If a null procedure used as a completion did not freeze, then AARM
+ 13.14(10.f/3) would not be true. There would be a way to construct a program
+ that made a procedure call with an unfrozen profile - admittedly, a
+ pathological program (it could only have null procedure bodies in a package
+ body). (This issue could be fixed by extending 13.14(10.1/3) to all
+ subprograms.)
+
+(3) If an expression function used as a completion did not freeze, then it would
+ be possible to make a call to an expression function with an unfrozen
+ expression. Consider:
+
+ package Pack is
+ function Foo (A : in Natural) return Natural;
+ type Bar is access function Foo (A : in Natural) return Natural;
+
+ P : Bar := Foo'Access; -- Freezes Bar and Foo.
+
+ type Flub is range 0 .. 100;
+
+ function Foo (A : in Natural) return Natural is
+ (A + Flub'Size); -- The expression is not frozen here.
+
+ Val : Natural := P.all(5); -- (!)
+
+ end Pack;
+
+The call of P.all passes the elaboration check (as the completion of Foo has
+been elaborated). However, if the body of Foo did not freeze everything, Flub
+would not be frozen, and thus the call P.all(5) would be evaluating the value of
+an aspect of an unfrozen type.
+
+Note that the prefix of Foo freezes the declaration of Foo, but not the (still
+to be seen) completion; and even if the completion was frozen, that would not
+freeze the expression.
+
+---
+
+This decision worries me. It seems to require that expression functions used as
+completions in specifications all be grouped at the end of the private part, not
+wherever they more naturally would appear. Given that this is the motivating use
+for introducing this construct, hamstringing them does not seem like a good
+thing. Of course, I can't say if this is a real problem until we have real
+examples of use.
+
+Even if this rule doesn't cause real problems, it is still going to force
+programmers to rearrange their code from time-to-time, which is likely to be an
+annoyance. And why do we have that annoyance? For foolish consistency (point (1)
+above) and to prevent problems with two pathological cases (points (2) and (3)
+above). That doesn't seem right to me.
+
+Thus, I'd like to find an alternative solution to the "always freeze
+completions" solution to point (3). [(2) is easy to fix, as noted above.]
+
+Unfortunately, nothing seems to jump out at me. The best I can come up with
+would be to say that the expression of an expression function F causes freezing
+at the point of the declaration of F if:
+ * the expression function F is a completion; and
+ * the declaration of F is declared in the same declarative_part or package
+ specification; and
+ * F is used before the completion as a prefix of the Access or
+ Unchecked_Access attribute, or as the formal parameter of a generic
+ instantiation.
+
+However, the implementation of this is not ideal: it would seem to require
+tracking how a function is used within a spec, or searching back in the code for
+uses. Which seems like a lot of work for a near pathology.
+
+But this only causes user pain when an expression function is used in one of
+these ways such that trouble might occur. That is likely to be rare; otherwise,
+the expression function's expression only is frozen when it is called, or (most
+likely) when the end of the declarative part is reached.
+
+In cases like this, I am inclined to give the implementation's the pain in order
+to spare the users the pain (many more users than implementers). But perhaps
+there is a better fix with even less pain.
+
+Thoughts??
+
+****************************************************************
+
+From: Tucker Taft
+Date: Monday, November 22, 2010 9:13 AM
+
+> This decision worries me. It seems to require that expression
+> functions used as completions in specifications all be grouped at the
+> end of the private part, not wherever they more naturally would
+> appear. Given that this is the motivating use for introducing this
+> construct, hamstringing them does not seem like a good thing. Of
+> course, I can't say if this is a real problem until we have real examples of
+> use.
+
+I don't see this as a big problem. This is no different than deferred
+constants. Their completion has to be placed after the full definition of the
+type.
+
+> Even if this rule doesn't cause real problems, it is still going to
+> force programmers to rearrange their code from time-to-time, which is
+> likely to be an annoyance. And why do we have that annoyance? For
+> foolish consistency (point (1) above) and to prevent problems with two
+> pathological cases (points (2) and (3) above). That doesn't seem right to me.
+
+I don't agree. If the completion effectively sets the "elaborated" bit then it
+seems it has to freeze. The only solution would be to defer setting the
+"elaborated" bit until the end of the enclosing package spec, but then you
+wouldn't be allowed to call it.
+
+I don't see the real problem for the user, given the existing deferred constant
+rules.
+
+****************************************************************
+
+From: Randy Brukardt
+Date: Monday, November 22, 2010 6:58 PM
+
+> I don't see this as a big problem. This is no different than deferred
+> constants. Their completion has to be placed after the full
+> definition of the type.
+
+Fair enough. I don't honestly know if it is a big problem, either, just that it
+is concerning to me, mainly because the reasons for the restriction is because
+of unlikely code sequences (calls evaluated in a spec are rare, 'Access in a
+spec is reasonably rare, and doing both together is highly unlikely). (Note that
+calls in Preconditions and in default expressions aren't usually evaluated in
+the spec.)
+
+I was worried about cases with multiple types; having to group all of the
+completions at the end may be unnatural (and might separate them a long ways
+from the associated types).
+
+I suppose if this freezing turns into a problem in practice, it would be less of
+a problem to change the freezing with a BI than to force a complex
+implementation without any significant evidence of a problem.
+
+> > Even if this rule doesn't cause real problems, it is still going to
+> > force programmers to rearrange their code from time-to-time, which
+> > is likely to be an annoyance. And why do we have that annoyance? For
+> > foolish consistency (point (1) above) and to prevent problems with
+> > two pathological cases (points (2) and (3) above). That doesn't
+> seem right to me.
+>
+> I don't agree. If the completion effectively sets the "elaborated"
+> bit then it seems it has to freeze. The only solution would be to
+> defer setting the "elaborated" bit until the end of the enclosing
+> package spec, but then you wouldn't be allowed to call it.
+
+As I noted above, I don't think there will be many calls in specs of these
+completions, so that the fact that one *might* occur is hardly a good reason for
+restricting these. I'd actually prefer the solution you outlined above (no calls
+in the spec at all) to the extra freezing.
+
+I didn't want expression functions given in specs to have to have elaboration
+bits at all; the reason they need them in specs is because of weird corner cases
+like the example that I started this message with.
+
+OTOH, it's clearly easier and more consistent for them to have elaboration bits,
+and for them to have the same semantics as "regular" functions. So I suppose it
+probably is best to use the restrictive freezing rule and see if there are
+problems in actual practice.
+
+> I don't see the real problem for the user, given the existing deferred
+> constant rules.
+
+My code doesn't have very many deferred constants, they usually have a value of
+null or 0, and they usually come immediately after the associated type. That
+works because each one is associated with a single type.
+
+Expression functions will have multiple parameters, and at least sometimes those
+parameters will all be declared in the same package. (Consider a tagged type and
+an associated enumeration, for instance). This freezing will require all of the
+expression functions that define completions to come after all of the associated
+types, usually at the very end of the package. Moreover, there are going to be
+plenty of these functions in a typical package (especially as Janus/Ada can't
+inline anything else). In a complex package like Claw, putting them all at the
+very end would be pretty ugly (widely separating them from the associated
+types).
+
+Even with this, I don't see this as a critical issue; we'll need to see examples
+in order to tell the effects. So I think we'll have to defer this one until
+expression functions get into significant use.
+
+****************************************************************
+
Questions? Ask the ACAA Technical Agent