mfeldman@seas.gwu.edu (Michael Feldman) (06/14/90)
I have a rationale-type questions regarding an apparent irregularity in Ada, namely in the area of default initializations. - We know that a _variable_ can be initialized in its declaration, e.g. X: T := some_expression; where some_expression need not even be static. [digression: over-use of this can be risky IMHO because of nastiness if some_expression manages to propagate an exception - the point is that initialization is permitted]. - We know that the components of a _record_ type can be default-initialized in the definition of the record type, e.g. type R is record F1 : T1 := something; F2 : T2 := something_else; end record; where some thing something_else can be e.g. aggregates. I don't remember having seen any discussion on the group about why other types cannot be default-initialized, e.g. type Little is range -10 .. 10 := 0; or type Vector is array (1..10) of float := (1..10 => 0.0); or even type Vector is array (integer range <>) of float := (others => 0.0); The last 3 examples are not permitted; it's obvious at least to me that there would be great benefit in permitting them. What are the costs? Can someone speak authoritatively about why this irregularity exists? The Ada Rationale gives a nice justification of default initializations (for record types, of course) but doesn't say boo about why, if they are so valuable, they are not allowed uniformly. I'm one of these guys who always wonders why irregularities in _designed_ languages exist. There is usually a pretty good reason, but in this case it certainly isn't obvious. (Irregularities even in natural languages often have good linguistic reasons). Thanks for whatever enlightenment is forthcoming. --------------------------------------------------------------------------- Prof. Michael Feldman Department of Electrical Engineering and Computer Science The George Washington University Washington, DC 20052 +1-202-994-5253 mfeldman@seas.gwu.edu ---------------------------------------------------------------------------
firth@sei.cmu.edu (Robert Firth) (06/15/90)
In article <1957@sparko.gwu.edu> mfeldman@seas.gwu.edu (Michael Feldman) writes: >I have a rationale-type questions regarding an apparent irregularity >in Ada, namely in the area of default initializations. There is no good reason for the irregularity. Since a record component can be of any type, the implementation of record Component : Thing := Initial_Value; end record; is no more and no less difficult than the implementation of type Thing is Type_Definition := Initial_Value; would be. There are no serious parsing difficulties with the above syntax, and no additional semantic issues. The reason for the irregularity is historical. In the original Green language, the syntax of a record type definition read record_type_definition ::= RECORD component_list END RECORD component_list ::= {object_declaration} [variant_part] | NULL ; Because the syntax of object_definition was reused, the ability to initialise the component got carried over automatically. When this was noticed, it was decided that this was a useful thing to have. I recall asking Jean why he didn't make the type model more regular by allowing all types to have initialisation expressions, and his reply was that you could always achieve this effect by nesting the type you wanted in a record, and he didn't want to add extra syntax. Please do not ask me to defend this position.
murphy@mips.COM (Mike Murphy) (06/15/90)
In article <1957@sparko.gwu.edu> mfeldman@seas.gwu.edu (Michael Feldman) writes: >I don't remember having seen any discussion on the group about why other >types cannot be default-initialized, e.g. > type Little is range -10 .. 10 := 0; >or > type Vector is array (1..10) of float := (1..10 => 0.0); >or even > type Vector is array (integer range <>) of float := (others => 0.0); I question how useful type initialization is given that we can easily initialize variables, but I agree that it is an irregularity to only allow it for record types. When I first read this question I thought, yea, that should be easy to do. But then I thought of some complications. To take your above example, suppose we later said: subtype PosLittle is Little range 1..10; p : PosLittle; What is p initialized to? If we implicitly initialize p to 0 we should raise constraint_error; is that acceptable? A related issue is initializing unconstrained arrays; either we limit the initialization to the others clause, or we have situations like: type Vector is array (integer range <>) of float := (0 => 0.0, others => 1.0); v : Vector(1..10); What happens here? Either we could raise constraint_error because there is an initialization to a component outside the range of v, or we could treat it like a variant part of a record that is not used and just ignore that part of the initialization. Which brings up the fact that type initialization is not free; it often requires building an implicit procedure that the compiler calls to dynamically decide how to initialize the object. A last case is initializing access types; is anything other than "null" a legal initial value, e.g. type astring is access string := new string'("void"); a : astring(1..3); -- constraint_error? -- Mike Murphy -- UUCP: sun!decwrl!mips!murphy or murphy@mips.com
mfeldman@seas.gwu.edu (Michael Feldman) (06/15/90)
In article <7540@fy.sei.cmu.edu> firth@sei.cmu.edu (Robert Firth) writes: > > I recall asking Jean why he didn't make the type model more regular > by allowing all types to have initialisation expressions, and his > reply was that you could always achieve this effect by nesting the > type you wanted in a record, and he didn't want to add extra syntax. > Please do not ask me to defend this position. Don't worry. If this is the extent of the reasoning, it's entirely indefensible IMHO. That's the way it goes. Sigh... --------------------------------------------------------------------------- Prof. Michael Feldman Department of Electrical Engineering and Computer Science The George Washington University Washington, DC 20052 +1-202-994-5253 mfeldman@seas.gwu.edu ---------------------------------------------------------------------------
mfeldman@seas.gwu.edu (Michael Feldman) (06/15/90)
In article <39390@mips.mips.COM> murphy@mips.COM (Mike Murphy) writes: > > To take your above example, suppose we later said: > subtype PosLittle is Little range 1..10; > p : PosLittle; > What is p initialized to? > If we implicitly initialize p to 0 we should raise constraint_error; > is that acceptable? Sure. Sounds OK to me. But you're right - the subtype issue does complicate matters a bit. > > A related issue is initializing unconstrained arrays; either we limit > the initialization to the others clause, or we have situations like: > type Vector is array (integer range <>) of float := > (0 => 0.0, others => 1.0); > v : Vector(1..10); I'm sure a counterexample could be found, but I guess I would allow only "others" aggregates for unconstrained array types. Explicitly supplying an index for something whose index range is undefined is not a sensible thing to do, it seems to me. > [ . . . ] Which brings up the fact that type > initialization is not free; it often requires building an implicit > procedure that the compiler calls to dynamically decide how to initialize > the object. Indeed. But there are many areas requiring this sort of dynamic decision anyway. > > A last case is initializing access types; is anything other than "null" > a legal initial value, e.g. > type astring is access string := new string'("void"); Hmmm. I'd advocate against this kind of dynamic initialization even if it were a variable declaration. If Storage_Error were raised, for example, the exception would undoubtedly propagate to an undesirable place. (since it would be raised in an elaboration, the current frame's handler can't handle, therefore the exception propagates). Might be legal, but not a good idea. This is what I argued in my last posting: initializations can be good, but can be too powerful for their own good if used over-zealously. > a : astring(1..3); -- constraint_error? ^^^^^^^ Hmmm. I wasn't aware that one could supply a constraint this way. For a string, sure. For an "access to string", is this legal Ada (i.e. the implicit "new")? If so, I just learned a new style. Mike Feldman
stachour@sctc.com (Paul Stachour) (03/28/91)
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >I would rather see features that help people detect or avoid the error >of using an uninitialised variable rather than features which define >the problem away. For example, if arrays with fill pointers were a >standard part of the language (perhaps defined as a standard package), >then we'd be close enough to Dijkstra's arrays to get some of the >protection without being too far from the kind of array already present. >Don't expect default initial values for types to be an unmixed blessing. As one who has programmed regularly in more than an half-dozen languages, and has worked on teams that have implemented 3 compilers for different lanauges, I agree. If you have a variable that is unitialized, then a good flow anyalysis tool (we had some inside one of the compilers) can follow your control-flow and give you "used before set" messages. When you do have something initialized, it is, by definition, set. Thus the flow-analysis gives you nothing. I long for the (ancient) FORTRAN II compiler I used on an IBM 7074 in the mid-1960s. It set all of the words in the machine to an "invalid pattern" before beginning your program. And then if you fetched anything that hadn't been set, you took a hardware fault and the run-time told what you were doing wrong. Much like Saber-C and other good c-interpreters can do today, but with hardware support. One problem is when you have an uninitialized item as a component of a struacture and you assign one instance of the structre to another. Do you get a fault or not. You really aren't "using" the item yet. Enjoy. ...Paul -- Paul Stachour SCTC, 1210 W. County Rd E, Suite 100 stachour@sctc.com Arden Hills, MN 55112 [1]-(612) 482-7467