comp.lang.ada
 help / color / mirror / Atom feed
* Strings with discriminated records
@ 2018-05-26 21:43 NiGHTS
  2018-05-26 23:42 ` Shark8
                   ` (4 more replies)
  0 siblings, 5 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-26 21:43 UTC (permalink / raw)


I know that Ada Strings are an unconstrained type, and so you can't use them in records. But if a discriminated record is being passed a String parameter which is then being assigned to a String object in a record, the string is being constrained at the instantiation of the record. So shouldn't the compiler allow this configuration since it has enough information to allocate the memory required for the record?

Either way, considering this unfortunate Ada limitation, is there a workaround that can assign a string's default value on a record using a discriminant? Is there a way to do this with Fixed or bounded strings?

Thank you for your help!

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

* Re: Strings with discriminated records
  2018-05-26 21:43 Strings with discriminated records NiGHTS
@ 2018-05-26 23:42 ` Shark8
  2018-05-27  1:42   ` NiGHTS
  2018-05-27 17:11 ` NiGHTS
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 51+ messages in thread
From: Shark8 @ 2018-05-26 23:42 UTC (permalink / raw)


You can do this:

Type Message(Length : Positive) is record
  Text  :  String(1..Length);
  -- Other components.
end record;

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

* Re: Strings with discriminated records
  2018-05-26 23:42 ` Shark8
@ 2018-05-27  1:42   ` NiGHTS
  2018-05-27  8:39     ` Dmitry A. Kazakov
  2018-05-27 12:48     ` Mehdi Saada
  0 siblings, 2 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-27  1:42 UTC (permalink / raw)


On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
> You can do this:
> 
> Type Message(Length : Positive) is record
>   Text  :  String(1..Length);
>   -- Other components.
> end record;

More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...

Type Message (Length : Positive; Text_Value : String) is record
  Text  :  String(1..Length) := Text_Value;
  -- Other components.
end record; 

This gives me an error: Discriminants must must have a discrete or access type

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

* Re: Strings with discriminated records
  2018-05-27  1:42   ` NiGHTS
@ 2018-05-27  8:39     ` Dmitry A. Kazakov
  2018-05-27 12:22       ` Mehdi Saada
  2018-05-27 14:34       ` NiGHTS
  2018-05-27 12:48     ` Mehdi Saada
  1 sibling, 2 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-27  8:39 UTC (permalink / raw)


On 2018-05-27 03:42, NiGHTS wrote:
> On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
>> You can do this:
>>
>> Type Message(Length : Positive) is record
>>    Text  :  String(1..Length);
>>    -- Other components.
>> end record;
> 
> More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...
> 
> Type Message (Length : Positive; Text_Value : String) is record
>    Text  :  String(1..Length) := Text_Value;
>    -- Other components.
> end record;
> 
> This gives me an error: Discriminants must must have a discrete or access type

There is no constructors and no user-defined aggregates, which you are 
actually asking for, but sometimes a constructing function does the job:

    function Create (Value : String) return Message is
    begin
       return (Length => Value'Length, Text => Value);
    end Create;

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

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

* Re: Strings with discriminated records
  2018-05-27  8:39     ` Dmitry A. Kazakov
@ 2018-05-27 12:22       ` Mehdi Saada
  2018-05-27 12:40         ` Dmitry A. Kazakov
  2018-05-27 14:34       ` NiGHTS
  1 sibling, 1 reply; 51+ messages in thread
From: Mehdi Saada @ 2018-05-27 12:22 UTC (permalink / raw)


What do you mean by "no constructor" exactly ? You said that several times, but never stated your point precisely (or I missed it). What's the problem with constructor functions ?

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

* Re: Strings with discriminated records
  2018-05-27 12:22       ` Mehdi Saada
@ 2018-05-27 12:40         ` Dmitry A. Kazakov
  0 siblings, 0 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-27 12:40 UTC (permalink / raw)


On 2018-05-27 14:22, Mehdi Saada wrote:
> What do you mean by "no constructor" exactly ? You said that several times, but never stated your point precisely (or I missed it).

Constructor is a sequence of actions that makes a valid object of type T 
from a chunk of raw memory. Constructor cannot be a procedure or a 
function, but it can call user-defined hooks from it.

Ada compiler generates constructors where necessary, but offers little 
(controlled types) or no support for user-defined hooks.

> What's the problem with constructor functions ?

They do not work well with limited types and inheritance trees 
especially in presence of private types and private extensions.

Another aspect is lack of type safety. It is easy to circumvent or 
misuse constructing functions leaving the object in an undefined state, 
yet considered valid = typing violation.

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

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

* Re: Strings with discriminated records
  2018-05-27  1:42   ` NiGHTS
  2018-05-27  8:39     ` Dmitry A. Kazakov
@ 2018-05-27 12:48     ` Mehdi Saada
  2018-05-27 13:03       ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: Mehdi Saada @ 2018-05-27 12:48 UTC (permalink / raw)


> Type Message (Length : Positive; Text_Value : String) is record
>   Text  :  String(1..Length) := Text_Value;
>   -- Other components.
> end record; 
The only interest in this would be being able to omit Length, and have the compiler write text: string (text_value'range) := text_value;
But it's a pretty limited improvement... not worth the work.
But type AA (LL : access String) is record
      L : String := LL.all;
   end record;
should be allowed, I guess, for the same reason as in my other post.

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

* Re: Strings with discriminated records
  2018-05-27 12:48     ` Mehdi Saada
@ 2018-05-27 13:03       ` Dmitry A. Kazakov
  0 siblings, 0 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-27 13:03 UTC (permalink / raw)


On 2018-05-27 14:48, Mehdi Saada wrote:
>> Type Message (Length : Positive; Text_Value : String) is record
>>    Text  :  String(1..Length) := Text_Value;
>>    -- Other components.
>> end record;
> The only interest in this would be being able to omit Length, and have the compiler write text: string (text_value'range) := text_value;
> But it's a pretty limited improvement... not worth the work.
> But type AA (LL : access String) is record
>        L : String := LL.all;
>     end record;
> should be allowed, I guess, for the same reason as in my other post.

Access discriminant is not intended for initialization. Initialization 
must be done by a constructor or a user-defined aggregate instead of 
misusing disciminants for this purpose.

The reason why access discriminant is not allowed for non-limited types 
is assignment. Consider this:

    function Mess return AA is
       Local  : aliased String := "Catch me if you can";
       Result : AA (Local'Access);
    begin
       return Result;
    end Mess;

Then

    Mess.LL.all; -- Oops!

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

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

* Re: Strings with discriminated records
  2018-05-27  8:39     ` Dmitry A. Kazakov
  2018-05-27 12:22       ` Mehdi Saada
@ 2018-05-27 14:34       ` NiGHTS
  2018-05-27 14:50         ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: NiGHTS @ 2018-05-27 14:34 UTC (permalink / raw)


On Sunday, May 27, 2018 at 4:39:36 AM UTC-4, Dmitry A. Kazakov wrote:
> On 2018-05-27 03:42, NiGHTS wrote:
> > On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
> >> You can do this:
> >>
> >> Type Message(Length : Positive) is record
> >>    Text  :  String(1..Length);
> >>    -- Other components.
> >> end record;
> > 
> > More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...
> > 
> > Type Message (Length : Positive; Text_Value : String) is record
> >    Text  :  String(1..Length) := Text_Value;
> >    -- Other components.
> > end record;
> > 
> > This gives me an error: Discriminants must must have a discrete or access type
> 
> There is no constructors and no user-defined aggregates, which you are 
> actually asking for, but sometimes a constructing function does the job:
> 
>     function Create (Value : String) return Message is
>     begin
>        return (Length => Value'Length, Text => Value);
>     end Create;
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

This is actually a good solution to me. I use this kind of technique often but not in the context of strings, so I find this an elegant way to solve my problem. Here is the final code for anyone who want to see it.

Type Message (Length : Positive) is record
    Text  :  String (1 .. Length);
end record; 
        
function Create (Value : String) return Message is
begin
    return (Length => Value'Length, Text => Value);
end Create;
        
M : Message := Create ("Hello World");


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

* Re: Strings with discriminated records
  2018-05-27 14:34       ` NiGHTS
@ 2018-05-27 14:50         ` Dmitry A. Kazakov
  2018-05-27 15:19           ` NiGHTS
  2018-05-29 22:31           ` Randy Brukardt
  0 siblings, 2 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-27 14:50 UTC (permalink / raw)


On 2018-05-27 16:34, NiGHTS wrote:
> On Sunday, May 27, 2018 at 4:39:36 AM UTC-4, Dmitry A. Kazakov wrote:
>> On 2018-05-27 03:42, NiGHTS wrote:
>>> On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
>>>> You can do this:
>>>>
>>>> Type Message(Length : Positive) is record
>>>>     Text  :  String(1..Length);
>>>>     -- Other components.
>>>> end record;
>>>
>>> More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...
>>>
>>> Type Message (Length : Positive; Text_Value : String) is record
>>>     Text  :  String(1..Length) := Text_Value;
>>>     -- Other components.
>>> end record;
>>>
>>> This gives me an error: Discriminants must must have a discrete or access type
>>
>> There is no constructors and no user-defined aggregates, which you are
>> actually asking for, but sometimes a constructing function does the job:
>>
>>      function Create (Value : String) return Message is
>>      begin
>>         return (Length => Value'Length, Text => Value);
>>      end Create;
>>
>> -- 
>> Regards,
>> Dmitry A. Kazakov
>> http://www.dmitry-kazakov.de
> 
> This is actually a good solution to me. I use this kind of technique often but not in the context of strings, so I find this an elegant way to solve my problem. Here is the final code for anyone who want to see it.
> 
> Type Message (Length : Positive) is record
>      Text  :  String (1 .. Length);
> end record;
>          
> function Create (Value : String) return Message is
> begin
>      return (Length => Value'Length, Text => Value);
> end Create;
>          
> M : Message := Create ("Hello World");

Some reduce it to an operator

    function "+" (Value : String) return Message is
    begin
       return (Length => Value'Length, Text => Value);
    end "+";

    M : Message := +"Hello World";

as a poor-man solution to supertyping. I.e. if it were possible to make 
Message a subtype of String (by providing conversions), you could simply 
write:

    M : Message := "Hello World";

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


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

* Re: Strings with discriminated records
  2018-05-27 14:50         ` Dmitry A. Kazakov
@ 2018-05-27 15:19           ` NiGHTS
  2018-05-27 15:32             ` AdaMagica
  2018-05-29 22:31           ` Randy Brukardt
  1 sibling, 1 reply; 51+ messages in thread
From: NiGHTS @ 2018-05-27 15:19 UTC (permalink / raw)


On Sunday, May 27, 2018 at 10:50:58 AM UTC-4, Dmitry A. Kazakov wrote:
> On 2018-05-27 16:34, NiGHTS wrote:
> > On Sunday, May 27, 2018 at 4:39:36 AM UTC-4, Dmitry A. Kazakov wrote:
> >> On 2018-05-27 03:42, NiGHTS wrote:
> >>> On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
> >>>> You can do this:
> >>>>
> >>>> Type Message(Length : Positive) is record
> >>>>     Text  :  String(1..Length);
> >>>>     -- Other components.
> >>>> end record;
> >>>
> >>> More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...
> >>>
> >>> Type Message (Length : Positive; Text_Value : String) is record
> >>>     Text  :  String(1..Length) := Text_Value;
> >>>     -- Other components.
> >>> end record;
> >>>
> >>> This gives me an error: Discriminants must must have a discrete or access type
> >>
> >> There is no constructors and no user-defined aggregates, which you are
> >> actually asking for, but sometimes a constructing function does the job:
> >>
> >>      function Create (Value : String) return Message is
> >>      begin
> >>         return (Length => Value'Length, Text => Value);
> >>      end Create;
> >>
> >> -- 
> >> Regards,
> >> Dmitry A. Kazakov
> >> http://www.dmitry-kazakov.de
> > 
> > This is actually a good solution to me. I use this kind of technique often but not in the context of strings, so I find this an elegant way to solve my problem. Here is the final code for anyone who want to see it.
> > 
> > Type Message (Length : Positive) is record
> >      Text  :  String (1 .. Length);
> > end record;
> >          
> > function Create (Value : String) return Message is
> > begin
> >      return (Length => Value'Length, Text => Value);
> > end Create;
> >          
> > M : Message := Create ("Hello World");
> 
> Some reduce it to an operator
> 
>     function "+" (Value : String) return Message is
>     begin
>        return (Length => Value'Length, Text => Value);
>     end "+";
> 
>     M : Message := +"Hello World";
> 
> as a poor-man solution to supertyping. I.e. if it were possible to make 
> Message a subtype of String (by providing conversions), you could simply 
> write:
> 
>     M : Message := "Hello World";
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

So I tried use your solution in another program I am writing but the compiler is complaining because the record I am doing this on is derived from Ada.Finalization.Controlled, so I'd need to use an extension aggregate, but I'm not sure how to do that with an abstract object like this.

This gives me an error...

Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
    Text  :  String (1 .. Length);
end record;
       
function Create (Value : String) return Message is
    Finalization : Ada.Finalization.Controlled; -- "ERROR: type of object cannot be abstract"
begin
    return (Finalization with Length => Value'Length, Text => Value);
end Create; 


Hmm, any ideas?

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

* Re: Strings with discriminated records
  2018-05-27 15:19           ` NiGHTS
@ 2018-05-27 15:32             ` AdaMagica
  2018-05-27 16:22               ` NiGHTS
  0 siblings, 1 reply; 51+ messages in thread
From: AdaMagica @ 2018-05-27 15:32 UTC (permalink / raw)


Am Sonntag, 27. Mai 2018 17:19:37 UTC+2 schrieb NiGHTS:
> On Sunday, May 27, 2018 at 10:50:58 AM UTC-4, Dmitry A. Kazakov wrote:
> > On 2018-05-27 16:34, NiGHTS wrote:
> > > On Sunday, May 27, 2018 at 4:39:36 AM UTC-4, Dmitry A. Kazakov wrote:
> > >> On 2018-05-27 03:42, NiGHTS wrote:
> > >>> On Saturday, May 26, 2018 at 7:42:22 PM UTC-4, Shark8 wrote:
> > >>>> You can do this:
> > >>>>
> > >>>> Type Message(Length : Positive) is record
> > >>>>     Text  :  String(1..Length);
> > >>>>     -- Other components.
> > >>>> end record;
> > >>>
> > >>> More interesting to me would be to pass a string literal as a discriminant. Using your example, something like this...
> > >>>
> > >>> Type Message (Length : Positive; Text_Value : String) is record
> > >>>     Text  :  String(1..Length) := Text_Value;
> > >>>     -- Other components.
> > >>> end record;
> > >>>
> > >>> This gives me an error: Discriminants must must have a discrete or access type
> > >>
> > >> There is no constructors and no user-defined aggregates, which you are
> > >> actually asking for, but sometimes a constructing function does the job:
> > >>
> > >>      function Create (Value : String) return Message is
> > >>      begin
> > >>         return (Length => Value'Length, Text => Value);
> > >>      end Create;
> > >>
> > >> -- 
> > >> Regards,
> > >> Dmitry A. Kazakov
> > >> http://www.dmitry-kazakov.de
> > > 
> > > This is actually a good solution to me. I use this kind of technique often but not in the context of strings, so I find this an elegant way to solve my problem. Here is the final code for anyone who want to see it.
> > > 
> > > Type Message (Length : Positive) is record
> > >      Text  :  String (1 .. Length);
> > > end record;
> > >          
> > > function Create (Value : String) return Message is
> > > begin
> > >      return (Length => Value'Length, Text => Value);
> > > end Create;
> > >          
> > > M : Message := Create ("Hello World");
> > 
> > Some reduce it to an operator
> > 
> >     function "+" (Value : String) return Message is
> >     begin
> >        return (Length => Value'Length, Text => Value);
> >     end "+";
> > 
> >     M : Message := +"Hello World";
> > 
> > as a poor-man solution to supertyping. I.e. if it were possible to make 
> > Message a subtype of String (by providing conversions), you could simply 
> > write:
> > 
> >     M : Message := "Hello World";
> > 
> > -- 
> > Regards,
> > Dmitry A. Kazakov
> > http://www.dmitry-kazakov.de
> 
> So I tried use your solution in another program I am writing but the compiler is complaining because the record I am doing this on is derived from Ada.Finalization.Controlled, so I'd need to use an extension aggregate, but I'm not sure how to do that with an abstract object like this.
> 
> This gives me an error...
> 
> Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
>     Text  :  String (1 .. Length);
> end record;
>       
 
function Create (Value : String) return Message is
begin
  return (Ada.Finalization.Controlled with
          Length => Value'Length, Text => Value);
end Create; 


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

* Re: Strings with discriminated records
  2018-05-27 15:32             ` AdaMagica
@ 2018-05-27 16:22               ` NiGHTS
  0 siblings, 0 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-27 16:22 UTC (permalink / raw)


On Sunday, May 27, 2018 at 11:32:58 AM UTC-4, AdaMagica wrote:  
>  
> function Create (Value : String) return Message is
> begin
>   return (Ada.Finalization.Controlled with
>           Length => Value'Length, Text => Value);
> end Create;

Thank you. It works!


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

* Re: Strings with discriminated records
  2018-05-26 21:43 Strings with discriminated records NiGHTS
  2018-05-26 23:42 ` Shark8
@ 2018-05-27 17:11 ` NiGHTS
  2018-05-27 18:07   ` Simon Wright
  2018-05-27 18:25   ` Dmitry A. Kazakov
  2018-05-28 13:55 ` NiGHTS
                   ` (2 subsequent siblings)
  4 siblings, 2 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-27 17:11 UTC (permalink / raw)


I've expanded my example to include a strange run-time crash I am getting.

Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
    Text  :  String (1 .. Length);
    Cstr  :  Interfaces.C.Strings.chars_ptr;
end record;
       
function Create (Value : String) return Message is
begin
    return (
        Ada.Finalization.Controlled with Length => Value'Length, 
        Text => Value, 
        Cstr => Interfaces.C.Strings.New_String (Value) 
    );
end Create; 

procedure Finalize (
    M : in out Message
) is
begin
    Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
end;

declare
    M : Message := Create ("Hello World");
begin
    null;
end; 

Why does my program crash on Finalization?


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

* Re: Strings with discriminated records
  2018-05-27 17:11 ` NiGHTS
@ 2018-05-27 18:07   ` Simon Wright
  2018-05-27 23:08     ` NiGHTS
  2018-05-27 18:25   ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: Simon Wright @ 2018-05-27 18:07 UTC (permalink / raw)


NiGHTS <nights@unku.us> writes:

> I've expanded my example to include a strange run-time crash I am getting.
>
> Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
>     Text  :  String (1 .. Length);
>     Cstr  :  Interfaces.C.Strings.chars_ptr;
> end record;
>        
> function Create (Value : String) return Message is
> begin
>     return (
>         Ada.Finalization.Controlled with Length => Value'Length, 
>         Text => Value, 
>         Cstr => Interfaces.C.Strings.New_String (Value) 
>     );
> end Create; 
>
> procedure Finalize (
>     M : in out Message
> ) is
> begin
>     Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> end;
>
> declare
>     M : Message := Create ("Hello World");
> begin
>     null;
> end; 
>
> Why does my program crash on Finalization?

Maybe Finalize is getting called twice? You should set M.Cstr to
Null_Ptr after freeing it.

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

* Re: Strings with discriminated records
  2018-05-27 17:11 ` NiGHTS
  2018-05-27 18:07   ` Simon Wright
@ 2018-05-27 18:25   ` Dmitry A. Kazakov
  2018-05-27 22:44     ` NiGHTS
  1 sibling, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-27 18:25 UTC (permalink / raw)


On 2018-05-27 19:11, NiGHTS wrote:
> I've expanded my example to include a strange run-time crash I am getting.
> 
> Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
>      Text  :  String (1 .. Length);
>      Cstr  :  Interfaces.C.Strings.chars_ptr;
> end record;
>         
> function Create (Value : String) return Message is
> begin
>      return (
>          Ada.Finalization.Controlled with Length => Value'Length,
>          Text => Value,
>          Cstr => Interfaces.C.Strings.New_String (Value)
>      );
> end Create;
> 
> procedure Finalize (
>      M : in out Message
> ) is
> begin
>      Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> end;
> 
> declare
>      M : Message := Create ("Hello World");
> begin
>      null;
> end;
> 
> Why does my program crash on Finalization?

Because it is wrong.

You have a controlled object which gets copied all the time. It means 
that the pointer Cstr is shared by all copies and is freed multiple 
times. Either

1. You must override Adjust and make a new string for the result.

or

2. You could deploy some reference counting schema cloning the content 
when the string at the pointer is updated. This is how dynamic strings 
are usually implemented.

P.S. If you want C-compatible strings use char_array, it is exactly the 
thing you need.

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


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

* Re: Strings with discriminated records
  2018-05-27 18:25   ` Dmitry A. Kazakov
@ 2018-05-27 22:44     ` NiGHTS
  2018-05-28  7:29       ` Dmitry A. Kazakov
  2018-05-28  7:42       ` Simon Wright
  0 siblings, 2 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-27 22:44 UTC (permalink / raw)


On Sunday, May 27, 2018 at 2:25:02 PM UTC-4, Dmitry A. Kazakov wrote:
> On 2018-05-27 19:11, NiGHTS wrote:
> > I've expanded my example to include a strange run-time crash I am getting.
> > 
> > Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
> >      Text  :  String (1 .. Length);
> >      Cstr  :  Interfaces.C.Strings.chars_ptr;
> > end record;
> >         
> > function Create (Value : String) return Message is
> > begin
> >      return (
> >          Ada.Finalization.Controlled with Length => Value'Length,
> >          Text => Value,
> >          Cstr => Interfaces.C.Strings.New_String (Value)
> >      );
> > end Create;
> > 
> > procedure Finalize (
> >      M : in out Message
> > ) is
> > begin
> >      Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> > end;
> > 
> > declare
> >      M : Message := Create ("Hello World");
> > begin
> >      null;
> > end;
> > 
> > Why does my program crash on Finalization?
> 
> Because it is wrong.
> 
> You have a controlled object which gets copied all the time. It means 
> that the pointer Cstr is shared by all copies and is freed multiple 
> times. Either
> 
> 1. You must override Adjust and make a new string for the result.
> 
> or
> 
> 2. You could deploy some reference counting schema cloning the content 
> when the string at the pointer is updated. This is how dynamic strings 
> are usually implemented.
> 
> P.S. If you want C-compatible strings use char_array, it is exactly the 
> thing you need.
> 
> -- 
> Regards,
> Dmitry A. Kazakov
> http://www.dmitry-kazakov.de

I confirmed with an Ada.Text_IO.Put_Line() that Finalize was called three times. I then disabled Finalize and created an explicitly called Finalize2 function and it worked fine. It's weird though because my program only elaborated the object once, so why did it finalize three times? 

I tried wrapping the body of finalize in a condition to force it to run only once, yet it still managed to run it again ignoring the boolean. I'm perplexed. Not sure if I should ever trust Ada.Finalization.Controlled.


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

* Re: Strings with discriminated records
  2018-05-27 18:07   ` Simon Wright
@ 2018-05-27 23:08     ` NiGHTS
  2018-05-28  1:44       ` Jere
  0 siblings, 1 reply; 51+ messages in thread
From: NiGHTS @ 2018-05-27 23:08 UTC (permalink / raw)


On Sunday, May 27, 2018 at 2:07:37 PM UTC-4, Simon Wright wrote:
> 
> > I've expanded my example to include a strange run-time crash I am getting.
> >
> > Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
> >     Text  :  String (1 .. Length);
> >     Cstr  :  Interfaces.C.Strings.chars_ptr;
> > end record;
> >        
> > function Create (Value : String) return Message is
> > begin
> >     return (
> >         Ada.Finalization.Controlled with Length => Value'Length, 
> >         Text => Value, 
> >         Cstr => Interfaces.C.Strings.New_String (Value) 
> >     );
> > end Create; 
> >
> > procedure Finalize (
> >     M : in out Message
> > ) is
> > begin
> >     Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> > end;
> >
> > declare
> >     M : Message := Create ("Hello World");
> > begin
> >     null;
> > end; 
> >
> > Why does my program crash on Finalization?
> 
> Maybe Finalize is getting called twice? You should set M.Cstr to
> Null_Ptr after freeing it.

It doesn't work. On each automatic call of Finalize, the object data is reset. Its very strange.

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

* Re: Strings with discriminated records
  2018-05-27 23:08     ` NiGHTS
@ 2018-05-28  1:44       ` Jere
  2018-05-28  3:05         ` NiGHTS
  0 siblings, 1 reply; 51+ messages in thread
From: Jere @ 2018-05-28  1:44 UTC (permalink / raw)


On Sunday, May 27, 2018 at 7:08:03 PM UTC-4, NiGHTS wrote:
> On Sunday, May 27, 2018 at 2:07:37 PM UTC-4, Simon Wright wrote:
> > 
> > > I've expanded my example to include a strange run-time crash I am getting.
> > >
> > > Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
> > >     Text  :  String (1 .. Length);
> > >     Cstr  :  Interfaces.C.Strings.chars_ptr;
> > > end record;
> > >        
> > > function Create (Value : String) return Message is
> > > begin
> > >     return (
> > >         Ada.Finalization.Controlled with Length => Value'Length, 
> > >         Text => Value, 
> > >         Cstr => Interfaces.C.Strings.New_String (Value) 
> > >     );
> > > end Create; 
> > >
> > > procedure Finalize (
> > >     M : in out Message
> > > ) is
> > > begin
> > >     Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> > > end;
> > >
> > > declare
> > >     M : Message := Create ("Hello World");
> > > begin
> > >     null;
> > > end; 
> > >
> > > Why does my program crash on Finalization?
> > 
> > Maybe Finalize is getting called twice? You should set M.Cstr to
> > Null_Ptr after freeing it.
> 
> It doesn't work. On each automatic call of Finalize, the object data is reset. Its very strange.

It won't work unless you have an appropriate Adjust.  Since your object is
controlled (and not limited controlled), the compiler is making temporaries,
each with their own copy of the pointer (someone else mentioned this above).
Each temporary will be finalized and each will have their own copy of
the pointer, so nulling it only nulls that objects copy and not the others.

As stated above by someone else, you'll either have to do a clone with
separately allocated memory or some sort of reference count that only 
allows finalize to call free when the last copy calls finalize (and
ignores the others calls).

Dmitry has an example of how to do this with an intrusive reference
count with his handles/objects library (see his website).

Making the type limited controlled is also a solution since it cannot
make temporaries for one like it can a regular controlled object.

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

* Re: Strings with discriminated records
  2018-05-28  1:44       ` Jere
@ 2018-05-28  3:05         ` NiGHTS
  2018-05-28  3:23           ` NiGHTS
  0 siblings, 1 reply; 51+ messages in thread
From: NiGHTS @ 2018-05-28  3:05 UTC (permalink / raw)


On Sunday, May 27, 2018 at 9:44:22 PM UTC-4, Jere wrote:
> On Sunday, May 27, 2018 at 7:08:03 PM UTC-4, NiGHTS wrote:
> > On Sunday, May 27, 2018 at 2:07:37 PM UTC-4, Simon Wright wrote:
> > > 
> > > > I've expanded my example to include a strange run-time crash I am getting.
> > > >
> > > > Type Message (Length : Positive) is new Ada.Finalization.Controlled with record
> > > >     Text  :  String (1 .. Length);
> > > >     Cstr  :  Interfaces.C.Strings.chars_ptr;
> > > > end record;
> > > >        
> > > > function Create (Value : String) return Message is
> > > > begin
> > > >     return (
> > > >         Ada.Finalization.Controlled with Length => Value'Length, 
> > > >         Text => Value, 
> > > >         Cstr => Interfaces.C.Strings.New_String (Value) 
> > > >     );
> > > > end Create; 
> > > >
> > > > procedure Finalize (
> > > >     M : in out Message
> > > > ) is
> > > > begin
> > > >     Interfaces.C.Strings.Free ( M.Cstr ); -- Crashes here
> > > > end;
> > > >
> > > > declare
> > > >     M : Message := Create ("Hello World");
> > > > begin
> > > >     null;
> > > > end; 
> > > >
> > > > Why does my program crash on Finalization?
> > > 
> > > Maybe Finalize is getting called twice? You should set M.Cstr to
> > > Null_Ptr after freeing it.
> > 
> > It doesn't work. On each automatic call of Finalize, the object data is reset. Its very strange.
> 
> It won't work unless you have an appropriate Adjust.  Since your object is
> controlled (and not limited controlled), the compiler is making temporaries,
> each with their own copy of the pointer (someone else mentioned this above).
> Each temporary will be finalized and each will have their own copy of
> the pointer, so nulling it only nulls that objects copy and not the others.
> 
> As stated above by someone else, you'll either have to do a clone with
> separately allocated memory or some sort of reference count that only 
> allows finalize to call free when the last copy calls finalize (and
> ignores the others calls).
> 
> Dmitry has an example of how to do this with an intrusive reference
> count with his handles/objects library (see his website).
> 
> Making the type limited controlled is also a solution since it cannot
> make temporaries for one like it can a regular controlled object.

Yes, I understand now. I will do some tests and see what works for me. Thank you.


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

* Re: Strings with discriminated records
  2018-05-28  3:05         ` NiGHTS
@ 2018-05-28  3:23           ` NiGHTS
  0 siblings, 0 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-28  3:23 UTC (permalink / raw)


I used Limited_Controlled to great success. Thank you everyone!

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

* Re: Strings with discriminated records
  2018-05-27 22:44     ` NiGHTS
@ 2018-05-28  7:29       ` Dmitry A. Kazakov
  2018-05-28  7:42       ` Simon Wright
  1 sibling, 0 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-28  7:29 UTC (permalink / raw)


On 2018-05-28 00:44, NiGHTS wrote:

> I confirmed with an Ada.Text_IO.Put_Line() that Finalize was called three times.

It is called for three different objects.

> I then disabled Finalize and created an explicitly called Finalize2 function and it worked fine. It's weird though because my program only elaborated the object once, so why did it finalize three times?

Because you have three copies of the controlled object. Here is a fixed 
implementation with Adjust:
-------------------------------------------------------
with Ada.Text_IO;          use Ada.Text_IO;
with Interfaces.C;         use Interfaces.C;
with Interfaces.C.Strings; use Interfaces.C.Strings;

with Ada.Finalization;

procedure Test is

    package P is
       type C_String is new Ada.Finalization.Controlled with private;
       function Create (Text : String) return C_String;
       overriding procedure Adjust (Text : in out C_String);
       overriding procedure Finalize (Text : in out C_String);
    private
       type C_String is new Ada.Finalization.Controlled with record
          Ptr : chars_ptr;
       end record;
    end P;

    package body P is
       function Create (Text : String) return C_String is
       begin
          Put_Line ("Creating:" & Text);
          return (Ada.Finalization.Controlled with New_String (Text));
       end Create;

       procedure Adjust (Text : in out C_String) is
       begin
          if Text.Ptr = Null_Ptr then
             Put_Line ("Copying null string:");
          else
             Put_Line ("Copying:" & Value (Text.Ptr));
             Text.Ptr := New_String (Value (Text.Ptr));
          end if;
       end Adjust;

       procedure Finalize (Text : in out C_String) is
       begin
          if Text.Ptr = Null_Ptr then
             Put_Line ("Finalizing null string:");
          else
             Put_Line ("Finalizing:" & Value (Text.Ptr));
             Free (Text.Ptr);
          end if;
       end Finalize;
    end P;

    use P;
    S1 : C_String := Create ("Hello");
begin
    null;
end Test;
-------------------------------------------------
It prints:

Creating:Hello
Copying:Hello
Finalizing:Hello
Copying:Hello
Finalizing:Hello
Finalizing:Hello

Now the meaning of this:

Creating:Hello   -- Create
Copying:Hello    -- Copy local object (aggregate?) in Create
Finalizing:Hello -- Finalize the local object in Create
Copying:Hello    -- Copy result of Create to S1
Finalizing:Hello -- Finalize the result of Create
Finalizing:Hello -- Finalize S1

> I tried wrapping the body of finalize in a condition to force it to run only once, yet it still managed to run it again ignoring the boolean. I'm perplexed. Not sure if I should ever trust Ada.Finalization.Controlled.

Yes, see the example.

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

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

* Re: Strings with discriminated records
  2018-05-27 22:44     ` NiGHTS
  2018-05-28  7:29       ` Dmitry A. Kazakov
@ 2018-05-28  7:42       ` Simon Wright
  2018-05-28 18:38         ` Shark8
  1 sibling, 1 reply; 51+ messages in thread
From: Simon Wright @ 2018-05-28  7:42 UTC (permalink / raw)


NiGHTS <nights@unku.us> writes:

> I confirmed with an Ada.Text_IO.Put_Line() that Finalize was called
> three times. I then disabled Finalize and created an explicitly called
> Finalize2 function and it worked fine. It's weird though because my
> program only elaborated the object once, so why did it finalize three
> times?

You need to read ARM7.6, in particular (17):
http://www.ada-auth.org/standards/rm12_w_tc1/html/RM-7-6.html#p17

Disregarding for the moment any "assignment" that might happen in
computing the result of Create, & looking at
   
   declare
      M : Nights.Message := Nights.Create ("Hello World");
   begin
      null;
   end;

First, the Create call makes an anonymous object.

Then, M is in theory finalized, but this is likely optimised away.

Then, the bits of the anonymous object are copied into M. This is a
"shallow copy". [***]

Then, the anonymous object is finalized, which frees
<anonymous>.Cstr. HOWEVER, M.Cstr still contains the same value, which
means it's pointing to deallocated memory.

Then, on exit from the declare block, M is finalized, and Finalize tries
to free M.Cstr again. Oops.

This is always going to happen if you make a shallow copy of something
which contains plain allocated memory.

As Dmitry said upthread, you need an Adjust, which makes a deep copy of
the plain allocated memory, immediately after [***] above:

   procedure Adjust (M : in out Message) is
      use Interfaces.C.Strings;
   begin
      M.Cstr := New_Char_Array (Value (M.Cstr));
   end Adjust;

> I tried wrapping the body of finalize in a condition to force it to
> run only once, yet it still managed to run it again ignoring the
> boolean.

If the boolean was in Message, the same argument as above applies.

>          I'm perplexed. Not sure if I should ever trust
> Ada.Finalization.Controlled.

As with most things, not until you know how to use it.

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

* Re: Strings with discriminated records
  2018-05-26 21:43 Strings with discriminated records NiGHTS
  2018-05-26 23:42 ` Shark8
  2018-05-27 17:11 ` NiGHTS
@ 2018-05-28 13:55 ` NiGHTS
  2018-05-29 14:37 ` Mehdi Saada
  2018-05-29 22:41 ` Mehdi Saada
  4 siblings, 0 replies; 51+ messages in thread
From: NiGHTS @ 2018-05-28 13:55 UTC (permalink / raw)


Thank you Simon and Dmitry, it is very clear to me now. I highly appreciate the time you took to explain it to me. I am now clear on how to use Controlled, and I can see it being very beneficial. Thank you again!


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

* Re: Strings with discriminated records
  2018-05-28  7:42       ` Simon Wright
@ 2018-05-28 18:38         ` Shark8
  2018-05-28 21:15           ` Mehdi Saada
  0 siblings, 1 reply; 51+ messages in thread
From: Shark8 @ 2018-05-28 18:38 UTC (permalink / raw)


On Monday, May 28, 2018 at 1:42:24 AM UTC-6, Simon Wright wrote:
>    
>    declare
>       M : Nights.Message := Nights.Create ("Hello World");
>    begin
>       null;
>    end;

One thing you could do here to reduce an assignment is change M's declaration to:
       M : Nights.Message RENAMES Nights.Create ("Hello World");

This eliminates a whole set of adjust/finalize by eliminating the temporary anonymous object AND the assignment. (Ok, so it's really giving a name to the anonymous object so you can use it directly.)


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

* Re: Strings with discriminated records
  2018-05-28 18:38         ` Shark8
@ 2018-05-28 21:15           ` Mehdi Saada
  2018-05-28 21:48             ` Shark8
  0 siblings, 1 reply; 51+ messages in thread
From: Mehdi Saada @ 2018-05-28 21:15 UTC (permalink / raw)


I don't understand this story of anonymous object... Is it optimizing anything ?

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

* Re: Strings with discriminated records
  2018-05-28 21:15           ` Mehdi Saada
@ 2018-05-28 21:48             ` Shark8
  2018-05-28 22:27               ` Mehdi Saada
  0 siblings, 1 reply; 51+ messages in thread
From: Shark8 @ 2018-05-28 21:48 UTC (permalink / raw)


On Monday, May 28, 2018 at 3:15:32 PM UTC-6, Mehdi Saada wrote:
> I don't understand this story of anonymous object... Is it optimizing anything ?

No, it could be optimized, but here I'm inserting $$ to delimit portions of a possible object.

   declare
      $$M : Nights.Message$$ := $$Nights.Create ("Hello World");$$
   begin
      null;
   end; 

"M : Nights.Message" is one object;
":=" is its initialization;
"Nights.Create" is the value to init.

The call produces a value, this is the anonymous object, that value is assigned to M.
Using a RENAMES, the value that is produced by the call is given a name.

See?

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

* Re: Strings with discriminated records
  2018-05-28 21:48             ` Shark8
@ 2018-05-28 22:27               ` Mehdi Saada
  2018-05-28 23:59                 ` Shark8
  2018-05-29  7:49                 ` Dmitry A. Kazakov
  0 siblings, 2 replies; 51+ messages in thread
From: Mehdi Saada @ 2018-05-28 22:27 UTC (permalink / raw)


I see, and I would expect a constant declaration M: constant nights.message := nights.create("hello world);
to have exactly the same implementation. I am right ?
After all you do or not do exactly the same, as far as I understood.


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

* Re: Strings with discriminated records
  2018-05-28 22:27               ` Mehdi Saada
@ 2018-05-28 23:59                 ` Shark8
  2018-05-29  0:41                   ` Dan'l Miller
  2018-05-29  7:49                 ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: Shark8 @ 2018-05-28 23:59 UTC (permalink / raw)


On Monday, May 28, 2018 at 4:27:26 PM UTC-6, Mehdi Saada wrote:
> I see, and I would expect a constant declaration M: constant nights.message := nights.create("hello world);
> to have exactly the same implementation. I am right ?
> After all you do or not do exactly the same, as far as I understood.

According to the LRM, this is true.
This is [possibly] untrue in GNAT -- the past several releases have bug-boxed on several rename features. (Really frustrating, as I tend to favor RENAME over CONSTANT when possible.)


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

* Re: Strings with discriminated records
  2018-05-28 23:59                 ` Shark8
@ 2018-05-29  0:41                   ` Dan'l Miller
  2018-05-30 17:11                     ` Shark8
  0 siblings, 1 reply; 51+ messages in thread
From: Dan'l Miller @ 2018-05-29  0:41 UTC (permalink / raw)


On Monday, May 28, 2018 at 1:38:27 PM UTC-5, Shark8 wrote:
> On Monday, May 28, 2018 at 1:42:24 AM UTC-6, Simon Wright wrote:
> >    
> >    declare
> >       M : Nights.Message := Nights.Create ("Hello World");
> >    begin
> >       null;
> >    end;
> 
> One thing you could do here to reduce an assignment is change M's declaration to:
>        M : Nights.Message RENAMES Nights.Create ("Hello World");
> 
> This eliminates a whole set of adjust/finalize by eliminating the temporary anonymous object AND the assignment. (Ok, so it's really giving a name to the anonymous object so you can use it directly.)

Whoa!  With C++ move semantics in mind, this is by far the most remarkable multifaceted lesson to teach in this whole thread.

1) This is a lesson not only of how to use Ada to accomplish more simply what are move semantics on the overloaded move constructor.

2) But perhaps this is more importantly for language design how much cleaner RENAMES reads than all the && move-semantics crypto syntax through the &&-overloaded-member-function backdoor that C++ has to accomplish (much) the same thing.  (In C++, the rvalue-temporary isn't given an identifier name at its scope of instantiation (although it is given a parameter name upon entry to the move-semantics overloaded member-functions); the rvalue-temporary's heavily-regulated ••address-of-sorts is captured•• for use within move-semantics overloaded member-functions.)

3) Plus, remember to keep RENAMES in mind when writing those Ada-versus-C++ bake-off competitions between languages.  Both for readability compared to the notoriously subtly-cantankerous* move semantics, as well as having Ada match C++'s efficiency regarding what C++ calls move semantics.

* See Scott Meyers' horror book _Effective Modern C++:  42 Specific Ways to Improve Your Use of C++11 and C++14_, especially horror stories #23 though #30, er, I mean the advice in #23 through #30, which is Chapter 5.

http://shop.oreilly.com/product/0636920033707.do

On Monday, May 28, 2018 at 6:59:53 PM UTC-5, Shark8 wrote:
> On Monday, May 28, 2018 at 4:27:26 PM UTC-6, Mehdi Saada wrote:
> > I see, and I would expect a constant declaration M: constant nights.message := nights.create("hello world);
> > to have exactly the same implementation. I am right ?
> > After all you do or not do exactly the same, as far as I understood.
> 
> According to the LRM, this is true.
> This is [possibly] untrue in GNAT -- the past several releases

Wow!  A major** semantics bug in FSF GNAT for “several releases”.  Regarding RENAMES, did AdaCore's customers also suffer such “bug-box” in GNAT Pro for “several releases”?

** assuming that C++'s brute-force moving of heaven & earth & every mountain in sight to make their analogue*** of RENAMES work in C++11, C++14, and C++17 is a measure of how important move semantics are.

*** move semantics via && crypto syntax on (the verbosity of) overloaded operators & member functions, i.e., the move constructor in this thread's case

> have bug-boxed on several rename features. (Really frustrating, as I tend to favor RENAME over CONSTANT when possible.)

What are the precise bugs that you have observed with RENAMES?  Crash of GNAT at compile-time or wrong behavior at runtime?

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

* Re: Strings with discriminated records
  2018-05-28 22:27               ` Mehdi Saada
  2018-05-28 23:59                 ` Shark8
@ 2018-05-29  7:49                 ` Dmitry A. Kazakov
  2018-05-29  9:31                   ` AdaMagica
  2018-05-29 13:40                   ` Dan'l Miller
  1 sibling, 2 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-29  7:49 UTC (permalink / raw)


On 2018-05-29 12:27 AM, Mehdi Saada wrote:
> I see, and I would expect a constant declaration M: constant nights.message := nights.create("hello world);
> to have exactly the same implementation. I am right ?

Yes. Renaming temporary objects is probably a language design bug. But 
renaming is broken in so many ways that one more, one less does not make 
much difference.

BTW, If I would allow renaming a function result, then that would have 
lazy evaluation/closure semantics.

> After all you do or not do exactly the same, as far as I understood.

There are subtle and not so subtle differences, like sliding or not 
array indices.

It is best to use rename only where it was originally intended, e.g.

1. for renaming long named objects/packages:

    X : T renames A.B.C.D.E.X;

2. for renaming view conversions:

    X : T'Class renames T'Class (Y);

3. for renaming array/list elements and record members:

    for I in A'Range loop
       declare
          Current : T renames A (I);
       begin
          ...

4. for resolving name clashes:

    type T is new Integer;
    function Integer_Add (Left, Right : Integer)
       return Integer renames "+"; -- Going to override, so keep the old
    function "+" (Left, Right : Integer)
       return Integer renames "+"; -- The new one

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


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

* Re: Strings with discriminated records
  2018-05-29  7:49                 ` Dmitry A. Kazakov
@ 2018-05-29  9:31                   ` AdaMagica
  2018-05-29 10:14                     ` Dmitry A. Kazakov
  2018-05-29 13:40                   ` Dan'l Miller
  1 sibling, 1 reply; 51+ messages in thread
From: AdaMagica @ 2018-05-29  9:31 UTC (permalink / raw)


Am Dienstag, 29. Mai 2018 09:49:20 UTC+2 schrieb Dmitry A. Kazakov:
> Yes. Renaming temporary objects is probably a language design bug.

It was a consequence of making function results to objects. Before, they were mere values.
Objects can be renamed.

> renaming is broken in so many ways that one more, one less does not make 
> much difference.

Hm, I only see one lie with renaming:

X: constant Integer := -1;
Y: Positive renames X;

What are the other broken features?

> It is best to use rename only where it was originally intended, e.g.

Dmitry's list is very good advice.

> 1. for renaming long named objects/packages:
> 
>     X : T renames A.B.C.D.E.X;
> 
> 2. for renaming view conversions:
> 
>     X : T'Class renames T'Class (Y);
> 
> 3. for renaming array/list elements and record members:
> 
>     for I in A'Range loop
>        declare
>           Current : T renames A (I);
>        begin
>           ...
> 
> 4. for resolving name clashes:
> 
>     type T is new Integer;
>     function Integer_Add (Left, Right : Integer)
>        return Integer renames "+"; -- Going to override, so keep the old
>     function "+" (Left, Right : Integer)
>        return Integer renames "+"; -- The new one

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

* Re: Strings with discriminated records
  2018-05-29  9:31                   ` AdaMagica
@ 2018-05-29 10:14                     ` Dmitry A. Kazakov
  0 siblings, 0 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-29 10:14 UTC (permalink / raw)


On 2018-05-29 11:31 AM, AdaMagica wrote:
> Am Dienstag, 29. Mai 2018 09:49:20 UTC+2 schrieb Dmitry A. Kazakov:
>> Yes. Renaming temporary objects is probably a language design bug.
> 
> It was a consequence of making function results to objects. Before, they were mere values.
> Objects can be renamed.

Yes, but renaming objects without names is obviously charged with 
potential problems. It is best to leave anonymous objects alone for 
optimization reasons.

>> renaming is broken in so many ways that one more, one less does not make
>> much difference.
> 
> Hm, I only see one lie with renaming:
> 
> X: constant Integer := -1;
> Y: Positive renames X;
> 
> What are the other broken features?
1. Not sliding array indices even if explicitly required/implied/expected.

(This is possibly a similar problem to with Integer/Positive that 
constraints are not respected/checked/enforced/rejected.)

2. Renaming can hide/conflict with the original object and its 
renamings. This should never happen.

3. There should be no subtype specification in renaming at all. Renaming 
must deal with names only.

(I understand the motivation behind. I.e. to be able to rename 
overloaded subprograms. But that is a false place to solve an unrelated 
problem: lack unambiguous naming for subprograms)

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

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

* Re: Strings with discriminated records
  2018-05-29  7:49                 ` Dmitry A. Kazakov
  2018-05-29  9:31                   ` AdaMagica
@ 2018-05-29 13:40                   ` Dan'l Miller
  2018-05-29 14:04                     ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: Dan'l Miller @ 2018-05-29 13:40 UTC (permalink / raw)


On Tuesday, May 29, 2018 at 2:49:20 AM UTC-5, Dmitry A. Kazakov wrote:
> On 2018-05-29 12:27 AM, Mehdi Saada wrote:
> > I see, and I would expect a constant declaration M: constant nights.message := nights.create("hello world);
> > to have exactly the same implementation. I am right ?
> 
> Yes. Renaming temporary objects is probably a language design bug.

Then submit an AI to launder the dirty laundry versus have this viewpoint vetted by the full board of ARG experts to see whether this assertion has any merit at all.

> But 
> renaming is broken in so many ways that one more, one less does not make 
> much difference.
> 
> BTW, If I would allow renaming a function result, then that would have 
> lazy evaluation/closure semantics.
> 
> > After all you do or not do exactly the same, as far as I understood.
> 
> There are subtle and not so subtle differences, like sliding or not 
> array indices.
> 
> It is best to use rename only where it was originally intended, e.g.

If you think that the ARG made a mistake in the wording of the _LRM_ to allow vastly more usage of RENAMES than “what* was originally intended”, then submit one or more AIs to launder the very-soiled dirty laundry versus have this viewpoint vetted by experts to see whether it has any merit at all.

* as the Dmitry Standard Organization itemized below:

> 1. for renaming long named objects/packages:
> 
>     X : T renames A.B.C.D.E.X;
> 
> 2. for renaming view conversions:
> 
>     X : T'Class renames T'Class (Y);
> 
> 3. for renaming array/list elements and record members:
> 
>     for I in A'Range loop
>        declare
>           Current : T renames A (I);
>        begin
>           ...
> 
> 4. for resolving name clashes:
> 
>     type T is new Integer;
>     function Integer_Add (Left, Right : Integer)
>        return Integer renames "+"; -- Going to override, so keep the old
>     function "+" (Left, Right : Integer)
>        return Integer renames "+"; -- The new one


On Tuesday, May 29, 2018 at 4:31:17 AM UTC-5, AdaMagica wrote:
> Dmitry's list is very good advice.

Wait, we have an international standard for Ada that specifies big-time industry-trend* language features that need a de facto amendment ‘out in the community’ (apparently: documented in only passing commentary on c.l.a) to amend the international standard in ways that undermine the ISO standard's normativeness?

* Move-semantics have been a feature-set that have received extraordinarily-focused attention to add to add them to the C++ ISO standard for multiple years running now:  C++11, C++14, C++17, and perhaps some fine tuning in the next C++2X as well.

Either

1) RENAMES is an awesome language feature with many valid uses deriving from the way RENAMES is officially specified in Ada's international standard (e.g., that shows C++ how its move semantics should have been done much more readably, much simpler).

or

2) the uses of RENAMES other than those on Dmitry Standard Organization's list above is a big pile of dog dung that needs AIs filed to officially deprecate RENAMES's unwise excesses in future editions of Ada's international standard.

It seems that the Law of Excluded Middle applies here:
a)  either restricting RENAMES's usage to only Dmitry Standard Organization's list above is awesome & wise
or
b) RENAMES as officially written into Ada's ISO international standard is awesome & wise in permitting RENAMES's full breadth of usages, including Shark8's above.


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

* Re: Strings with discriminated records
  2018-05-29 13:40                   ` Dan'l Miller
@ 2018-05-29 14:04                     ` Dmitry A. Kazakov
  2018-05-29 22:41                       ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-29 14:04 UTC (permalink / raw)


On 2018-05-29 03:40 PM, Dan'l Miller wrote:

> If you think that the ARG made a mistake in the wording of the _LRM_ to allow vastly more usage of RENAMES than “what* was originally intended”, then submit one or more AIs to launder the very-soiled dirty laundry versus have this viewpoint vetted by experts to see whether it has any merit at all.

Whatever mistakes made they are permanent now due to the backward 
compatibility issue.

Except for, possibly, not allowing a renaming to hide another renaming 
of the same object, there is nothing that can be fixed.

The case is represented by this:

    use Ada.IO_Exceptions;
    use Streams.Stream_IO;

    begin
       ...
    exception
       when End_Error => -- Illegal
          null;
    end;

which is obviously wrong, the code must be OK.

But if anybody would care write an AI to fix that, it will be surely 
rejected by ARG, on the ground of being "nice to have". I have more 
important things to do, so count me out.

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


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

* Re: Strings with discriminated records
  2018-05-26 21:43 Strings with discriminated records NiGHTS
                   ` (2 preceding siblings ...)
  2018-05-28 13:55 ` NiGHTS
@ 2018-05-29 14:37 ` Mehdi Saada
  2018-05-29 22:44   ` Randy Brukardt
  2018-05-29 22:41 ` Mehdi Saada
  4 siblings, 1 reply; 51+ messages in thread
From: Mehdi Saada @ 2018-05-29 14:37 UTC (permalink / raw)


Let's go half and half: how about making subtype indication in object renaming simply optional, and allow it for compatibility and in case of ambiguity ? A pragma would suffice if it doesn't exist yet (just wondering).

I can see myself how renaming is broken:
Some constraints in subprograms profile are taken in account, and some are not.
The compiler will enforce this constraint:
Function KI (JJ : in INTEGER := 5) return Integer is (JJ);
function KKI (JJ : in Positive) return Positive renames KI;
then put_line(KKi(-5)'img) will cause warnings.

But this is ignored:
procedure MMI (JJ : in Integer) renames MM;, the subtype in MM's declaration is used, and this is ignored too: 
declare
   procedure KI (JJ : out Integer) is
   begin
      JJ := -5;
   end KI;
   procedure KKI (JJ : out Positive) renames KI;
   M : Positive;
begin
   KKI (M);
end;
Then you really obtain a M with a value out of range. What the fuck ? This is the worst thing and type security breach I saw in Ada until now. Fixing this in the next version is more important that adding new features, and it's worth incompatibilities.


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

* Re: Strings with discriminated records
  2018-05-27 14:50         ` Dmitry A. Kazakov
  2018-05-27 15:19           ` NiGHTS
@ 2018-05-29 22:31           ` Randy Brukardt
  2018-05-30  7:29             ` Dmitry A. Kazakov
  1 sibling, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2018-05-29 22:31 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:peegke$rt1$1@gioia.aioe.org...
...
> as a poor-man solution to supertyping. I.e. if it were possible to make 
> Message a subtype of String (by providing conversions), you could simply 
> write:
>
>    M : Message := "Hello World";

Or you could just give string literals to type Message (although you'll have 
to wait a bit for that capability -- but it should be in Ada 2020 - 
finally).

                                    Randy.



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

* Re: Strings with discriminated records
  2018-05-26 21:43 Strings with discriminated records NiGHTS
                   ` (3 preceding siblings ...)
  2018-05-29 14:37 ` Mehdi Saada
@ 2018-05-29 22:41 ` Mehdi Saada
  2018-05-30 19:46   ` Randy Brukardt
  4 siblings, 1 reply; 51+ messages in thread
From: Mehdi Saada @ 2018-05-29 22:41 UTC (permalink / raw)


>    M : Message := "Hello World";

>Or you could just give string literals to type Message (although you'll have
to wait a bit for that capability -- but it should be in Ada 2020 -
finally). 
I don't get what you mean exactly (meaning of "give"). What would it look like ?
Would it be something like
type Message (discriminants or not) is ... end record with IS_LIKE => String ?

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

* Re: Strings with discriminated records
  2018-05-29 14:04                     ` Dmitry A. Kazakov
@ 2018-05-29 22:41                       ` Randy Brukardt
  2018-05-30  5:00                         ` J-P. Rosen
  0 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2018-05-29 22:41 UTC (permalink / raw)



"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:pejmlh$1ic1$1@gioia.aioe.org...
...
> The case is represented by this:
>
>    use Ada.IO_Exceptions;
>    use Streams.Stream_IO;
>
>    begin
>       ...
>    exception
>       when End_Error => -- Illegal
>          null;
>    end;
>
> which is obviously wrong, the code must be OK.
>
> But if anybody would care write an AI to fix that, it will be surely 
> rejected by ARG, on the ground of being "nice to have". I have more 
> important things to do, so count me out.

It's been discussed over dinner a few times, but everyone has more important 
things to do than write an AI for it. So nothing ever happens. (Of course, 
the real problem above is "package use clauses", don't use (ahem) them and 
you can't possibly have this problem.)

In any case, it is too late for Ada 2020; the deadline for new ideas (from 
anyone, including me) has passed.

                                                         Randy.



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

* Re: Strings with discriminated records
  2018-05-29 14:37 ` Mehdi Saada
@ 2018-05-29 22:44   ` Randy Brukardt
  0 siblings, 0 replies; 51+ messages in thread
From: Randy Brukardt @ 2018-05-29 22:44 UTC (permalink / raw)



"Mehdi Saada" <00120260a@gmail.com> wrote in message 
news:b5d211dd-beea-4de3-a509-7a8cf5b3f5a0@googlegroups.com...
> Let's go half and half: how about making subtype indication in object 
> renaming simply optional, and allow it for compatibility and in case of 
> ambiguity ?

There's supposed to be an AI for that, but the supposed author hasn't 
written it yet. It's on the Ada 2020 list so it might happen. But it might 
not, too, at least some people think that renames and constants ought to 
work the same -- if that mindset exists then I doubt it will be adopted (the 
only reason I would vote for making the subtype optional in a renames is 
because it is a lie; if it told the truth I would be very against changing 
it).

                                               Randy.


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

* Re: Strings with discriminated records
  2018-05-29 22:41                       ` Randy Brukardt
@ 2018-05-30  5:00                         ` J-P. Rosen
  2018-05-30 20:09                           ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: J-P. Rosen @ 2018-05-30  5:00 UTC (permalink / raw)


Le 30/05/2018 à 00:41, Randy Brukardt a écrit :
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
> news:pejmlh$1ic1$1@gioia.aioe.org...
> ...
>> The case is represented by this:
>>
>>    use Ada.IO_Exceptions;
>>    use Streams.Stream_IO;
>>
>>    begin
>>       ...
>>    exception
>>       when End_Error => -- Illegal
>>          null;
>>    end;
>>
>> which is obviously wrong, the code must be OK.

>(Of course, 
> the real problem above is "package use clauses", don't use (ahem) them and 
> you can't possibly have this problem.)
> ????
With use clauses, you'll have to write:
    when Ada.IO_Exceptions.End_Error =>

while without use clauses, you'll have to write:
    when Ada.IO_Exceptions.End_Error =>

I fail to see the "real problem". Use clauses make the code more
readable, and when there is an ambiguity, you fall back to what you
would do without them. What's the problem?

-- 
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] 51+ messages in thread

* Re: Strings with discriminated records
  2018-05-29 22:31           ` Randy Brukardt
@ 2018-05-30  7:29             ` Dmitry A. Kazakov
  2018-05-30 20:11               ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-05-30  7:29 UTC (permalink / raw)


On 2018-05-30 12:31 AM, Randy Brukardt wrote:
> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> news:peegke$rt1$1@gioia.aioe.org...
> ...
>> as a poor-man solution to supertyping. I.e. if it were possible to make
>> Message a subtype of String (by providing conversions), you could simply
>> write:
>>
>>     M : Message := "Hello World";
> 
> Or you could just give string literals to type Message (although you'll have
> to wait a bit for that capability -- but it should be in Ada 2020 -
> finally).

Yes, I heard about use-defined literals, I am glad they made into Ada.

However subtyping per conversions is a more general approach which would 
work for literals too as it does with universal types.

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


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

* Re: Strings with discriminated records
  2018-05-29  0:41                   ` Dan'l Miller
@ 2018-05-30 17:11                     ` Shark8
  0 siblings, 0 replies; 51+ messages in thread
From: Shark8 @ 2018-05-30 17:11 UTC (permalink / raw)


On Monday, May 28, 2018 at 6:41:41 PM UTC-6, Dan'l Miller wrote:
> On Monday, May 28, 2018 at 1:38:27 PM UTC-5, Shark8 wrote:
>> have bug-boxed on several rename features. (Really frustrating, as I tend to favor RENAME over CONSTANT when possible.)
> 
> What are the precise bugs that you have observed with RENAMES?  Crash of GNAT at compile-time or wrong behavior at runtime?

"Bug-Box" refers to a compile-time crash that prints out an error-message with a surrounding "ASCII-art", really quite annoying when talking about such a basic feature as renaming attributes.

I first encountered it in Byron, where I was renaming attributes that I was using. IIRC, something along the lines of:
DECLARE
  First : Positive renames Input_Vector'First;
  Last  : Natural  renames Input_Vector'Last;
BEGIN
  For Index in First..Last-1 loop
   DECLARE
    Item : Element renames Input_Vector( Index );
    Next : Element renames Input_Vector( Index+1 );
   BEGIN
     -- Do stuff on one item possibly depending on lookahead "Next"...
   END;
  End loop;
END;

If you look in the history of Byron there's one commit where a huge chunk of RENAMES are replaced with the equivalent CONSTANT :=, which is this bug.


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

* Re: Strings with discriminated records
  2018-05-29 22:41 ` Mehdi Saada
@ 2018-05-30 19:46   ` Randy Brukardt
  2018-05-30 19:48     ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2018-05-30 19:46 UTC (permalink / raw)


"Mehdi Saada" <00120260a@gmail.com> wrote in message 
news:06a59646-1d72-4200-967b-592ab61c4b1f@googlegroups.com...
>>    M : Message := "Hello World";
>
>>Or you could just give string literals to type Message (although you'll 
>>have
> to wait a bit for that capability -- but it should be in Ada 2020 -
> finally).
> I don't get what you mean exactly (meaning of "give"). What would it look 
> like ?
> Would it be something like
> type Message (discriminants or not) is ... end record with IS_LIKE => 
> String ?

See AI12-0249-1. This hasn't been discussed at a meeting yet, so it probably 
will change some, but Tucker suggests aspects "Integer_Literal", 
"Real_Literal", "Null_Literal", and "String_Literal". These represent 
functions that can be specified:

type Message (discriminants or not) is ... end record
    with String_Literal  => Make_Message;

where Make_Message is something like:

    function Make_Message (Lit : in Wide_Wide_String) return Message;

with the obvious semantics when a string literal is encountered.

                                             Randy.



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

* Re: Strings with discriminated records
  2018-05-30 19:46   ` Randy Brukardt
@ 2018-05-30 19:48     ` Randy Brukardt
  0 siblings, 0 replies; 51+ messages in thread
From: Randy Brukardt @ 2018-05-30 19:48 UTC (permalink / raw)


BTW, the reason that I said "it might change" is that there are some issues 
with what to do with private types where the full type "naturally" has the 
same kind of literal. I don't think that is handled quite right yet, and 
it's relatively important to get right (user-defined aggregates have a 
similar, even worse problem).

                                    Randy.

"Randy Brukardt" <randy@rrsoftware.com> wrote in message 
news:pemv2c$1uq$1@franka.jacob-sparre.dk...
> "Mehdi Saada" <00120260a@gmail.com> wrote in message 
> news:06a59646-1d72-4200-967b-592ab61c4b1f@googlegroups.com...
>>>    M : Message := "Hello World";
>>
>>>Or you could just give string literals to type Message (although you'll 
>>>have
>> to wait a bit for that capability -- but it should be in Ada 2020 -
>> finally).
>> I don't get what you mean exactly (meaning of "give"). What would it look 
>> like ?
>> Would it be something like
>> type Message (discriminants or not) is ... end record with IS_LIKE => 
>> String ?
>
> See AI12-0249-1. This hasn't been discussed at a meeting yet, so it 
> probably will change some, but Tucker suggests aspects "Integer_Literal", 
> "Real_Literal", "Null_Literal", and "String_Literal". These represent 
> functions that can be specified:
>
> type Message (discriminants or not) is ... end record
>    with String_Literal  => Make_Message;
>
> where Make_Message is something like:
>
>    function Make_Message (Lit : in Wide_Wide_String) return Message;
>
> with the obvious semantics when a string literal is encountered.
>
>                                             Randy.
>
> 


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

* Re: Strings with discriminated records
  2018-05-30  5:00                         ` J-P. Rosen
@ 2018-05-30 20:09                           ` Randy Brukardt
  2018-05-31  4:19                             ` J-P. Rosen
  0 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2018-05-30 20:09 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 2202 bytes --]


"J-P. Rosen" <rosen@adalog.fr> wrote in message 
news:pelb5u$cqo$1@gioia.aioe.org...
> Le 30/05/2018 à 00:41, Randy Brukardt a écrit :
...
>>(Of course,
>> the real problem above is "package use clauses", don't use (ahem) them 
>> and
>> you can't possibly have this problem.)
>> ????
> With use clauses, you'll have to write:
>    when Ada.IO_Exceptions.End_Error =>
>
> while without use clauses, you'll have to write:
>    when Ada.IO_Exceptions.End_Error =>
>
> I fail to see the "real problem". Use clauses make the code more
> readable, and when there is an ambiguity, you fall back to what you
> would do without them. What's the problem?

(A) The person I was responding to was upset that they had to write the 
fully qualified name in this case, and practically, they're right. (Tucker 
has complained about this multiple times.)

(B) But package use clauses make things visible that are not overloadable 
(like objects), so they tend to be a substantial maintenance hazard --  
adding something to a package can make client code using use clauses illegal 
because of conflicts. Adding unrelated stuff should *never* make any client 
illegal (changes, obviously are different).

If Ada had made objects/exceptions overloadable, this problem would be much 
less severe. But it didn't, and changing that now would be difficult to do 
without lots of subtle incompatibilities.

Use type/use all type (and better still, prefix calls) mostly avoid this 
problem by only operating on overloadable things. You still can get 
conflicts, but only when there are design issues (having multiple operations 
with the same name and profile means either there is unnecessary duplication 
[two routines doing the same thing] or that there is routines doing 
different things with the same name (yikes!).

In a best case world, a rename conflicting with the original routine or 
another rename of it would be ignored in all use clauses, along with 
overloading of objects/exceptions. That would reduce conflicts to a handful 
of cases. (If overloading of generics could be figured out, that would be 
even better.) But that has to wait for Ada++.

                                                    Randy.


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

* Re: Strings with discriminated records
  2018-05-30  7:29             ` Dmitry A. Kazakov
@ 2018-05-30 20:11               ` Randy Brukardt
  0 siblings, 0 replies; 51+ messages in thread
From: Randy Brukardt @ 2018-05-30 20:11 UTC (permalink / raw)


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message 
news:peljsm$q5i$1@gioia.aioe.org...
> On 2018-05-30 12:31 AM, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:peegke$rt1$1@gioia.aioe.org...
>> ...
>>> as a poor-man solution to supertyping. I.e. if it were possible to make
>>> Message a subtype of String (by providing conversions), you could simply
>>> write:
>>>
>>>     M : Message := "Hello World";
>>
>> Or you could just give string literals to type Message (although you'll 
>> have
>> to wait a bit for that capability -- but it should be in Ada 2020 -
>> finally).
>
> Yes, I heard about use-defined literals, I am glad they made into Ada.
>
> However subtyping per conversions is a more general approach which would 
> work for literals too as it does with universal types.

Yes, but it's never gotten any traction. I've never been able to get any 
interest in any sort of user-defined conversion - there is a large faction 
that thinks function calls are good enough for that.

                              Randy.



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

* Re: Strings with discriminated records
  2018-05-30 20:09                           ` Randy Brukardt
@ 2018-05-31  4:19                             ` J-P. Rosen
  2018-05-31 22:18                               ` Randy Brukardt
  0 siblings, 1 reply; 51+ messages in thread
From: J-P. Rosen @ 2018-05-31  4:19 UTC (permalink / raw)


Le 30/05/2018 à 22:09, Randy Brukardt a écrit :
> (B) But package use clauses make things visible that are not overloadable 
> (like objects), so they tend to be a substantial maintenance hazard --  
> adding something to a package can make client code using use clauses illegal 
> because of conflicts. Adding unrelated stuff should *never* make any client 
> illegal (changes, obviously are different).
Here I don't agree. OF COURSE, changing a specification can make client
code illegal, with or without use clauses. And I would not call making
code illegal a "maintenance hazard"; on the contrary, a maintenance
hazard is when a change does not make code illegal, but acts
differently. We know how hard Tuck fought in Ada 95 to eliminate the
Beaujolais effect...

-- 
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] 51+ messages in thread

* Re: Strings with discriminated records
  2018-05-31  4:19                             ` J-P. Rosen
@ 2018-05-31 22:18                               ` Randy Brukardt
  2018-06-01 13:35                                 ` Dan'l Miller
  0 siblings, 1 reply; 51+ messages in thread
From: Randy Brukardt @ 2018-05-31 22:18 UTC (permalink / raw)


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 2240 bytes --]

"J-P. Rosen" <rosen@adalog.fr> wrote in message 
news:pent4f$nrj$1@gioia.aioe.org...
> Le 30/05/2018 à 22:09, Randy Brukardt a écrit :
>> (B) But package use clauses make things visible that are not overloadable
>> (like objects), so they tend to be a substantial maintenance hazard --
>> adding something to a package can make client code using use clauses 
>> illegal
>> because of conflicts. Adding unrelated stuff should *never* make any 
>> client
>> illegal (changes, obviously are different).
> Here I don't agree. OF COURSE, changing a specification can make client
> code illegal, with or without use clauses. And I would not call making
> code illegal a "maintenance hazard"; on the contrary, a maintenance
> hazard is when a change does not make code illegal, but acts
> differently. We know how hard Tuck fought in Ada 95 to eliminate the
> Beaujolais effect...

Whenever large amounts of code depend on some package, causing unusual 
illegalities in working code just because of the addition of a new 
object/exception is a major problem. Consider something like Claw: we have 
to avoid making changes to the specs -- even ones that are clearly good 
ideas -- in order to avoid breaking user code. Similarly, I have to document 
*every single* change in a language-defined package as an incompatibility --  
even though only people overusing use clauses have a possibility of such an 
incompatibility. And this is a real problem; it bites me often in Janus/Ada 
(which itself overuses use clauses) -- the main reason that I hardly ever 
use them in new code.

Ada's "solution" of making things illegal is better than silent changes 
(although those can happen, too, especially in child units), but the best 
situation is one where adding new subprograms/objects/exceptions don't have 
any effect at all on existing code (in the absence of dubious design - that 
is multiple different things with the same name and profile). Anything else 
makes it hard to enhance libraries cleanly (you end up with unnecessary 
child packages - like "Ada.Directories.Hierarchical_File_Names" - to avoid 
the incompatibilities - and that itself is just another kind of pain.

                                                            Randy.


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

* Re: Strings with discriminated records
  2018-05-31 22:18                               ` Randy Brukardt
@ 2018-06-01 13:35                                 ` Dan'l Miller
  2018-06-01 15:20                                   ` Dmitry A. Kazakov
  0 siblings, 1 reply; 51+ messages in thread
From: Dan'l Miller @ 2018-06-01 13:35 UTC (permalink / raw)


On Thursday, May 31, 2018 at 5:18:51 PM UTC-5, Randy Brukardt wrote:
> Whenever large amounts of code depend on some package, causing unusual 
> illegalities in working code just because of the addition of a new 
> object/exception is a major problem. Consider something like Claw: we have 
> to avoid making changes to the specs -- even ones that are clearly good 
> ideas -- in order to avoid breaking user code.

In that hypothetical Ada++ for the 21st century, every externally-visible portion of the interface of a package would be required to be versioned, so that laggards can stay with the old clunky version-x interface unmodified and trendy people can run with the Cool Kids by using the next-gen version-x+1 interface.

(I word that with a bit of humor there, but I mean it seriously as the key remaining largely-untouched obstacle to writing software-in-the-large in any programming language that purports to support programming software-in-the-large at the millions or tens-of-millions of lines of code level.  We have succeeded in almost all other aspects of writing software-in-the-large but have failed miserably on this one that you bring up above—mainly because no one ever tried to tackle it in a programming language.  Btw, for distributed systems communicating via packets, we solved that versioned-interface problem via TLVs:  don't recognize the new tag?; then you already know from Day One to ignore any unrecognized next-gen subTLV including this one, you uncouth laggard old long-in-the-tooth software, but use the backwards-compatibility mode of the containing TLV instead.)

> Similarly, I have to document 
> *every single* change in a language-defined package as an incompatibility --  
> even though only people overusing use clauses have a possibility of such an 
> incompatibility.

An Ada compiler seeing a combination of
1) a pragma/aspect on that specification
and
2) the overuse of use-clause for that package
could automate that, obviating the need for such documentation to human-beings; human beings are not trustworthy to read anything.  Again, Ada++ for the 21st century would have that feature because it is obviously needed for programming software-in-the-large.

Indeed, Ada++ for the 21st century would just entirely remove the syntax for overusing use-clauses, forcing the more-piecemeal alternative*.

* or indeed forcing my own personal style in all programming languages that support it:  (almost) never use a use-clause, but always declare 1-, 2-, or 3-character abbreviations for packagename-paths, and then prefix every single identifier in app-domain source-code with that abbreviation (the “almost” there:  use use-clauses to obtain operators and non-inheritance type-extensions in the languages that have those, only because there seems to be no alternative).  These abbrevs actually drastically improve the readability of the code, because a human being can see at a glance the various packages interacting with each other, such as to transliterate one package's (or app-domain's) worldview/contract/terms into another package's different worldview/contract/terms.


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

* Re: Strings with discriminated records
  2018-06-01 13:35                                 ` Dan'l Miller
@ 2018-06-01 15:20                                   ` Dmitry A. Kazakov
  0 siblings, 0 replies; 51+ messages in thread
From: Dmitry A. Kazakov @ 2018-06-01 15:20 UTC (permalink / raw)


On 2018-06-01 15:35, Dan'l Miller wrote:

> In that hypothetical Ada++ for the 21st century, every externally-visible portion of the interface of a package would be required to be versioned, so that laggards can stay with the old clunky version-x interface unmodified and trendy people can run with the Cool Kids by using the next-gen version-x+1 interface.

Versions on which level? Versioning on the level of compilation unit 
will not be sufficient. Versioning on the level of individual types 
could be very difficult.

[ The problem must be certainly addressed because the actual situation 
with maintenance of dynamic libraries becomes increasingly intolerable 
as we part with monolithic software architectures in all areas. ]

> Indeed, Ada++ for the 21st century would just entirely remove the syntax for overusing use-clauses, forcing the more-piecemeal alternative*.

I would rather eliminate with-clause as useless. The use-clause would be 
the only method to express a dependency. I would make illegal any use 
clause that hides anything. The programmer would have explicitly rename 
any conflicting items.

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


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

end of thread, other threads:[~2018-06-01 15:20 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-26 21:43 Strings with discriminated records NiGHTS
2018-05-26 23:42 ` Shark8
2018-05-27  1:42   ` NiGHTS
2018-05-27  8:39     ` Dmitry A. Kazakov
2018-05-27 12:22       ` Mehdi Saada
2018-05-27 12:40         ` Dmitry A. Kazakov
2018-05-27 14:34       ` NiGHTS
2018-05-27 14:50         ` Dmitry A. Kazakov
2018-05-27 15:19           ` NiGHTS
2018-05-27 15:32             ` AdaMagica
2018-05-27 16:22               ` NiGHTS
2018-05-29 22:31           ` Randy Brukardt
2018-05-30  7:29             ` Dmitry A. Kazakov
2018-05-30 20:11               ` Randy Brukardt
2018-05-27 12:48     ` Mehdi Saada
2018-05-27 13:03       ` Dmitry A. Kazakov
2018-05-27 17:11 ` NiGHTS
2018-05-27 18:07   ` Simon Wright
2018-05-27 23:08     ` NiGHTS
2018-05-28  1:44       ` Jere
2018-05-28  3:05         ` NiGHTS
2018-05-28  3:23           ` NiGHTS
2018-05-27 18:25   ` Dmitry A. Kazakov
2018-05-27 22:44     ` NiGHTS
2018-05-28  7:29       ` Dmitry A. Kazakov
2018-05-28  7:42       ` Simon Wright
2018-05-28 18:38         ` Shark8
2018-05-28 21:15           ` Mehdi Saada
2018-05-28 21:48             ` Shark8
2018-05-28 22:27               ` Mehdi Saada
2018-05-28 23:59                 ` Shark8
2018-05-29  0:41                   ` Dan'l Miller
2018-05-30 17:11                     ` Shark8
2018-05-29  7:49                 ` Dmitry A. Kazakov
2018-05-29  9:31                   ` AdaMagica
2018-05-29 10:14                     ` Dmitry A. Kazakov
2018-05-29 13:40                   ` Dan'l Miller
2018-05-29 14:04                     ` Dmitry A. Kazakov
2018-05-29 22:41                       ` Randy Brukardt
2018-05-30  5:00                         ` J-P. Rosen
2018-05-30 20:09                           ` Randy Brukardt
2018-05-31  4:19                             ` J-P. Rosen
2018-05-31 22:18                               ` Randy Brukardt
2018-06-01 13:35                                 ` Dan'l Miller
2018-06-01 15:20                                   ` Dmitry A. Kazakov
2018-05-28 13:55 ` NiGHTS
2018-05-29 14:37 ` Mehdi Saada
2018-05-29 22:44   ` Randy Brukardt
2018-05-29 22:41 ` Mehdi Saada
2018-05-30 19:46   ` Randy Brukardt
2018-05-30 19:48     ` Randy Brukardt

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