!standard 3.2.4(31/4) 19-01-09 AI12-0301-1/01 !class binding interpretation 19-01-09 !status work item 19-01-09 !status received 18-12-17 !priority Low !difficulty Easy !qualifier Omission !subject Predicates should work like constraints for types with Default_Value !summary If a part of an default-initialized object has specified Default_Value or Default_Component_Value aspects, predicates are evaluated for the object. !question 3.2.4(31/4) says that predicates are not checked for default-initialized objects unless "any subcomponents have default_expressions". This seems different than the rule for constraints and exclusions of stand-alone objects, which check them if an inplicit initial value is defined. Should this be fixed? (Yes.) !recommendation (See Summary.) !wording Modify 3.2.4(31/4): Redundant[On every subtype conversion, a check is performed that the operand satisfies the predicates of the target subtype. This includes all parameter passing, except for certain parameters passed by reference, which are covered by the following rule: ] After normal completion and leaving of a subprogram, for each /in out/ or /out/ parameter that is passed by reference, a check is performed that the value of the parameter satisfies the predicates of the subtype of the actual. For an object created by an object_declaration with no explicit initialization expression, or by an uninitialized allocator, if {the types of any parts have specified Default_Value or Default_Component_Value aspects, or} any subcomponents have default_expressions, a check is performed that the value of the created object satisfies the predicates of the nominal subtype. [Author's note: We have to talk about "parts" in the new text as we need to cover the case where the type of the object itself has one of these aspects. OTOH, the existing wording only applies to subcomponents, as there is no such thing as a default expression for a type (that is the role of these aspects.] !discussion A default-initialized stand-alone object of a type with Default_Value has the constraint checked on the value (that occurs when the value is converted to the nominal subtype, see 3.3.1(11)). The current rule for predicates do not check the predicates. As much as possible, we want the rules for constraints and predicates to be the same, so that changing between them can be seamless. Minor differences are likely to be confusing. The predicate rule was defined this way in part so that default initialization of access values would not trigger predicate evaluation. That is to say, the difference between the behavior of the "not null" exclusion and predicates is intentional (at least by the author of the rules). On the other hand, leaving out Default_Value and Default_Component_Value was unintentional. The easiest rule would be make the rules exactly consistent, by checking the predicate on any type which has a part that has an implicit initial value. However, that would change the clear intent of the rule. Moreover, access types are common and it is likely that at least some programs depend on the predicate checks not being made. So we adopt a correction only for types with parts that have Default_Value or Default_Component_Value aspects. We justify this change in part by saying that the programmer has requested a default value and thus that value should be enforced like any other. The issue with access types is that there is no way to not have a default value, so one is provided whether it makes sense for a particular type or not. There is a small compatibility issue with this change, in that some objects will get predicate checks that did not in the past. This is not as likely to happen as Default_Value is used much less frequently than access types, and it was a new feature in Ada 2012, so it does not appear in any legacy code. !ASIS No ASIS effect. !ACATS test An ACATS C-test needs to be constructed to ensure the checks are made in this case. !appendix From: Tucker Taft Sent: Monday, December 17, 2018 3:43 PM It seems a bit weird to me that a composite object without an explicit initialization has its subtype predicates checked, if any subcomponent has default initialization, while an elementary type with a default initialization doesn't have any subtype predicate check on a default initialization. Last sentence of RM 3.2.4(31/4) says: "... For an object created by an object_declaration with no explicit initialization expression, or by an uninitialized allocator, if any subcomponents have default_expressions, a check is performed that the value of the created object satisfies the predicates of the nominal subtype." Do others find this strange as well? If this said "..., if any *part has default initialization,* a check is performed ..." would make more sense to me. **************************************************************** From: Gary Dismukes Sent: Monday, December 17, 2018 4:05 PM > Do others find this strange as well? If this said "..., if any *part has > default initialization,* a check is performed ..." would make more sense > to me. I agree that seems odd and would expect them to be treated the same way. **************************************************************** From: Randy Brukardt Sent: Monday, December 17, 2018 4:12 PM > Do others find this strange as well? If this said "..., if any *part > has default initialization,* a check is performed ..." would make more > sense to me. Yes, I've complained about this repeatedly. This would also have the pleasant side-effect of making null exclusions and dynamic predicates work the same way. Bob, however, seems to have a hidden agenda to allow incorrectly initialized objects (I'm not sure why -- to me, the behavior of uninitialized constrained scalar objects is a language bug that we have to live with, not a useful feature). So I think he'll resist. **************************************************************** From: Bob Duff Sent: Tuesday, December 18, 2018 1:24 PM > Do others find this strange as well? If this said "..., if any *part > has default initialization,* a check is performed ..." would make more > sense to me. I agree. **************************************************************** From: Tucker Taft Sent: Tuesday, December 18, 2018 1:49 PM Bob didn't resist. But I am not sure my suggestion was completely clear. In particular, it would only affect elementary subtypes with both a subtype predicate, and some default initialization specified (i.e. an access subtype or a subtype of a type that has Default_Value => ...). In that special case, an object of such a subtype when created without an explicit initial value, would nevertheless have its subtype predicate checked after performing default initialization. **************************************************************** From: Bob Duff Sent: Tuesday, December 18, 2018 2:12 PM > Bob didn't resist. Because I thought you were talking about "Default_Value =>" for scalars. > ...But I am not sure my suggestion was completely clear. In > particular, it would only affect elementary subtypes with both a > subtype predicate, and some default initialization specified (i.e. an > access subtype or a subtype of a type that has Default_Value => ...). > In that special case, an object of such a subtype when created without > an explicit initial value, would nevertheless have its subtype > predicate checked after performing default initialization. Now that I see you are talking about access as well, I object. The decision that implicit init to null should NOT trigger the predicate check was deliberate, and would be incompatible. Don't you think it's too late to make that change (only for access)? I think I've written code that will break, like this: X : Some_Record_Containing_Access_Components; ... X := ...; **************************************************************** From: Tucker Taft Sent: Tuesday, December 18, 2018 2:25 PM > Now that I see you are talking about access as well, I object. > The decision that implicit init to null should NOT trigger the > predicate check was deliberate, and would be incompatible. Both of these ideas are incompatible. I had forgotten the underlying reasoning related to the access type case. > Don't you think it's too late to make that change (only for access)? It just seemed inconsistent. I wanted to see if there was sympathy with "fixing" this inconsistency. Apparently the access type "inconsistency" was intentional, while perhaps the scalar-type-with-default-value inconsistency was unintentional. > I think I've written code that will break, like this: > > X : Some_Record_Containing_Access_Components; > ... > X := ...; Subtype predicates are already being checked on such a record type. So your concern must be about subtype predicates on the access subtypes used for the components of the record, which will fail if they are null. Is that the example you had in mind? **************************************************************** From: Bob Duff Sent: Tuesday, December 18, 2018 3:42 PM > Both of these ideas are incompatible. Yes. But I'd think the Default_Value would typically obey the predicate, where 'null' probably does not. > ...I had forgotten the underlying reasoning related to the access type > case. Right, the problem is that you get implicit initialization whether you want it or not. That's not true of anything other than access types. It would be better to init access values to something that blows up if you look at it in any way, not just if you dereference it. Too late for that. > > Don't you think it's too late to make that change (only for access)? > > It just seemed inconsistent. I wanted to see if there was sympathy > with "fixing" this inconsistency. Apparently the access type > "inconsistency" was intentional, while perhaps the > scalar-type-with-default-value inconsistency was unintentional. I think the Default_Value case was a mistake, and I think it was my fault. > > I think I've written code that will break, like this: > > > > X : Some_Record_Containing_Access_Components; > > ... > > X := ...; > > Subtype predicates are already being checked on such a record type. > So your concern must be about subtype predicates on the access > subtypes used for the components of the record, which will fail if > they are null. Is that the example you had in mind? My example was confusing. Sorry. There is no predicate check on the decl of X, and you were proposing to change that, and I object. There is a predicate check when you assign into X, and that's a good thing (I'm sure we both agree). You can say: X : Scalar_Type_With_Predicate; ... X := ...; and it works fine. Same for a record containing scalars (without defaults). I just want to be able to do the same thing for access types, and for composites containing access types. Note that predicates work differently from "not null" in this regard, and last time I pointed that out, you wanted to change "not null" to work like predicates (i.e. going in the opposite direction as what you suggested in this email thread). I didn't want to change "not null", because I think it's an obsolete feature -- use predicates instead. But I don't STRONGLY object to that change -- it just seems like a waste of time. **************************************************************** From: Tucker Taft Sent: Tuesday, December 18, 2018 4:00 PM > ... > > Note that predicates work differently from "not null" in this regard, > and last time I pointed that out, you wanted to change "not null" to > work like predicates (i.e. going in the opposite direction as what you > suggested in this email thread). Unfortunately, I don't have any specific memory of this or what made me feel that way. It does seem way too late to change the behavior of "not null," and these days having uninitialized variables seems less and less necessary, given all of the ways to create values that incorporate conditionality. > I didn't want to change "not null", because I think it's an obsolete > feature -- use predicates instead. But I don't STRONGLY object to > that change -- it just seems like a waste of time. It seems too late to me now to change the behavior of "not null." I still don't like the inconsistency between Default_Value'd scalar types and composites with defaulted components, but the whole thing seems like a bit of a morass now. If everyone agreed scalar types with Default_Value specified should be treated the same as composite types with some defaults somewhere, then I would support that. But it doesn't really resolve the overall inconsistency, so not sure it is worth it. **************************************************************** From: Bob Duff Sent: Tuesday, December 18, 2018 4:13 PM > It seems too late to me now to change the behavior of "not null." I > still don't like the inconsistency between Default_Value'd scalar > types and composites with defaulted components, but the whole thing > seems like a bit of a morass now. If everyone agreed scalar types > with Default_Value specified should be treated the same as composite > types with some defaults somewhere, then I would support that. I think I support that. >...But it > doesn't really resolve the overall inconsistency, so not sure it is >worth it. I can make it sound sort-of consistent: If the programmer explicitly asked for defaults, they get a predicate check on an object decl with no init. If they didn't, then they don't. It kind of makes sense -- if you asked for defaults, you presumably make the default obey the predicate, except in a case like this: type Constant_Reference_Type (Element : not null access constant Element_Type) is record Control : Reference_Control_Type := raise Program_Error with "uninitialized reference"; -- The RM says, "The default initialization of an object of -- type Constant_Reference_Type or Reference_Type propagates -- Program_Error." end record; If the language forces you to have a particular default, you can't make it obey the predicate without loosening the predicate. **************************************************************** From: Randy Brukardt Sent: Tuesday, December 18, 2018 8:06 PM > > Both of these ideas are incompatible. > > Yes. But I'd think the Default_Value would typically obey the > predicate, where 'null' probably does not. > > > ...I had forgotten the underlying reasoning related to the > access type > > case. > > Right, the problem is that you get implicit initialization whether you > want it or not. That's not true of anything other than access types. That's not really accurate: you get implicit initialization of discriminants whether or not you initialize anything else in a record. For an unconstrained, mutable type, that can be an issue. You also have such a requirement for a tagged type (the tag being initialized). But I agree with Tucker: there is very little reason anymore to use any uninitialized objects. It's highly unfortunate that the easy thing to declare is an uninitialized variable, while what you ought to try to declare is an initialized constant. But of course, what made sense in 1978 doesn't make as much sense now. (Definitely something I would change in my "better Ada".) The only reason I know of is when you have a massive array covering almost all of memory that you will use an unknown part of. (That happened in my website log analyzer.) But in that case, it is the discriminant and/or tag initialization that kills you (such things tend to be some sort of complex record type). Access initialization might have been a problem, but the discriminant already forced it. > It would be better to init access values to something that blows up if > you look at it in any way, not just if you dereference it. Too late > for that. True, but this is just another thing that Ada 83 got wrong that we're stuck with. And the entire notion of objects that are invalid *after* declaration is bogus (but necessary for compatibility with Ada 83). IMHO, the only objects that should be allowed to be uninitialized are those with no constraints at all. > > > Don't you think it's too late to make that change (only for access)? > > > > It just seemed inconsistent. I wanted to see if there was sympathy > > with "fixing" this inconsistency. Apparently the access type > > "inconsistency" was intentional, while perhaps the > > scalar-type-with-default-value inconsistency was unintentional. > > I think the Default_Value case was a mistake, and I think it was my > fault. BTW, we're also talking about the Default_Component_Value case, but I don't think anyone is worried about treating those differently. > > > I think I've written code that will break, like this: > > > > > > X : Some_Record_Containing_Access_Components; > > > ... > > > X := ...; > > > > Subtype predicates are already being checked on such a record type. > > So your concern must be about subtype predicates on the access > > subtypes used for the components of the record, which will fail if > > they are null. Is that the example you had in mind? > > My example was confusing. Sorry. > > There is no predicate check on the decl of X, and you were proposing > to change that, and I object. Which is what I told Tucker in his original message. > There is a predicate check when you assign into X, and that's a good > thing (I'm sure we both agree). > > You can say: > > X : Scalar_Type_With_Predicate; > ... > X := ...; > > and it works fine. Yes, and that's so it is consistent with: X : Scalar_Type range ...; But the above is a rather nasty misfeature of Ada, and I've always objected to extending that misfeature further. The only objects that should be allowed to be uninitialized are those with no constraints (or those that match the constraints of 'Base). > Same for a record containing scalars > (without defaults). I just want to be able to do the same thing for > access types, and for composites containing access types. Understood, but I see no good reason that you should be allowed to. Ada 83 botched the definition of scalar types, and we're stuck with that. But why extend the misfeature even further? I almost always explicitly initialize null access objects (so I can read what is happening anyway, and so I know that I properly considered what to initialize the objects to) -- but in your world that does something different. I find that distasteful. > Note that predicates work differently from "not null" in this regard, > and last time I pointed that out, you wanted to change "not null" to > work like predicates (i.e. going in the opposite direction as what you > suggested in this email thread). > I didn't want to change "not null", because I think it's an obsolete > feature -- use predicates instead. But I don't STRONGLY object to > that change -- it just seems like a waste of time. I would strongly object to changing "not null", because it works the way the entire language should. (And we discussed this once before, but "not null" is not obsolete in any way -- it provides an assertion that the compiler can enforce and more importantly trust. To do that with predicates requires flow analysis [in Janus/Ada at least, that comes too late to be useful in checking elimination]. [On top of which, that other argument was about anonymous access types, which can't have predicates in the first place, so how "not null" can be obsolete for them escapes me. :-)]) And I don't see much reason to make a halfway change to predicates. Any change would be incompatible at this point, but such a change would mostly force people to write better code. So I personally would be in favor of such a change. But I don't see any reason to change the rule just to leave a "Bob" hole in it. At least the current rule has some form of logic. P.S. I think we actually argued all of this before approving the predicate AI in the first place. The current rule was a compromise that no one really likes. It is precisely why predicate use is less useful than it appears -- and unlikely type invariants, it didn't have to be that way. Grumble. **************************************************************** From: Randy Brukardt Sent: Tuesday, December 18, 2018 9:05 PM ... > Note that predicates work differently from "not null" in this regard, > and last time I pointed that out, you wanted to change "not null" to > work like predicates (i.e. going in the opposite direction as what you > suggested in this email thread). ["you" here meaning Tucker.] I don't recall any such discussion on ARG or Ada-Comment, nor any position from Tucker on this issue. The only discussion that happened here that I remember was about "not null" and anonymous access types. I'd guess you are remembering this incorrectly. (Of course, there's always a chance that it happened somewhere else, and Tucker was on his third glass of wine at the time. ;-) **************************************************************** From: Bob Duff Sent: Wednesday, December 19, 2018 8:46 AM > I don't recall any such discussion on ARG or Ada-Comment, nor any > position from Tucker on this issue. I thought it was on arg@, but if you don't remember it, maybe it was within AdaCore. I don't think I'm imagining things (but I could be wrong). **************************************************************** From: Randy Brukardt Sent: Thursday, January 3, 2019 10:06 PM ... It seems too late to me now to change the behavior of "not > null." I still don't like the inconsistency between Default_Value'd > scalar types and composites with defaulted components, but the whole > thing seems like a bit of a morass now. If everyone agreed scalar > types with Default_Value specified should be treated the same as > composite types with some defaults somewhere, then I would support > that. But it doesn't really resolve the overall inconsistency, so not > sure it is worth it. I certainly agree; it would be more consistent with the rest of the language (where the presence of Default_Value changes the semantics). Bob replied: > I can make it sound sort-of consistent: If the programmer explicitly > asked for defaults, they get a predicate check on an object decl with > no init. If they didn't, then they don't. And the reason for replying to this now: I'd guess that we'd want to include Default_Component_Value in any rule change as well. A component with such a type also is default-initialized by something under control of the user. >It kind of makes sense -- if you asked for defaults, you presumably >make the default obey the predicate, except in a case like this: > > type Constant_Reference_Type > (Element : not null access constant Element_Type) is > record > Control : Reference_Control_Type := > raise Program_Error with "uninitialized reference"; > -- The RM says, "The default initialization of an object of > -- type Constant_Reference_Type or Reference_Type propagates > -- Program_Error." > end record; > >If the language forces you to have a particular default, you can't make >it obey the predicate without loosening the predicate. Well, in this case, it doesn't matter what the predicate is 'cause the default initialization will raise an exception before any predicate could be evaluated. The point was of course to prevent default-initialized objects from existing. That would have been a better way to handle access types, but like everything it is way too late. **************************************************************** From: Tucker Taft Sent: Friday, January 4, 2019 8:19 AM > ... > It seems too late to me now to change the behavior of "not >> null." I still don't like the inconsistency between Default_Value'd >> scalar types and composites with defaulted components, but the whole >> thing seems like a bit of a morass now. If everyone agreed scalar >> types with Default_Value specified should be treated the same as >> composite types with some defaults somewhere, then I would support >> that. But it doesn't really resolve the overall inconsistency, so >> not sure it is worth it. > > I certainly agree; it would be more consistent with the rest of the > language (where the presence of Default_Value changes the semantics). When you say "it would be more consistent," what does "it" refer to? > Bob replied: >> I can make it sound sort-of consistent: If the programmer explicitly >> asked for defaults, they get a predicate check on an object decl with >> no init. If they didn't, then they don't. > > And the reason for replying to this now: I'd guess that we'd want to > include Default_Component_Value in any rule change as well. A > component with such a type also is default-initialized by something under > control of the user. Agreed. To be consistent, specifying Default_Component_Value should trigger evaluation of any predicates, whether on the component subtype or the array subtype. >> It kind of makes sense -- if you asked for defaults, you presumably >> make the default obey the predicate, except in a case like this: >> >> type Constant_Reference_Type >> (Element : not null access constant Element_Type) is >> record >> Control : Reference_Control_Type := >> raise Program_Error with "uninitialized reference"; >> -- The RM says, "The default initialization of an object of >> -- type Constant_Reference_Type or Reference_Type propagates >> -- Program_Error." >> end record; >> >> If the language forces you to have a particular default, you can't >> make it obey the predicate without loosening the predicate. I suppose. As far as whether to use copy-in for "out" parameters, we don't make such a distinction between Default-Value'd scalars and access types. On the other hand, for "out" parameters, we never check the access subtype on the copied-in value (RM 6.4.1(13/3)), so that does represent somewhat of a special case for access types. On the other, other hand, scalars with Default_Value and composite types with some default-initialized components are treated differently for OUT parameters as far as checking predicates. For a scalar OUT parameter, we never check the predicate even if we copy in, whereas for composite OUT parameters with any defaulted components, they are treated like IN OUT parameters, and hence will have predicates checked. So OUT parameters have somewhat the same inconsistency we were worried about between Default_Value'd scalars and composites with default-init'ed components. So in as much as we see OUT parameters and not-explicitly-initialized objects as being similar, the same sort of inconsistencies exist in both cases. > Well, in this case, it doesn't matter what the predicate is 'cause the > default initialization will raise an exception before any predicate > could be evaluated. The point was of course to prevent > default-initialized objects from existing. That would have been a > better way to handle access types, but like everything it is way too late. Not sure what you mean by this last sentence. What would have been a better way to handle access types? Bottom line for me: The rules for whether to check predicates on non-explicitly-initialized objects are not sufficiently broken, and are too hard to decide on any possible fix. **************************************************************** From: Randy Brukardt Sent: Friday, January 4, 2019 4:54 PM ... > > I certainly agree; it would be more consistent with the rest of the > > language (where the presence of Default_Value changes the > semantics). > > When you say "it would be more consistent," what does "it" refer to? Changing the predicate rule to include components with Default_Value or Default_Component_Value. Bob's justification is a bit hand wavy, but it's at least understandable. Personally, I'd rather include any default-initialized object (that is, including access values) -- I don't see any good reason to make a language mistake worse. (That is, that there are cases where the constraint/predicate of an object is allowed to be False. We obviously were stuck with that from Ada 83, but that doesn't make it any better.) But clearly Bob would object to that, he has a different view and he's not likely to be swayed even now. (I'm pretty sure that the design of "not null" would have been different had he been participating regularly in the ARG work when that was defined. All of the Legality Rules about "not null" exist so that there never is a case where a "not null" object contains null -- the feeling at the time was that is how Ada should have worked, but we were stuck with a bad definition. I'm sure that group would have made predicates work like "not null".) And he's right that there would be a compatibility issue, which is less concerning for Default_Value/Default_Component_Value, which are much less used than access types. ... > I suppose. As far as whether to use copy-in for "out" > parameters, we don't make such a distinction between Default-Value'd > scalars and access types. On the other hand, for "out" parameters, we > never check the access subtype on the copied-in value (RM > 6.4.1(13/3)), so that does represent somewhat of a special case for > access types. > > On the other, other hand, scalars with Default_Value and composite > types with some default-initialized components are treated differently > for OUT parameters as far as checking predicates. For a scalar OUT > parameter, we never check the predicate even if we copy in, whereas > for composite OUT parameters with any defaulted components, they are > treated like IN OUT parameters, and hence will have predicates > checked. So OUT parameters have somewhat the same inconsistency we > were worried about between Default_Value'd scalars and composites with > default-init'ed components. > > So in as much as we see OUT parameters and not-explicitly-initialized > objects as being similar, the same sort of inconsistencies exist in > both cases. I originally started to write something about OUT parameters in my reply, but after reading the rules I couldn't decide if it proved anything, so I deleted that paragraph. And I think you see why. ;-) > > Well, in this case, it doesn't matter what the predicate is 'cause > > the default initialization will raise an exception before any > > predicate could be evaluated. The point was of course to prevent > > default-initialized objects from existing. That would have been a > > better way to handle access types, but like everything it is way too > > late. > > Not sure what you mean by this last sentence. What would have been a > better way to handle access types? I was thinking out loud. Ada 83 was trying to prevent the existence of uninitialized access values. It adopted a rule forcibly initializing them to null. It would have been better to simply have them raise an exception like Program_Error (meaning that all such objects would have to be initialized). It's not that much harder to write: Temp : My_Access := null; than Temp : My_Access; and it's way clearer. (Indeed, default-initialization ought to be rare in newly written Ada 2012 and later code; I'd prefer that it be marked if you want that, something like: Temp : Natural := <>; rather than having the easy thing to write be the least safe and most expensive in use. But that will have to wait for "Better Ada".) The alternative of default-initializing access values to "bottom", which raise an exception when read, is too expensive for Ada (as it implies overhead on most reads - that overhead could be eliminated with a mechanism similar to the one used by Janus/Ada for validity - if the object is explicitly initialized, no reading checks are needed - even so, that seems like a bridge too far). > Bottom line for me: The rules for whether to check predicates on > non-explicitly-initialized objects are not sufficiently broken, and > are too hard to decide on any possible fix. I think that rule is severely broken, and I knew that when it was written. (I probably should have fought harder at the time, but one has to pick his battles...) Bob being the reason that it is broken, and him having agreed to a small fix which improves the situation, seems to me to be enough reason to formally propose a fix along the lines of what Bob has said he'd agree to. (As I noted above, I have to be sensitive to the likelihood that a full fix would be too incompatible to adopt.) P.S. This topic always seems to get me worked up and I write far too much on it. Sorry. **************************************************************** From: Tucker Taft Sent: Friday, January 4, 2019 5:27 PM > I was thinking out loud. Ada 83 was trying to prevent the existence of > uninitialized access values. It adopted a rule forcibly initializing them to > null. It would have been better to simply have them raise an exception like > Program_Error (meaning that all such objects would have to be initialized). > It's not that much harder to write: > > Temp : My_Access := null; > > than > > Temp : My_Access; > > and it's way clearer. (Indeed, default-initialization ought to be rare in > newly written Ada 2012 and later code; I'd prefer that it be marked if you > want that, something like: > > Temp : Natural := <>; > > rather than having the easy thing to write be the least safe and most > expensive in use. But that will have to wait for "Better Ada".) When doing static analysis, it is tricky to distinguish between the programmer omitting the explicit initialization specifically to get the default, or omitting it because it must be initialized explicitly later. Some languages happily default initialize everything to something like zero, which exacerbates this problem. I agree with you that something like "<>" might have been a better way to explicitly get some "default" value. The new "[]" notation may emerge as something approximating that for containers. In ParaSail, "()" can be used when all components of a (visible) type have defaults. And finally there is "null" in ParaSail, which can be used with any type, representing the absence of a value. Isn't language design fun? ;-) **************************************************************** From: Randy Brukardt Sent: Friday, January 4, 2019 5:54 PM >When doing static analysis, it is tricky to distinguish between the programmer >omitting the explicit initialization specifically to get the default, >or omitting it because it must be initialized explicitly later. Some languages >happily default initialize everything to something like zero, which exacerbates >this problem. And of course "reading code" is just static analysis performed by the programmer rather than a machine. If it's hard to statically analyze, it's probably a readability problem too. >I agree with you that something like "<>" might have been a better way >to explicitly get some "default" value. The new "[]" notation may >emerge as something approximating that for containers. In ParaSail, >"()" can be used when all components of a (visible) type have defaults. >And finally there is "null" in ParaSail, which can be used with any >type, representing the absence of a value. You might remember that Ada 2005 briefly had "(<>)" as the default-initialized object of any composite type. As I recall, there were some semantic issues with that that got it tossed out at the last minute (during the snowstorm in Paris). It probably could have been made to work, but it didn't seem important enough at the time. I've rather regretted that, as I wanted to use it and a restriction (No_Uninitialized_Objects) to at least allow/enforce a better style. >Isn't language design fun? ;-) Surely. I've spent way too much time thinking about how best to handle arrays and strings in "Better Ada". One of these days I'll write something up (as a blog entry, not here). ****************************************************************