comp.lang.ada
 help / color / mirror / Atom feed
* Unknown constraints and type composition
@ 2018-06-14 15:37 Alejandro R. Mosteo
  2018-06-14 16:19 ` Dmitry A. Kazakov
                   ` (4 more replies)
  0 siblings, 5 replies; 9+ messages in thread
From: Alejandro R. Mosteo @ 2018-06-14 15:37 UTC (permalink / raw)


I think I have read somewhere that types with unknown constraints are a 
good way of ensuring you (or your users) don't end with uninitialized values:

types Whatever (<>) is [limited] private;

function Create return Whatever;

This seems nice at first sight but when these types have any likelihood 
of ending as members of another type you will hit the "unconstrained 
member" problem.

A workaround then is to use a Indefinite_Holder, but that's an imposition 
on your clients (ugly). If your type is furthermore limited, then you 
must use pointers and consider providing controlledness and deallocation 
in the enclosing type (uglier).

Right now I'm on the point of a new design where I have many interrelated 
types that require initialization calls (it's a C binding). And, as 
always, I'm unsure of the way to go, or if I'm missing another technique 
without shortcomings. Your thoughts if you have any on this issue are 
much appreciated.

Alex.

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

* Re: Unknown constraints and type composition
  2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
@ 2018-06-14 16:19 ` Dmitry A. Kazakov
  2018-06-14 16:58 ` sbelmont700
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: Dmitry A. Kazakov @ 2018-06-14 16:19 UTC (permalink / raw)


On 2018-06-14 17:37, Alejandro R. Mosteo wrote:
> I think I have read somewhere that types with unknown constraints are a 
> good way of ensuring you (or your users) don't end with uninitialized 
> values:
> 
> types Whatever (<>) is [limited] private;
> 
> function Create return Whatever;
> 
> This seems nice at first sight but when these types have any likelihood 
> of ending as members of another type you will hit the "unconstrained 
> member" problem.

As well as problems with publicly derived types.

> A workaround then is to use a Indefinite_Holder, but that's an 
> imposition on your clients (ugly). If your type is furthermore limited, 
> then you must use pointers and consider providing controlledness and 
> deallocation in the enclosing type (uglier).
> 
> Right now I'm on the point of a new design where I have many 
> interrelated types that require initialization calls (it's a C binding). 
> And, as always, I'm unsure of the way to go, or if I'm missing another 
> technique without shortcomings. Your thoughts if you have any on this 
> issue are much appreciated.

Without constructors there is no solution to the problem.

In large projects instead of holder I use a reference-counted controlled 
handle. The target's type declaration goes into private packages. The 
handles go to the public interface packages. It is tedious [*], but it 
the only working method if you want to enforce construction and hide 
implementation.

-----------------------
* Because of parallel types hierarchy, lack of delegation support, lack 
of interface inheritance.

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


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

* Re: Unknown constraints and type composition
  2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
  2018-06-14 16:19 ` Dmitry A. Kazakov
@ 2018-06-14 16:58 ` sbelmont700
  2018-06-14 17:53 ` Jeffrey R. Carter
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 9+ messages in thread
From: sbelmont700 @ 2018-06-14 16:58 UTC (permalink / raw)


One approach would be to use coextensions, assuming you are aware of all that entails, e.g.:

type Inner (<>) is private;
function Create_Inner return Inner;

...

type Outer (<>) is private;
function Create_Outer return Outer;

private
type Outer (x : access Inner) is null record;

function Create_Outer return Outer is
begin
  return Outer (x => new Inner'(Create_Inner));
end Create;


And, assuming the compiler follows the advice (and is bug free :/ ) everything should work itself out safely and neatly.  Though a portable way to do this would be nice.

-sb




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

* Re: Unknown constraints and type composition
  2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
  2018-06-14 16:19 ` Dmitry A. Kazakov
  2018-06-14 16:58 ` sbelmont700
@ 2018-06-14 17:53 ` Jeffrey R. Carter
  2018-06-15  5:13   ` J-P. Rosen
  2018-06-14 21:28 ` Randy Brukardt
  2018-06-15  9:37 ` Alejandro R. Mosteo
  4 siblings, 1 reply; 9+ messages in thread
From: Jeffrey R. Carter @ 2018-06-14 17:53 UTC (permalink / raw)


On 06/14/2018 05:37 PM, Alejandro R. Mosteo wrote:
> I think I have read somewhere that types with unknown constraints are a good way 
> of ensuring you (or your users) don't end with uninitialized values:
> 
> types Whatever (<>) is [limited] private;
> 
> function Create return Whatever;

It's one way. There are others that might be better. Unknown discriminants are 
more for generic formal types, to show that the generic accepts indefinite 
actual types.

One way to deal with this is to make the full type a record with reasonable 
defaults for all the components. This works for all versions of the language.

Another is to make the type a descendant of [Limited_}Controlled and override 
Initialize. This works for Ada 95 and later.

Another way is to have

function Initialized (Thing : Whatever) return Boolean;

that returns True if its parameter has been initialized. Have a 
Dynamic_Predicate on Whatever that Initialized returns True. Have a 
postcondition on your New_Whatever function that its return value is 
Initialized. Make the full type a record with an Initialized component default 
initialized to False. This only works for Ada 12.

Another is to leave off the predicate, and instead give all operations on the 
type the precondition that the value is Initialized. This only works for Ada 12, 
but it can be emulated in any version of Ada with manual checks of the precondition.

> This seems nice at first sight but when these types have any likelihood of 
> ending as members of another type you will hit the "unconstrained member" problem.

After having made an effort to make the type indefinite, you should not be 
surprised that it's an indefinite type.

Part of design is to try to anticipate all reasonable uses for a type, and 
choose an approach that works for them all. If this is a reasonable use of the 
type, then unknown discriminants is not a suitable approach.

-- 
Jeff Carter
"When Roman engineers built a bridge, they had to stand under it
while the first legion marched across. If programmers today
worked under similar ground rules, they might well find
themselves getting much more interested in Ada!"
Robert Dewar
62

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

* Re: Unknown constraints and type composition
  2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
                   ` (2 preceding siblings ...)
  2018-06-14 17:53 ` Jeffrey R. Carter
@ 2018-06-14 21:28 ` Randy Brukardt
  2018-06-15  9:37 ` Alejandro R. Mosteo
  4 siblings, 0 replies; 9+ messages in thread
From: Randy Brukardt @ 2018-06-14 21:28 UTC (permalink / raw)


"Alejandro R. Mosteo" <alejandro@mosteo.com> wrote in message 
news:pfu23n$csb$1@dont-email.me...
...
> Right now I'm on the point of a new design where I have many interrelated 
> types that require initialization calls (it's a C binding). And, as 
> always, I'm unsure of the way to go, or if I'm missing another technique 
> without shortcomings. Your thoughts if you have any on this issue are much 
> appreciated.

If there was a technique without shortcomings, we wouldn't need any other 
options!!

The other option, of course, is to ensure that the default initialized 
object is "meaningful" in some sense. Most of my objects default initialize 
to a state that causes most operations on them to raise an exception 
("Not_Valid_Error" in Claw). I don't think it is reasonable to try to make 
objects valid 100% of the time, that forces all of your operations into the 
straitjacket of Ada scoping.

That of course has the downside of making the checks dynamic. In the case of 
Claw, there's no choice anyway (a Window object can disappear due to an 
action that comes from the program's user [clicking on the close button], 
not the program's code, so nothing really can be determined statically). I 
suspect that is somewhat true of most real systems.

                                    Randy.



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

* Re: Unknown constraints and type composition
  2018-06-14 17:53 ` Jeffrey R. Carter
@ 2018-06-15  5:13   ` J-P. Rosen
  2018-06-15  9:34     ` Alejandro R. Mosteo
  2018-07-08 13:53     ` Jacob Sparre Andersen
  0 siblings, 2 replies; 9+ messages in thread
From: J-P. Rosen @ 2018-06-15  5:13 UTC (permalink / raw)


Le 14/06/2018 à 19:53, Jeffrey R. Carter a écrit :
> On 06/14/2018 05:37 PM, Alejandro R. Mosteo wrote:
>> I think I have read somewhere that types with unknown constraints are
>> a good way of ensuring you (or your users) don't end with
>> uninitialized values:
>>
>> types Whatever (<>) is [limited] private;
>>
>> function Create return Whatever;
> 
> It's one way. There are others that might be better. Unknown
> discriminants are more for generic formal types, to show that the
> generic accepts indefinite actual types.
> 
> One way to deal with this is to make the full type a record with
> reasonable defaults for all the components. This works for all versions
> of the language.
> 
Even better, the default can be a raise expression (or a function that
raises an exception for pre-2012), so no uninitialized object can be
created. This is a run-time check, but a decent compiler would warn you
at compile time.

-- 
J-P. Rosen
Adalog
2 rue du Docteur Lombard, 92441 Issy-les-Moulineaux CEDEX
Tel: +33 1 45 29 21 52, Fax: +33 1 45 29 25 00
http://www.adalog.fr

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

* Re: Unknown constraints and type composition
  2018-06-15  5:13   ` J-P. Rosen
@ 2018-06-15  9:34     ` Alejandro R. Mosteo
  2018-07-08 13:53     ` Jacob Sparre Andersen
  1 sibling, 0 replies; 9+ messages in thread
From: Alejandro R. Mosteo @ 2018-06-15  9:34 UTC (permalink / raw)


On 15/06/2018 07:13, J-P. Rosen wrote:
> Le 14/06/2018 à 19:53, Jeffrey R. Carter a écrit :
>> On 06/14/2018 05:37 PM, Alejandro R. Mosteo wrote:
>>> I think I have read somewhere that types with unknown constraints are
>>> a good way of ensuring you (or your users) don't end with
>>> uninitialized values:
>>>
>>> types Whatever (<>) is [limited] private;
>>>
>>> function Create return Whatever;
>>
>> It's one way. There are others that might be better. Unknown
>> discriminants are more for generic formal types, to show that the
>> generic accepts indefinite actual types.
>>
>> One way to deal with this is to make the full type a record with
>> reasonable defaults for all the components. This works for all versions
>> of the language.
>>
> Even better, the default can be a raise expression (or a function that
> raises an exception for pre-2012), so no uninitialized object can be
> created. This is a run-time check, but a decent compiler would warn you
> at compile time.

Interesting. So you can have the definite type, but you're forced to 
provide a initialization, and are warned about it. Seems one trick to 
remember, thanks!


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

* Re: Unknown constraints and type composition
  2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
                   ` (3 preceding siblings ...)
  2018-06-14 21:28 ` Randy Brukardt
@ 2018-06-15  9:37 ` Alejandro R. Mosteo
  4 siblings, 0 replies; 9+ messages in thread
From: Alejandro R. Mosteo @ 2018-06-15  9:37 UTC (permalink / raw)


On 14/06/2018 17:37, Alejandro R. Mosteo wrote:

Thanks everyone for your comments. I think every approach was different 
and had some good food for thought. It seems things where more or less as 
I figured but seeing how different people goes about it reassures me.

Alex.

> I think I have read somewhere that types with unknown constraints are a 
> good way of ensuring you (or your users) don't end with uninitialized 
> values:
> 
> types Whatever (<>) is [limited] private;
> 
> function Create return Whatever;
> 
> This seems nice at first sight but when these types have any likelihood 
> of ending as members of another type you will hit the "unconstrained 
> member" problem.
> 
> A workaround then is to use a Indefinite_Holder, but that's an imposition 
> on your clients (ugly). If your type is furthermore limited, then you 
> must use pointers and consider providing controlledness and deallocation 
> in the enclosing type (uglier).
> 
> Right now I'm on the point of a new design where I have many interrelated 
> types that require initialization calls (it's a C binding). And, as 
> always, I'm unsure of the way to go, or if I'm missing another technique 
> without shortcomings. Your thoughts if you have any on this issue are 
> much appreciated.
> 
> Alex.

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

* Re: Unknown constraints and type composition
  2018-06-15  5:13   ` J-P. Rosen
  2018-06-15  9:34     ` Alejandro R. Mosteo
@ 2018-07-08 13:53     ` Jacob Sparre Andersen
  1 sibling, 0 replies; 9+ messages in thread
From: Jacob Sparre Andersen @ 2018-07-08 13:53 UTC (permalink / raw)


J-P. Rosen wrote:

> Even better, the default can be a raise expression (or a function that
> raises an exception for pre-2012), so no uninitialized object can be
> created. This is a run-time check, but a decent compiler would warn
> you at compile time.

This does not give a warning at compile time with FSF GNAT 8
(Debian/sid), nor with GNAT CE 2018, but you get the correct run-time
error with both compilers:

   private with Ada.Strings.Unbounded;
   
   package Initialisation_Required is
   
      type Instance is private;
   
      function Create (Name : in String) return Instance;
   
   private
   
      type Instance is
         record
            Name : Ada.Strings.Unbounded.Unbounded_String := raise Constraint_Error with "Uninitialised object.";
         end record;
   
   end Initialisation_Required;

   package body Initialisation_Required is
   
      function Create (Name : in String) return Instance is
      begin
         return R : Instance do
            R.Name := Ada.Strings.Unbounded.To_Unbounded_String (Name);
         end return;
      end Create;
   
   end Initialisation_Required;

   with Initialisation_Required;
   
   procedure Demo is
      O : Initialisation_Required.Instance := Initialisation_Required.Create (Name => "Hello");
   begin
      O := Initialisation_Required.Create (Name => "Hello");
   end Demo;

Another problem with this is that you can't wait until you leave your
internal constructor function, before the initialisation has to happen.

With the example above, you get your exception already at "return R :
Instance do", which isn't what we want.  (Easy to work around, but
something you should be aware of.)

Greetings,

Jacob
-- 
"Sleep is just a cheap substitute for coffee"

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

end of thread, other threads:[~2018-07-08 13:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-14 15:37 Unknown constraints and type composition Alejandro R. Mosteo
2018-06-14 16:19 ` Dmitry A. Kazakov
2018-06-14 16:58 ` sbelmont700
2018-06-14 17:53 ` Jeffrey R. Carter
2018-06-15  5:13   ` J-P. Rosen
2018-06-15  9:34     ` Alejandro R. Mosteo
2018-07-08 13:53     ` Jacob Sparre Andersen
2018-06-14 21:28 ` Randy Brukardt
2018-06-15  9:37 ` Alejandro R. Mosteo

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