From: Randy Brukardt on 9 Feb 2010 21:39 "Hibou57 (Yannick Duch�ne)" <yannick_duchene(a)yahoo.fr> wrote in message news:4e959c35-34d1-49fb-b1eb-5b298e42610f(a)z19g2000yqk.googlegroups.com... >On 9 f�v, 15:47, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote: >> I agree that it's good to avoid heap management when possible. >> But why can't you declare local variables of type My_Interface'Class, >> initialized with build-in-place function calls? > >Synchronized-and-the-like interface types are limited, so the built-in- >place is indeed really built-in-place (no kind of conversion allowed >at any stage). The initializer function have to return a class wide >and return it using an extended return statement which is required to >return the same exact type/subtype as the one function returns. > >This way of doing thing is not compatible with the implementation- >hiding requirement, as it would require the implementation type to be >exposed in the public part, so that I could define a public function >returning this exact type. I don't buy this at all. The exact types to create can be selected by many means (presumably by the parameters). You can use a dispatching constructor function in the concrete types, using the factory pattern (Generic_Dispatching_Constructor), and roughly organized as Bob noted. Note that you have this problem with *any* constructor of any tagged type if you have any interest at all in allowing future extensions. It would be nice to have a container for Classwide limited types as the problem comes up frequently. We made some initial efforts in that direction but had problems with finalization and readability of the results. We then turned our attention to those building-block problems and never did come back to the limited containers themselves. I suspect that we could do a very usable job with the new syntax magic for iterators, accessors, and the like. (Presuming that we got those to work out, not there yet.) Randy.
From: Hibou57 (Yannick Duchêne) on 10 Feb 2010 00:12 On 10 fév, 00:29, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote: > I don't understand the problem. The following should work. > Doesn't it do what you want? Type T exports Public, > but hides Hidden. No heap allocation. > > package P is > type T is synchronized interface; > function Create return T'Class; > > procedure Public (X : in out T) is abstract; > > private > > protected type T2 is new T with > overriding entry Public; > entry Hidden; > end T2; > > end P; > > package body P is > function Create return T'Class is > begin > return Result : T2 do > ... > end return; > end Create; > > protected body T2 is > entry Public when ... is > begin > ... > end Public; > > entry Hidden when ... is > begin > ... > end Hidden; > end T2; > > end P; > > with P; use P; > procedure Main is > > X : T'Class := Create; > > begin > Public (X); > end Main; > > - Bob This was exactly what I've tried, except that I used something like return Result : T'Class := ... do instead of return Result : T2 do , which is not legal, as stated by the ARM : [ARM 6.5(5.2/2)] If the result subtype of the function is defined by a subtype_mark, the return_subtype_indication shall be a subtype_indication. Ok for this one, but later it's going wrong : Remainder of [ARM 6.5(5.2/2)] The type of the subtype_indication shall be the result type of the function. But T2, in the return statement, is not T'Class, in the function return type indication. And indeed, when I've tried your way, GNAT complained wrong type for return_subtype_indication So it must be T'Class in the return statement, and as by both [ARM 6.5(5.d/2)] Discussion: We know that if the result type is class wide, then there must be an expression of the return statement. and [ARM 6.5(5.5/2)] If the result subtype of the function is limited, then the expression of the return statement (if any) shall be an aggregate, a function call (or equivalent use of an operator), or a qualified_expression or parenthesized expression whose operand is one of these. an initialization is required (otherwise the concret type of the object would be unknown). I was failing there, as there is no kind of extention aggregate for a protected type (it's not a record, although tagged). But I've finally solved the trick : see next reply to Randy. On 10 fév, 00:29, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote: > I don't understand the problem. The following should work. > Doesn't it do what you want? Type T exports Public, > but hides Hidden. No heap allocation. > > package P is > type T is synchronized interface; > function Create return T'Class; > > procedure Public (X : in out T) is abstract; > > private > > protected type T2 is new T with > overriding entry Public; > entry Hidden; > end T2; > > end P; > > package body P is > function Create return T'Class is > begin > return Result : T2 do > ... > end return; > end Create; > > protected body T2 is > entry Public when ... is > begin > ... > end Public; > > entry Hidden when ... is > begin > ... > end Hidden; > end T2; > > end P; > > with P; use P; > procedure Main is > > X : T'Class := Create; > > begin > Public (X); > end Main; > > - Bob This was exactly what I've tried, except that I used something like return Result : T'Class := ... do instead of return Result : T2 do , which is not legal, as stated by the ARM : [ARM 6.5(5.2/2)] If the result subtype of the function is defined by a subtype_mark, the return_subtype_indication shall be a subtype_indication. Ok for this one, but later it's going wrong : Remainder of [ARM 6.5(5.2/2)] The type of the subtype_indication shall be the result type of the function. But T2, in the return statement, is not T'Class, in the function return type indication. And indeed, when I've tried your way, GNAT complained wrong type for return_subtype_indication So it must be T'Class in the return statement, and as by both [ARM 6.5(5.d/2)] Discussion: We know that if the result type is class wide, then there must be an expression of the return statement. and [ARM 6.5(5.5/2)] If the result subtype of the function is limited, then the expression of the return statement (if any) shall be an aggregate, a function call (or equivalent use of an operator), or a qualified_expression or parenthesized expression whose operand is one of these. an initialization is required (otherwise the concret type of the object would be unknown). I was failing there, as there is no kind of extention aggregate for a protected type (it's not a record, although tagged). But I've finally solved the trick : see next, in the reply to Randy On 10 fév, 03:39, "Randy Brukardt" <ra...(a)rrsoftware.com> wrote: > I don't buy this at all. The exact types to create can be selected by many > means (presumably by the parameters). You can use a dispatching constructor > function in the concrete types, using the factory pattern > (Generic_Dispatching_Constructor), and roughly organized as Bob noted. What confused me, was I meet with initialization of a class wide type whose initializer was to of a protected type, as explained in the reply to Robert/Bob. I could finally solve it, using a function, instead of an aggregate. > Note that you have this problem with *any* constructor of any tagged type if > you have any interest at all in allowing future extensions. While tagged record and tagged protected is not fully the same, as this example shows. Well, finally the previous assertion is canceled, and there is indeed a nice and clean way to do things with a synchronized interface type. Thanks to the one who suggested this path.
From: Hibou57 (Yannick Duchêne) on 10 Feb 2010 02:17 On 10 fév, 06:12, Hibou57 (Yannick Duchêne) <yannick_duch...(a)yahoo.fr> wrote: > What confused me, was I meet with initialization of a class wide type > whose initializer was to of a protected type, as explained in the > reply to Robert/Bob. > > I could finally solve it, using a function, instead of an aggregate. Unfortunately, this was working only when the interface type is "implemented" by a protected type, but as soon as I want to apply the same scheme with a task type "implementing" the interface, then GNAT crashes (it says Program_Error EXCEPTION_ACCESS_VIOLATION). Not lucky
From: Adam Beneschan on 10 Feb 2010 11:05 On Feb 9, 6:56 am, Robert A Duff <bobd...(a)shell01.TheWorld.com> wrote: > AdaMagica <christoph.gr...(a)eurocopter.com> writes: > > OK, but then you have a similar problem to Ada83's syntactically > > unneeded bodies which Ada95 solved with a pragma. > > I think that problem is an illusion. There was a problem, > but it was a problem with implementations, not with the > language. How do we know if a given package spec has > a body? Simple: look on the disk and see if there's > a source file containing that body. In GNAT, that would > mean looking for foo.adb. And for other implementations (that put fewer restrictions on the names and locations of source files containing the Ada source), that would mean searching every file on the disk to see if one of them had "package body foo" in it. :) :) I know---those other implementations wouldn't do things this way; they'd provide some other mechanism to allow a programmer to tell the compilation system that a package no longer requires a body---or does require a body. But you should be careful when you say things like "Simple...". Unless, of course, you were joking. Anyway, the problem was certainly solvable in any implementation, although as Randy points out it's still not ideal because it makes it too easy for an accidental error to result in the compiler accepting a package without a body that's supposed to have one, or vice versa, causing incorrect results at runtime that could be puzzling to track down. And that issue exists with GNAT also---you delete some files from your directory with a wildcard, somehow foo.adb accidentally gets deleted along with them, and the compiler still thinks your program is OK. -- Adam
From: Robert A Duff on 10 Feb 2010 11:09
"Hibou57 (Yannick Duch�ne)" <yannick_duchene(a)yahoo.fr> writes: > Remainder of [ARM 6.5(5.2/2)] > The type of the subtype_indication shall be the result type of the > function. Ah, I see the problem. This is a mistake in the RM, and there's an AI that fixes it. The real rule is that (in my example) T2 must be covered by T'Class, which it is. Recent versions of GNAT correctly implement this new rule, but I don't know what version you're using. - Bob |