comp.lang.ada
 help / color / mirror / Atom feed
* Type invariants and private extensions?
@ 2017-09-11 19:51 Victor Porton
  2017-09-11 20:00 ` Egil H H
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-11 19:51 UTC (permalink / raw)


As far as I understand, type invariants cannot be applied to types with 
private extensions. Right?

It would be nice to create private extension types which would allow to use 
them only when certain boolean function on the parent type returns True.

Is anything like this possible?

-- 
Victor Porton - http://portonvictor.org


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 19:51 Type invariants and private extensions? Victor Porton
@ 2017-09-11 20:00 ` Egil H H
  2017-09-11 20:48   ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Egil H H @ 2017-09-11 20:00 UTC (permalink / raw)


On Monday, September 11, 2017 at 9:51:35 PM UTC+2, Victor Porton wrote:
> As far as I understand, type invariants cannot be applied to types with 
> private extensions. Right?
> 
> It would be nice to create private extension types which would allow to use 
> them only when certain boolean function on the parent type returns True.
> 
> Is anything like this possible?
> 

You can already do
type Foo is tagged private
   with Type_Invariant'Class => Bar(Foo);

The Invariant will then be inherited by all derived types


-- 
~egilhh


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 20:00 ` Egil H H
@ 2017-09-11 20:48   ` Victor Porton
  2017-09-11 21:19     ` Egil H H
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-11 20:48 UTC (permalink / raw)


Egil H H wrote:

> On Monday, September 11, 2017 at 9:51:35 PM UTC+2, Victor Porton wrote:
>> As far as I understand, type invariants cannot be applied to types with
>> private extensions. Right?
>> 
>> It would be nice to create private extension types which would allow to
>> use them only when certain boolean function on the parent type returns
>> True.
>> 
>> Is anything like this possible?
>> 
> 
> You can already do
> type Foo is tagged private
>    with Type_Invariant'Class => Bar(Foo);
> 
> The Invariant will then be inherited by all derived types

It is not what I want. I want different invariants for different derived 
types.

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 20:48   ` Victor Porton
@ 2017-09-11 21:19     ` Egil H H
  2017-09-11 21:27       ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Egil H H @ 2017-09-11 21:19 UTC (permalink / raw)


On Monday, September 11, 2017 at 10:48:46 PM UTC+2, Victor Porton wrote:
> > The Invariant will then be inherited by all derived types
> 
> It is not what I want. I want different invariants for different derived 
> types.
> 

You can add new invariants in addition to the ones inherited


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:19     ` Egil H H
@ 2017-09-11 21:27       ` Victor Porton
  2017-09-11 21:49         ` Egil H H
                           ` (3 more replies)
  0 siblings, 4 replies; 28+ messages in thread
From: Victor Porton @ 2017-09-11 21:27 UTC (permalink / raw)


Egil H H wrote:

> On Monday, September 11, 2017 at 10:48:46 PM UTC+2, Victor Porton wrote:
>> > The Invariant will then be inherited by all derived types
>> 
>> It is not what I want. I want different invariants for different derived
>> types.
>> 
> 
> You can add new invariants in addition to the ones inherited

I cannot: the compiler gives an error:

package P is

  type T is tagged private;

private

  type T is tagged null record;

end P;

with P; use P;

package P1 is

  type T1 is new T with null record
    with Type_Invariant => True;

end P1;


$ gnatgcc -gnatc -c p1.ads 
p1.ads:6:10: aspect "Type_Invariant" only allowed for private type or 
corresponding full view

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:27       ` Victor Porton
@ 2017-09-11 21:49         ` Egil H H
  2017-09-11 22:00           ` Victor Porton
  2017-09-11 22:00         ` Jere
                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 28+ messages in thread
From: Egil H H @ 2017-09-11 21:49 UTC (permalink / raw)


On Monday, September 11, 2017 at 11:27:54 PM UTC+2, Victor Porton wrote:
> 
>   type T1 is new T with null record
>     with Type_Invariant => True;
> 
> 

Like I said, Type_Invariant'Class...

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:27       ` Victor Porton
  2017-09-11 21:49         ` Egil H H
@ 2017-09-11 22:00         ` Jere
  2017-09-11 22:02           ` Victor Porton
  2017-09-11 22:48         ` Shark8
  2017-10-02 23:16         ` Randy Brukardt
  3 siblings, 1 reply; 28+ messages in thread
From: Jere @ 2017-09-11 22:00 UTC (permalink / raw)


On Monday, September 11, 2017 at 5:27:54 PM UTC-4, Victor Porton wrote:
> Egil H H wrote:
> 
> > On Monday, September 11, 2017 at 10:48:46 PM UTC+2, Victor Porton wrote:
> >> > The Invariant will then be inherited by all derived types
> >> 
> >> It is not what I want. I want different invariants for different derived
> >> types.
> >> 
> > 
> > You can add new invariants in addition to the ones inherited
> 
> I cannot: the compiler gives an error:
> 
> package P is
> 
>   type T is tagged private;
> 
> private
> 
>   type T is tagged null record;
> 
> end P;
> 
> with P; use P;
> 
> package P1 is
> 
>   type T1 is new T with null record
>     with Type_Invariant => True;
> 
> end P1;
> 
> 
> $ gnatgcc -gnatc -c p1.ads 
> p1.ads:6:10: aspect "Type_Invariant" only allowed for private type or 
> corresponding full view
> 
> -- 
> Victor Porton - http://portonvictor.org

You aren't applying it to a private type.  Try:

   package P1 is
      
      type T1 is new T with private
         with Type_Invariant'Class => True;
      
   private

      type T1 is new T with null record;
        

   end P1;

The relevant RM section:

7.3.2

2/3
Type_Invariant

This aspect shall be specified by an expression, called an 
invariant expression. Type_Invariant may be specified on a 
private_type_declaration, on a private_extension_declaration, 
or on a full_type_declaration that declares the completion of 
a private type or private extension.

3/3
Type_Invariant'Class

This aspect shall be specified by an expression, called an 
invariant expression. Type_Invariant'Class may be specified 
on a private_type_declaration or a private_extension_declaration.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:49         ` Egil H H
@ 2017-09-11 22:00           ` Victor Porton
  2017-09-11 22:06             ` Egil H H
  2017-09-12  7:30             ` Dmitry A. Kazakov
  0 siblings, 2 replies; 28+ messages in thread
From: Victor Porton @ 2017-09-11 22:00 UTC (permalink / raw)


Egil H H wrote:

> On Monday, September 11, 2017 at 11:27:54 PM UTC+2, Victor Porton wrote:
>> 
>>   type T1 is new T with null record
>>     with Type_Invariant => True;
>> 
>> 
> 
> Like I said, Type_Invariant'Class...

It seems that you don't understand me: I need different boolean functions 
for different derived tagged types. If we specify Type_Invariant or 
Type_Invariant'Class this is the same function because it can be specified 
only for the base class not my derived classes.

Or maybe I do not understand you? If so, please explain.

Hm, well, Type_Invariant'Class may point to dispatching function which can 
be overridden in the derived classes. Isn't it what you mean?

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 22:00         ` Jere
@ 2017-09-11 22:02           ` Victor Porton
  2017-09-12 18:26             ` Jeffrey R. Carter
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-11 22:02 UTC (permalink / raw)


Isn't it a good idea to modify the RM to allow type invariants also for 
derived types with null records?

Jere wrote:
> On Monday, September 11, 2017 at 5:27:54 PM UTC-4, Victor Porton wrote:
>> Egil H H wrote:
>> 
>> > On Monday, September 11, 2017 at 10:48:46 PM UTC+2, Victor Porton
>> > wrote:
>> >> > The Invariant will then be inherited by all derived types
>> >> 
>> >> It is not what I want. I want different invariants for different
>> >> derived types.
>> >> 
>> > 
>> > You can add new invariants in addition to the ones inherited
>> 
>> I cannot: the compiler gives an error:
>> 
>> package P is
>> 
>>   type T is tagged private;
>> 
>> private
>> 
>>   type T is tagged null record;
>> 
>> end P;
>> 
>> with P; use P;
>> 
>> package P1 is
>> 
>>   type T1 is new T with null record
>>     with Type_Invariant => True;
>> 
>> end P1;
>> 
>> 
>> $ gnatgcc -gnatc -c p1.ads
>> p1.ads:6:10: aspect "Type_Invariant" only allowed for private type or
>> corresponding full view
>> 
>> --
>> Victor Porton - http://portonvictor.org
> 
> You aren't applying it to a private type.  Try:
> 
>    package P1 is
>       
>       type T1 is new T with private
>          with Type_Invariant'Class => True;
>       
>    private
> 
>       type T1 is new T with null record;
>         
> 
>    end P1;
> 
> The relevant RM section:
> 
> 7.3.2
> 
> 2/3
> Type_Invariant
> 
> This aspect shall be specified by an expression, called an
> invariant expression. Type_Invariant may be specified on a
> private_type_declaration, on a private_extension_declaration,
> or on a full_type_declaration that declares the completion of
> a private type or private extension.
> 
> 3/3
> Type_Invariant'Class
> 
> This aspect shall be specified by an expression, called an
> invariant expression. Type_Invariant'Class may be specified
> on a private_type_declaration or a private_extension_declaration.
-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 22:00           ` Victor Porton
@ 2017-09-11 22:06             ` Egil H H
  2017-09-12  7:30             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 28+ messages in thread
From: Egil H H @ 2017-09-11 22:06 UTC (permalink / raw)


On Tuesday, September 12, 2017 at 12:00:41 AM UTC+2, Victor Porton wrote:
> 
> It seems that you don't understand me: I need different boolean functions 
> for different derived tagged types. If we specify Type_Invariant or 
> Type_Invariant'Class this is the same function because it can be specified 
> only for the base class not my derived classes.
> 
> Or maybe I do not understand you? If so, please explain.
> 
> Hm, well, Type_Invariant'Class may point to dispatching function which can 
> be overridden in the derived classes. Isn't it what you mean?
> 
> 

Any Invariants declared for a parent type must also hold for all derived types, but derived types can add more. Think about what someone holding a variable of Parent'Class expects. The definition of Parent promises an invariant. But what if the actual type is a child? Mayhem will ensue if the child does not promise the same invariant, hence it is inherited.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:27       ` Victor Porton
  2017-09-11 21:49         ` Egil H H
  2017-09-11 22:00         ` Jere
@ 2017-09-11 22:48         ` Shark8
  2017-10-02 23:16         ` Randy Brukardt
  3 siblings, 0 replies; 28+ messages in thread
From: Shark8 @ 2017-09-11 22:48 UTC (permalink / raw)


On Monday, September 11, 2017 at 3:27:54 PM UTC-6, Victor Porton wrote:
>
> package P1 is
> 
    type T1 is new T with private;
  PRIVATE
>   type T1 is new T with null record
>     with Type_Invariant => True;
> 
> end P1;
> 
> 
> $ gnatgcc -gnatc -c p1.ads 
> p1.ads:6:10: aspect "Type_Invariant" only allowed for private type or 
> corresponding full view

The error-message is telling you that "Type_Invariant" is only applicable to private-types, or the full-view of a private-type.


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 22:00           ` Victor Porton
  2017-09-11 22:06             ` Egil H H
@ 2017-09-12  7:30             ` Dmitry A. Kazakov
  1 sibling, 0 replies; 28+ messages in thread
From: Dmitry A. Kazakov @ 2017-09-12  7:30 UTC (permalink / raw)


On 12/09/2017 00:00, Victor Porton wrote:

> It seems that you don't understand me: I need different boolean functions
> for different derived tagged types.

Well, but that is not invariant, at least not formally. The invariant of 
the parent type must hold on the derived type, otherwise the instances 
of the latter would not be substitutable for the former.

In effect this means that you can only strengthen the invariant by 
adding new conjunction elements, if you inherit any in-operation or use 
it in any class-wide in-operations, i.e. basically anywhere.

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 22:02           ` Victor Porton
@ 2017-09-12 18:26             ` Jeffrey R. Carter
  2017-09-12 18:54               ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Jeffrey R. Carter @ 2017-09-12 18:26 UTC (permalink / raw)


On 09/12/2017 12:02 AM, Victor Porton wrote:
> Isn't it a good idea to modify the RM to allow type invariants also for
> derived types with null records?

Not unless you have a real problem that can't be solved otherwise.

-- 
Jeff Carter
"Why don't you bore a hole in yourself and let the sap run out?"
Horse Feathers
49


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 18:26             ` Jeffrey R. Carter
@ 2017-09-12 18:54               ` Victor Porton
  2017-09-12 19:56                 ` Jeffrey R. Carter
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-12 18:54 UTC (permalink / raw)


Jeffrey R. Carter wrote:

> On 09/12/2017 12:02 AM, Victor Porton wrote:
>> Isn't it a good idea to modify the RM to allow type invariants also for
>> derived types with null records?
> 
> Not unless you have a real problem that can't be solved otherwise.

I do have:

A SPARQL query may return boolean, graph, bindings, etc. The return type is 
determined by the text of the query.

I want to make derived types of a query which are validated that their 
return is of a certain type (e.g. a boolean). This certainly useful in a 
language like Ada intended for reliability and maximum runtime check during 
debugging.

I could make them just private extensions instead of null record extensions, 
but after this I would be forced to manually make a derived version of every 
constructor function for the derived type.

It appeared as a real practical problem in my research.

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 18:54               ` Victor Porton
@ 2017-09-12 19:56                 ` Jeffrey R. Carter
  2017-09-12 20:08                   ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Jeffrey R. Carter @ 2017-09-12 19:56 UTC (permalink / raw)


On 09/12/2017 08:54 PM, Victor Porton wrote:
> 
> A SPARQL query may return boolean, graph, bindings, etc. The return type is
> determined by the text of the query.
> 
> I want to make derived types of a query which are validated that their
> return is of a certain type (e.g. a boolean). This certainly useful in a
> language like Ada intended for reliability and maximum runtime check during
> debugging.

"I want to" is not the same as "there is no way to solve the problem in current 
Ada". Ada has a feature that provides exactly what you need. It's called a 
variant record.

-- 
Jeff Carter
"Why don't you bore a hole in yourself and let the sap run out?"
Horse Feathers
49

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 19:56                 ` Jeffrey R. Carter
@ 2017-09-12 20:08                   ` Victor Porton
  2017-09-12 22:34                     ` Shark8
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-12 20:08 UTC (permalink / raw)


Jeffrey R. Carter wrote:

> On 09/12/2017 08:54 PM, Victor Porton wrote:
>> 
>> A SPARQL query may return boolean, graph, bindings, etc. The return type
>> is determined by the text of the query.
>> 
>> I want to make derived types of a query which are validated that their
>> return is of a certain type (e.g. a boolean). This certainly useful in a
>> language like Ada intended for reliability and maximum runtime check
>> during debugging.
> 
> "I want to" is not the same as "there is no way to solve the problem in
> current Ada". Ada has a feature that provides exactly what you need. It's
> called a variant record.

It is a tagged type. AFAIK, a type cannot be both a variant record and 
tagged.

Moreover, the object in consideration is a wrapper over a certain C API. It 
surely cannot be described in variant record terms.

Moreover, bindings may contain more than one row of values which can be 
enumerated like an iterator. I am not sure if this can be expressed in terms 
of a variant record.

The proposed feature increases reliability of programming. It is undoubtful 
that adding more type invariants increases reliability.

-- 
Victor Porton - http://portonvictor.org


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 20:08                   ` Victor Porton
@ 2017-09-12 22:34                     ` Shark8
  2017-09-12 22:59                       ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Shark8 @ 2017-09-12 22:34 UTC (permalink / raw)


On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton wrote:
> Jeffrey R. Carter wrote:
> 
> > 
> > "I want to" is not the same as "there is no way to solve the problem in
> > current Ada". Ada has a feature that provides exactly what you need. It's
> > called a variant record.
> 
> It is a tagged type. AFAIK, a type cannot be both a variant record and 
> tagged.

You certainly can:

    Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
    
    Type Example( Item_Type : Type_Enumeration ) is tagged record
	case Item_Type is
	    when TInteger => I : Integer;
	    when TReal    => R : Float range Float'Range;
	    when TBoolean => B : Boolean;
	    when Nothing  => Null;
	end case;
    end record;
    
> Moreover, the object in consideration is a wrapper over a certain C API. It 
> surely cannot be described in variant record terms.

Sure it can; there's a reason that there's a separation between specification and body, part of which is so you can hide something like an interface to C and present something sensible to your program/clients.

> Moreover, bindings may contain more than one row of values which can be 
> enumerated like an iterator. I am not sure if this can be expressed in terms 
> of a variant record.

Variant records can have discriminants, too. (In fact, discriminants are half of how variant-records do their thing, the other half being the "internal case statement/construct".)

> The proposed feature increases reliability of programming. It is undoubtful 
> that adding more type invariants increases reliability.

I fail to see how you couldn't achieve this by use of (a) variant records, and (b) constrained subtypes.

eg:
  SubType Integer_Example is Example( TInteger );
  Function X(Input : Integer) Return Integer_Example;


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 22:34                     ` Shark8
@ 2017-09-12 22:59                       ` Victor Porton
  2017-09-13  4:21                         ` Jere
  2017-09-14  7:28                         ` Shark8
  0 siblings, 2 replies; 28+ messages in thread
From: Victor Porton @ 2017-09-12 22:59 UTC (permalink / raw)


Shark8 wrote:

> On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton wrote:
>> Jeffrey R. Carter wrote:
>> 
>> > 
>> > "I want to" is not the same as "there is no way to solve the problem in
>> > current Ada". Ada has a feature that provides exactly what you need.
>> > It's called a variant record.
>> 
>> It is a tagged type. AFAIK, a type cannot be both a variant record and
>> tagged.
> 
> You certainly can:
> 
>     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>     
>     Type Example( Item_Type : Type_Enumeration ) is tagged record
> case Item_Type is
> when TInteger => I : Integer;
> when TReal    => R : Float range Float'Range;
> when TBoolean => B : Boolean;
> when Nothing  => Null;
> end case;
>     end record;
>     
>> Moreover, the object in consideration is a wrapper over a certain C API.
>> It surely cannot be described in variant record terms.
> 
> Sure it can; there's a reason that there's a separation between
> specification and body, part of which is so you can hide something like an
> interface to C and present something sensible to your program/clients.

Thanks.

But this seems not to solve my problem:

The base type for Example cannot be defined as a discriminated type for 
certain Type_Enumeration, because it is possible that when creating the 
object it may be yet unknown what the value of the discriminant should have 
(my main problem is to invent somethings if this value is known at object 
creation, but we must support the unknown case too). AFAIK, it is not 
possible to change the discriminant later.

The solution would be to define a discriminated type as its descendant, but 
then all problems which I described in previous messages appear again. So 
this is not a solution.

Hm, we can make Type_Enumeration to contain the value "Any" to allow any 
result type. This is formally a solution, but it is against OO principles 
such as the principle that derived types should be made by object 
inheritance. Wait, it has another more important in practice deficiency: 
Example(Any) would be incompatible with Example(TInteger); this seems not 
acceptable.

And variant records are certainly not applicable here, as I deal with 
(tagged) private types which contain a C pointer only.

>> Moreover, bindings may contain more than one row of values which can be
>> enumerated like an iterator. I am not sure if this can be expressed in
>> terms of a variant record.
> 
> Variant records can have discriminants, too. (In fact, discriminants are
> half of how variant-records do their thing, the other half being the
> "internal case statement/construct".)
> 
>> The proposed feature increases reliability of programming. It is
>> undoubtful that adding more type invariants increases reliability.
> 
> I fail to see how you couldn't achieve this by use of (a) variant records,
> and (b) constrained subtypes.
> 
> eg:
>   SubType Integer_Example is Example( TInteger );
>   Function X(Input : Integer) Return Integer_Example;
-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 22:59                       ` Victor Porton
@ 2017-09-13  4:21                         ` Jere
  2017-09-13  4:28                           ` Jere
  2017-09-14 13:52                           ` Victor Porton
  2017-09-14  7:28                         ` Shark8
  1 sibling, 2 replies; 28+ messages in thread
From: Jere @ 2017-09-13  4:21 UTC (permalink / raw)


On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton wrote:
> Shark8 wrote:
> 
> > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton wrote:
> >> Jeffrey R. Carter wrote:
> >> 
> >> > 
> >> > "I want to" is not the same as "there is no way to solve the problem in
> >> > current Ada". Ada has a feature that provides exactly what you need.
> >> > It's called a variant record.
> >> 
> >> It is a tagged type. AFAIK, a type cannot be both a variant record and
> >> tagged.
> > 
> > You certainly can:
> > 
> >     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
> >     
> >     Type Example( Item_Type : Type_Enumeration ) is tagged record
> > case Item_Type is
> > when TInteger => I : Integer;
> > when TReal    => R : Float range Float'Range;
> > when TBoolean => B : Boolean;
> > when Nothing  => Null;
> > end case;
> >     end record;
> >     
> >> Moreover, the object in consideration is a wrapper over a certain C API.
> >> It surely cannot be described in variant record terms.
> > 
> > Sure it can; there's a reason that there's a separation between
> > specification and body, part of which is so you can hide something like an
> > interface to C and present something sensible to your program/clients.
> 
> Thanks.
> 
> But this seems not to solve my problem:
> 
> The base type for Example cannot be defined as a discriminated type for 
> certain Type_Enumeration, because it is possible that when creating the 
> object it may be yet unknown what the value of the discriminant should have 
> (my main problem is to invent somethings if this value is known at object 
> creation, but we must support the unknown case too). AFAIK, it is not 
> possible to change the discriminant later.
> 

I may be misunderstanding what you are looking for, but you can 
make discriminant types unconstrained to let you choose the type 
at run time:

Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
   
    Type Example( Item_Type : Type_Enumeration := Nothing) is tagged record
        case Item_Type is
            when TInteger => I : Integer;
            when TReal    => R : Float range Float'Range;
            when TBoolean => B : Boolean;
            when Nothing  => Null;
        end case;
    end record; 

Then all you have to do is declare an object with no 
specified discriminant:

 Some_Object : Example;  --notice no discriminant

In Ada, when you do this, you are able to assign new versions 
of the type (with different discriminants:

Some_Integer : Example := (Item_Type => TInteger, I => 100);
Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);

Some_Object := Some_Integer;
Some_Object := Some_Float;

That's just a play example, you can handle building them however 
you want at run time.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-13  4:21                         ` Jere
@ 2017-09-13  4:28                           ` Jere
  2017-09-13  4:34                             ` Jere
  2017-09-14 13:52                           ` Victor Porton
  1 sibling, 1 reply; 28+ messages in thread
From: Jere @ 2017-09-13  4:28 UTC (permalink / raw)


On Wednesday, September 13, 2017 at 12:21:12 AM UTC-4, Jere wrote:
> On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton wrote:
> > Shark8 wrote:
> > 
> > > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton wrote:
> > >> Jeffrey R. Carter wrote:
> > >> 
> > >> > 
> > >> > "I want to" is not the same as "there is no way to solve the problem in
> > >> > current Ada". Ada has a feature that provides exactly what you need.
> > >> > It's called a variant record.
> > >> 
> > >> It is a tagged type. AFAIK, a type cannot be both a variant record and
> > >> tagged.
> > > 
> > > You certainly can:
> > > 
> > >     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
> > >     
> > >     Type Example( Item_Type : Type_Enumeration ) is tagged record
> > > case Item_Type is
> > > when TInteger => I : Integer;
> > > when TReal    => R : Float range Float'Range;
> > > when TBoolean => B : Boolean;
> > > when Nothing  => Null;
> > > end case;
> > >     end record;
> > >     
> > >> Moreover, the object in consideration is a wrapper over a certain C API.
> > >> It surely cannot be described in variant record terms.
> > > 
> > > Sure it can; there's a reason that there's a separation between
> > > specification and body, part of which is so you can hide something like an
> > > interface to C and present something sensible to your program/clients.
> > 
> > Thanks.
> > 
> > But this seems not to solve my problem:
> > 
> > The base type for Example cannot be defined as a discriminated type for 
> > certain Type_Enumeration, because it is possible that when creating the 
> > object it may be yet unknown what the value of the discriminant should have 
> > (my main problem is to invent somethings if this value is known at object 
> > creation, but we must support the unknown case too). AFAIK, it is not 
> > possible to change the discriminant later.
> > 
> 
> I may be misunderstanding what you are looking for, but you can 
> make discriminant types unconstrained to let you choose the type 
> at run time:
> 
> Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>    
>     Type Example( Item_Type : Type_Enumeration := Nothing) is tagged record
>         case Item_Type is
>             when TInteger => I : Integer;
>             when TReal    => R : Float range Float'Range;
>             when TBoolean => B : Boolean;
>             when Nothing  => Null;
>         end case;
>     end record; 
> 
> Then all you have to do is declare an object with no 
> specified discriminant:
> 
>  Some_Object : Example;  --notice no discriminant
> 
> In Ada, when you do this, you are able to assign new versions 
> of the type (with different discriminants:
> 
> Some_Integer : Example := (Item_Type => TInteger, I => 100);
> Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);
> 
> Some_Object := Some_Integer;
> Some_Object := Some_Float;
> 
> That's just a play example, you can handle building them however 
> you want at run time.

Sorry, TFloat should be TReal and F should be R

Also, I didn't realize this, but you can't do the default value with a tagged type unless it is limited so it would need to be untagged:

   Type Example( Item_Type : Type_Enumeration := Nothing) is record
        case Item_Type is
            when TInteger => I : Integer;
            when TReal    => R : Float range Float'Range;
            when TBoolean => B : Boolean;
            when Nothing  => Null;
        end case;
    end record; 

If you are selecting the type via enum, does it still need to be tagged at this point?

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-13  4:28                           ` Jere
@ 2017-09-13  4:34                             ` Jere
  0 siblings, 0 replies; 28+ messages in thread
From: Jere @ 2017-09-13  4:34 UTC (permalink / raw)


On Wednesday, September 13, 2017 at 12:28:10 AM UTC-4, Jere wrote:
> On Wednesday, September 13, 2017 at 12:21:12 AM UTC-4, Jere wrote:
> > On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton wrote:
> > > Shark8 wrote:
> > > 
> > > > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton wrote:
> > > >> Jeffrey R. Carter wrote:
> > > >> 
> > > >> > 
> > > >> > "I want to" is not the same as "there is no way to solve the problem in
> > > >> > current Ada". Ada has a feature that provides exactly what you need.
> > > >> > It's called a variant record.
> > > >> 
> > > >> It is a tagged type. AFAIK, a type cannot be both a variant record and
> > > >> tagged.
> > > > 
> > > > You certainly can:
> > > > <SNIPPED>
> > > 
> > > Thanks.
> > > 
> > > But this seems not to solve my problem:
> > > <SNIPPED>
> > 
> > I may be misunderstanding what you are looking for, but you can 
> > make discriminant types unconstrained to let you choose the type 
> > at run time:
> > 
> > Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
> >    
> >     Type Example( Item_Type : Type_Enumeration := Nothing) is tagged record
> >         case Item_Type is
> >             when TInteger => I : Integer;
> >             when TReal    => R : Float range Float'Range;
> >             when TBoolean => B : Boolean;
> >             when Nothing  => Null;
> >         end case;
> >     end record; 
> > 
> > Then all you have to do is declare an object with no 
> > specified discriminant:
> > 
> >  Some_Object : Example;  --notice no discriminant
> > 
> > In Ada, when you do this, you are able to assign new versions 
> > of the type (with different discriminants:
> > 
> > Some_Integer : Example := (Item_Type => TInteger, I => 100);
> > Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);
> > 
> > Some_Object := Some_Integer;
> > Some_Object := Some_Float;
> > 
> > That's just a play example, you can handle building them however 
> > you want at run time.
> 
> Sorry, TFloat should be TReal and F should be R
> 
> Also, I didn't realize this, but you can't do the default value with a tagged type unless it is limited so it would need to be untagged:
> 
>    Type Example( Item_Type : Type_Enumeration := Nothing) is record
>         case Item_Type is
>             when TInteger => I : Integer;
>             when TReal    => R : Float range Float'Range;
>             when TBoolean => B : Boolean;
>             when Nothing  => Null;
>         end case;
>     end record; 
> 
> If you are selecting the type via enum, does it still need to be tagged at this point?

If you do need it tagged, you can also wrap the non tagged record in a tagged record:

   type Wrapper is tagged record
      Placeholder : Example;  -- notice no discriminant
   end record;
   
   Some_Object : Wrapper;


   Some_Integer : Wrapper := (Placeholder => (Item_Type => TInteger, I => 100));
   Some_Float   : Wrapper := (Placeholder => (Item_Type => TReal,    R => 20.2)); 

and then later:

   Some_Object := Some_Integer;
   Some_Object := Some_Float; 


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-12 22:59                       ` Victor Porton
  2017-09-13  4:21                         ` Jere
@ 2017-09-14  7:28                         ` Shark8
  2017-09-14 13:56                           ` Victor Porton
  1 sibling, 1 reply; 28+ messages in thread
From: Shark8 @ 2017-09-14  7:28 UTC (permalink / raw)


On Tuesday, September 12, 2017 at 4:59:17 PM UTC-6, Victor Porton wrote:
> 
> Thanks.
> 
> But this seems not to solve my problem:
> 
> The base type for Example cannot be defined as a discriminated type for 
> certain Type_Enumeration, because it is possible that when creating the 
> object it may be yet unknown what the value of the discriminant should have 
> (my main problem is to invent somethings if this value is known at object 
> creation, but we must support the unknown case too). AFAIK, it is not 
> possible to change the discriminant later.

What are you doing that you need to create an object w/o knowing the types? I've used the variant-record approach in several interpreters to excellent effect; I've also used tagged-type hierarchies, too.

Perhaps what would be more called for in your design is an abstract base type with a discriminant, then having the child-types use the proper value and using Base'Class variables/returns as needed:

  Type Base( Item_Type : Type_Enumeration ) is abstract tagged null record;
  Type Integer is new Base( TInteger ) with null record;
  Type Boolean is new Base( TBoolean ) with null record;
  --...

> 
> The solution would be to define a discriminated type as its descendant, but 
> then all problems which I described in previous messages appear again. So 
> this is not a solution.
> 

I think you're tripping yourself up by overcomplicating / underelaborating on the design. Clear your mind, pull put a piece of paper, and in pen [so you can't erase] write a description of the system being careful to keep it consistent -- I find it very helpful nailing down a design. (In my experience how you're presenting things is how I feel when I haven't solidified a good design yet, and so things keep swirling out of control... kind of the infinite-loop version of "analysis paralysis".)

> Hm, we can make Type_Enumeration to contain the value "Any" to allow any 
> result type. This is formally a solution, but it is against OO principles 
> such as the principle that derived types should be made by object 
> inheritance. Wait, it has another more important in practice deficiency: 
> Example(Any) would be incompatible with Example(TInteger); this seems not 
> acceptable.

Again, see the above.

> And variant records are certainly not applicable here, as I deal with 
> (tagged) private types which contain a C pointer only.

That actually might be all the more reason to use them: C-pointers are notorious for being unsafe WRT type-safety... and a variant-record could certainly be used to isolate them and ensure that they are only used in the places they ought.

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-13  4:21                         ` Jere
  2017-09-13  4:28                           ` Jere
@ 2017-09-14 13:52                           ` Victor Porton
  2017-09-15  0:48                             ` Jere
  1 sibling, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-14 13:52 UTC (permalink / raw)


Jere wrote:

> On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton wrote:
>> Shark8 wrote:
>> 
>> > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton
>> > wrote:
>> >> Jeffrey R. Carter wrote:
>> >> 
>> >> > 
>> >> > "I want to" is not the same as "there is no way to solve the problem
>> >> > in current Ada". Ada has a feature that provides exactly what you
>> >> > need. It's called a variant record.
>> >> 
>> >> It is a tagged type. AFAIK, a type cannot be both a variant record and
>> >> tagged.
>> > 
>> > You certainly can:
>> > 
>> >     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>> >     
>> >     Type Example( Item_Type : Type_Enumeration ) is tagged record
>> > case Item_Type is
>> > when TInteger => I : Integer;
>> > when TReal    => R : Float range Float'Range;
>> > when TBoolean => B : Boolean;
>> > when Nothing  => Null;
>> > end case;
>> >     end record;
>> >     
>> >> Moreover, the object in consideration is a wrapper over a certain C
>> >> API. It surely cannot be described in variant record terms.
>> > 
>> > Sure it can; there's a reason that there's a separation between
>> > specification and body, part of which is so you can hide something like
>> > an interface to C and present something sensible to your
>> > program/clients.
>> 
>> Thanks.
>> 
>> But this seems not to solve my problem:
>> 
>> The base type for Example cannot be defined as a discriminated type for
>> certain Type_Enumeration, because it is possible that when creating the
>> object it may be yet unknown what the value of the discriminant should
>> have (my main problem is to invent somethings if this value is known at
>> object creation, but we must support the unknown case too). AFAIK, it is
>> not possible to change the discriminant later.
>> 
> 
> I may be misunderstanding what you are looking for, but you can
> make discriminant types unconstrained to let you choose the type
> at run time:
> 
> Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>    
>     Type Example( Item_Type : Type_Enumeration := Nothing) is tagged
>     record
>         case Item_Type is
>             when TInteger => I : Integer;
>             when TReal    => R : Float range Float'Range;
>             when TBoolean => B : Boolean;
>             when Nothing  => Null;
>         end case;
>     end record;
> 
> Then all you have to do is declare an object with no
> specified discriminant:
> 
>  Some_Object : Example;  --notice no discriminant
> 
> In Ada, when you do this, you are able to assign new versions
> of the type (with different discriminants:
> 
> Some_Integer : Example := (Item_Type => TInteger, I => 100);
> Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);
> 
> Some_Object := Some_Integer;
> Some_Object := Some_Float;
> 
> That's just a play example, you can handle building them however
> you want at run time.

It does not suffice for me, because at the point of actual object creation, 
the discriminant value may be yet unknown. Sometimes, I need first create 
the object and LATER (when the object was already created and I did some 
operations with it) assign it the type.

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-14  7:28                         ` Shark8
@ 2017-09-14 13:56                           ` Victor Porton
  2017-09-14 13:58                             ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Victor Porton @ 2017-09-14 13:56 UTC (permalink / raw)


Shark8 wrote:

> On Tuesday, September 12, 2017 at 4:59:17 PM UTC-6, Victor Porton wrote:
>> 
>> Thanks.
>> 
>> But this seems not to solve my problem:
>> 
>> The base type for Example cannot be defined as a discriminated type for
>> certain Type_Enumeration, because it is possible that when creating the
>> object it may be yet unknown what the value of the discriminant should
>> have (my main problem is to invent somethings if this value is known at
>> object creation, but we must support the unknown case too). AFAIK, it is
>> not possible to change the discriminant later.
> 
> What are you doing that you need to create an object w/o knowing the
> types? I've used the variant-record approach in several interpreters to
> excellent effect; I've also used tagged-type hierarchies, too.

Consider an interactive user interface.

The user enters the query command.

After this I create the object (at this point its "kind" is not yet known). 
After this I parse the query with the object. At this point I can determine 
the kind of the object (which depends on the query text), but at this point 
the object already exists, so that I cannot assign the discriminant.

-- 
Victor Porton - http://portonvictor.org

^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-14 13:56                           ` Victor Porton
@ 2017-09-14 13:58                             ` Victor Porton
  0 siblings, 0 replies; 28+ messages in thread
From: Victor Porton @ 2017-09-14 13:58 UTC (permalink / raw)


Victor Porton wrote:

> Shark8 wrote:
> 
>> On Tuesday, September 12, 2017 at 4:59:17 PM UTC-6, Victor Porton wrote:
>>> 
>>> Thanks.
>>> 
>>> But this seems not to solve my problem:
>>> 
>>> The base type for Example cannot be defined as a discriminated type for
>>> certain Type_Enumeration, because it is possible that when creating the
>>> object it may be yet unknown what the value of the discriminant should
>>> have (my main problem is to invent somethings if this value is known at
>>> object creation, but we must support the unknown case too). AFAIK, it is
>>> not possible to change the discriminant later.
>> 
>> What are you doing that you need to create an object w/o knowing the
>> types? I've used the variant-record approach in several interpreters to
>> excellent effect; I've also used tagged-type hierarchies, too.
> 
> Consider an interactive user interface.
> 
> The user enters the query command.
> 
> After this I create the object (at this point its "kind" is not yet
> known). After this I parse the query with the object. At this point I can
> determine the kind of the object (which depends on the query text), but at
> this point the object already exists, so that I cannot assign the
> discriminant.

On the other hand, when it is done programmatically without a user 
intervention, the kind of object is usually known at the point of object 
creation. In this case I could use the discriminant approach. But this 
breaks the above case with a query entered interactively by a user.

-- 
Victor Porton - http://portonvictor.org


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-14 13:52                           ` Victor Porton
@ 2017-09-15  0:48                             ` Jere
  2017-09-16 14:22                               ` Victor Porton
  0 siblings, 1 reply; 28+ messages in thread
From: Jere @ 2017-09-15  0:48 UTC (permalink / raw)


On Thursday, September 14, 2017 at 9:52:58 AM UTC-4, Victor Porton wrote:
> Jere wrote:
> 
> > On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton wrote:
> >> Shark8 wrote:
> >> 
> >> > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton
> >> > wrote:
> >> >> Jeffrey R. Carter wrote:
> >> >> 
> >> >> > 
> >> >> > "I want to" is not the same as "there is no way to solve the problem
> >> >> > in current Ada". Ada has a feature that provides exactly what you
> >> >> > need. It's called a variant record.
> >> >> 
> >> >> It is a tagged type. AFAIK, a type cannot be both a variant record and
> >> >> tagged.
> >> > 
> >> > You certainly can:
> >> > 
> >> >     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
> >> >     
> >> >     Type Example( Item_Type : Type_Enumeration ) is tagged record
> >> > case Item_Type is
> >> > when TInteger => I : Integer;
> >> > when TReal    => R : Float range Float'Range;
> >> > when TBoolean => B : Boolean;
> >> > when Nothing  => Null;
> >> > end case;
> >> >     end record;
> >> >     
> >> >> Moreover, the object in consideration is a wrapper over a certain C
> >> >> API. It surely cannot be described in variant record terms.
> >> > 
> >> > Sure it can; there's a reason that there's a separation between
> >> > specification and body, part of which is so you can hide something like
> >> > an interface to C and present something sensible to your
> >> > program/clients.
> >> 
> >> Thanks.
> >> 
> >> But this seems not to solve my problem:
> >> 
> >> The base type for Example cannot be defined as a discriminated type for
> >> certain Type_Enumeration, because it is possible that when creating the
> >> object it may be yet unknown what the value of the discriminant should
> >> have (my main problem is to invent somethings if this value is known at
> >> object creation, but we must support the unknown case too). AFAIK, it is
> >> not possible to change the discriminant later.
> >> 
> > 
> > I may be misunderstanding what you are looking for, but you can
> > make discriminant types unconstrained to let you choose the type
> > at run time:
> > 
> > Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
> >    
> >     Type Example( Item_Type : Type_Enumeration := Nothing) is tagged
> >     record
> >         case Item_Type is
> >             when TInteger => I : Integer;
> >             when TReal    => R : Float range Float'Range;
> >             when TBoolean => B : Boolean;
> >             when Nothing  => Null;
> >         end case;
> >     end record;
> > 
> > Then all you have to do is declare an object with no
> > specified discriminant:
> > 
> >  Some_Object : Example;  --notice no discriminant
> > 
> > In Ada, when you do this, you are able to assign new versions
> > of the type (with different discriminants:
> > 
> > Some_Integer : Example := (Item_Type => TInteger, I => 100);
> > Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);
> > 
> > Some_Object := Some_Integer;
> > Some_Object := Some_Float;
> > 
> > That's just a play example, you can handle building them however
> > you want at run time.
> 
> It does not suffice for me, because at the point of actual object creation, 
> the discriminant value may be yet unknown. Sometimes, I need first create 
> the object and LATER (when the object was already created and I did some 
> operations with it) assign it the type.
> 
> -- 
> Victor Porton - http://portonvictor.org

But that is what this does.  You declare your object:

Some_Object : Example;  --notice no discriminant

Here no discriminant is provided, so it is unconstrained.

Sometime later (a minute from now, a 100 days from now, etc.) you 
get some user input that tells you what type you want (we'll 
say an integer for example, but any type you have defined can be 
used), you can then simply do:

declare
   Some_Integer : Example := (Item_Type => TInteger, I => User_Input);
begin
   Some_Object := Some_Integer;
end;

-- You might even be able to simply do it without a declare block:  
--  Some_Object := (Item_Type => TInteger, I => User_Input);
-- I just haven't tried that out.

and now you have a runtime selected version.  You can replace that 
Some_Integer with Some_Real or any other version you want.  You 
don't have to know the type at compile time because the type 
Example is unconstrained.

You can have a discriminated type that is unconstrained so you can
change it freely at runtime.  Since the default value of the 
discriminant is "Nothing", it handles the object while we are
waiting for input and are basically in an unknown state.  You
can rename Nothing to Unknown if it helps for readability.

Does that sound better?


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-15  0:48                             ` Jere
@ 2017-09-16 14:22                               ` Victor Porton
  0 siblings, 0 replies; 28+ messages in thread
From: Victor Porton @ 2017-09-16 14:22 UTC (permalink / raw)


Jere wrote:

> On Thursday, September 14, 2017 at 9:52:58 AM UTC-4, Victor Porton wrote:
>> Jere wrote:
>> 
>> > On Tuesday, September 12, 2017 at 6:59:17 PM UTC-4, Victor Porton
>> > wrote:
>> >> Shark8 wrote:
>> >> 
>> >> > On Tuesday, September 12, 2017 at 2:09:08 PM UTC-6, Victor Porton
>> >> > wrote:
>> >> >> Jeffrey R. Carter wrote:
>> >> >> 
>> >> >> > 
>> >> >> > "I want to" is not the same as "there is no way to solve the
>> >> >> > problem in current Ada". Ada has a feature that provides exactly
>> >> >> > what you need. It's called a variant record.
>> >> >> 
>> >> >> It is a tagged type. AFAIK, a type cannot be both a variant record
>> >> >> and tagged.
>> >> > 
>> >> > You certainly can:
>> >> > 
>> >> >     Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>> >> >     
>> >> >     Type Example( Item_Type : Type_Enumeration ) is tagged record
>> >> > case Item_Type is
>> >> > when TInteger => I : Integer;
>> >> > when TReal    => R : Float range Float'Range;
>> >> > when TBoolean => B : Boolean;
>> >> > when Nothing  => Null;
>> >> > end case;
>> >> >     end record;
>> >> >     
>> >> >> Moreover, the object in consideration is a wrapper over a certain C
>> >> >> API. It surely cannot be described in variant record terms.
>> >> > 
>> >> > Sure it can; there's a reason that there's a separation between
>> >> > specification and body, part of which is so you can hide something
>> >> > like an interface to C and present something sensible to your
>> >> > program/clients.
>> >> 
>> >> Thanks.
>> >> 
>> >> But this seems not to solve my problem:
>> >> 
>> >> The base type for Example cannot be defined as a discriminated type
>> >> for certain Type_Enumeration, because it is possible that when
>> >> creating the object it may be yet unknown what the value of the
>> >> discriminant should have (my main problem is to invent somethings if
>> >> this value is known at object creation, but we must support the
>> >> unknown case too). AFAIK, it is not possible to change the
>> >> discriminant later.
>> >> 
>> > 
>> > I may be misunderstanding what you are looking for, but you can
>> > make discriminant types unconstrained to let you choose the type
>> > at run time:
>> > 
>> > Type Type_Enumeration is ( TInteger, TReal, TBoolean, Nothing );
>> >    
>> >     Type Example( Item_Type : Type_Enumeration := Nothing) is tagged
>> >     record
>> >         case Item_Type is
>> >             when TInteger => I : Integer;
>> >             when TReal    => R : Float range Float'Range;
>> >             when TBoolean => B : Boolean;
>> >             when Nothing  => Null;
>> >         end case;
>> >     end record;
>> > 
>> > Then all you have to do is declare an object with no
>> > specified discriminant:
>> > 
>> >  Some_Object : Example;  --notice no discriminant
>> > 
>> > In Ada, when you do this, you are able to assign new versions
>> > of the type (with different discriminants:
>> > 
>> > Some_Integer : Example := (Item_Type => TInteger, I => 100);
>> > Some_Float   : Example := (Item_Type => TFloat,   F => 20.2);
>> > 
>> > Some_Object := Some_Integer;
>> > Some_Object := Some_Float;
>> > 
>> > That's just a play example, you can handle building them however
>> > you want at run time.
>> 
>> It does not suffice for me, because at the point of actual object
>> creation, the discriminant value may be yet unknown. Sometimes, I need
>> first create the object and LATER (when the object was already created
>> and I did some operations with it) assign it the type.
>> 
>> --
>> Victor Porton - http://portonvictor.org
> 
> But that is what this does.  You declare your object:
> 
> Some_Object : Example;  --notice no discriminant
> 
> Here no discriminant is provided, so it is unconstrained.
> 
> Sometime later (a minute from now, a 100 days from now, etc.) you
> get some user input that tells you what type you want (we'll
> say an integer for example, but any type you have defined can be
> used), you can then simply do:
> 
> declare
>    Some_Integer : Example := (Item_Type => TInteger, I => User_Input);
> begin
>    Some_Object := Some_Integer;
> end;

It is not what I need: If we use discriminants your way, I need to create 
some fields of the object before assignment of the discriminant.

This is not possible in Ada: I can assign to object fields only after the 
discriminant is known.

> -- You might even be able to simply do it without a declare block:
> --  Some_Object := (Item_Type => TInteger, I => User_Input);
> -- I just haven't tried that out.
> 
> and now you have a runtime selected version.  You can replace that
> Some_Integer with Some_Real or any other version you want.  You
> don't have to know the type at compile time because the type
> Example is unconstrained.
> 
> You can have a discriminated type that is unconstrained so you can
> change it freely at runtime.  Since the default value of the
> discriminant is "Nothing", it handles the object while we are
> waiting for input and are basically in an unknown state.  You
> can rename Nothing to Unknown if it helps for readability.

I already pointed that Example(TBoolean) is incompatible with 
Example(Nothing) (we can't assign a Example(TBoolean) object to an 
Example(Nothing) variable). That's not acceptable, too.

> Does that sound better?

-- 
Victor Porton - http://portonvictor.org


^ permalink raw reply	[flat|nested] 28+ messages in thread

* Re: Type invariants and private extensions?
  2017-09-11 21:27       ` Victor Porton
                           ` (2 preceding siblings ...)
  2017-09-11 22:48         ` Shark8
@ 2017-10-02 23:16         ` Randy Brukardt
  3 siblings, 0 replies; 28+ messages in thread
From: Randy Brukardt @ 2017-10-02 23:16 UTC (permalink / raw)


"Victor Porton" <porton@narod.ru> wrote in message 
news:op6v4m$tmm$1@gioia.aioe.org...
> Egil H H wrote:
>
>> On Monday, September 11, 2017 at 10:48:46 PM UTC+2, Victor Porton wrote:
>>> > The Invariant will then be inherited by all derived types
>>>
>>> It is not what I want. I want different invariants for different derived
>>> types.
>>>
>>
>> You can add new invariants in addition to the ones inherited
>
> I cannot: the compiler gives an error:
>
> package P is
>
>  type T is tagged private;
>
> private
>
>  type T is tagged null record;
>
> end P;
>
> with P; use P;
>
> package P1 is
>
>  type T1 is new T with null record
>    with Type_Invariant => True;
>
> end P1;

Right, but you can define a private extension:

package P1 is

    type T1 is new T with private;

private

    type T1 is new T with null record
       with Type_Invariant => True;

 end P1;

The semantics is the same as with a plain record extension, and the 
invariant makes more sense.

                                      Randy.



^ permalink raw reply	[flat|nested] 28+ messages in thread

end of thread, other threads:[~2017-10-02 23:16 UTC | newest]

Thread overview: 28+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-09-11 19:51 Type invariants and private extensions? Victor Porton
2017-09-11 20:00 ` Egil H H
2017-09-11 20:48   ` Victor Porton
2017-09-11 21:19     ` Egil H H
2017-09-11 21:27       ` Victor Porton
2017-09-11 21:49         ` Egil H H
2017-09-11 22:00           ` Victor Porton
2017-09-11 22:06             ` Egil H H
2017-09-12  7:30             ` Dmitry A. Kazakov
2017-09-11 22:00         ` Jere
2017-09-11 22:02           ` Victor Porton
2017-09-12 18:26             ` Jeffrey R. Carter
2017-09-12 18:54               ` Victor Porton
2017-09-12 19:56                 ` Jeffrey R. Carter
2017-09-12 20:08                   ` Victor Porton
2017-09-12 22:34                     ` Shark8
2017-09-12 22:59                       ` Victor Porton
2017-09-13  4:21                         ` Jere
2017-09-13  4:28                           ` Jere
2017-09-13  4:34                             ` Jere
2017-09-14 13:52                           ` Victor Porton
2017-09-15  0:48                             ` Jere
2017-09-16 14:22                               ` Victor Porton
2017-09-14  7:28                         ` Shark8
2017-09-14 13:56                           ` Victor Porton
2017-09-14 13:58                             ` Victor Porton
2017-09-11 22:48         ` Shark8
2017-10-02 23:16         ` Randy Brukardt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox