comp.lang.ada
 help / color / mirror / Atom feed
From: Doctor Who <doc@tardis.org>
Subject: Re: Discriminants or Constructor Function for Limited Types
Date: Sun, 08 May 2022 19:19:18 +0200	[thread overview]
Message-ID: <7puf7h59k2e2ns66918i95s847na2b8num@4ax.com> (raw)
In-Reply-To: t57vgs$4su$1@gioia.aioe.org

On Sun, 8 May 2022 10:37:48 +0200, "Dmitry A. Kazakov"
<mailbox@dmitry-kazakov.de> wrote:

>On 2022-05-08 04:32, Randy Brukardt wrote:
>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>> news:t5619r$10bc$1@gioia.aioe.org...
>>> On 2022-05-07 05:26, Randy Brukardt wrote:
>>>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
>>>> news:t52nd4$vj2$1@gioia.aioe.org...
>>>
>>>>> Because the task type is not composable.
>>>>
>>>> Irrelevant. A task can only be safe if it never interacts with no other
>>>> objects outside of itself.
>>>
>>> Not when other objects are tasks, protected objects, active objects,
>>> atomic objects.
>> 
>> That's a common fallacy. Such objects are safe only if there is exactly one
>> in your system. If there is more than one, various forms of failure are
>> possible even if everything is supposely safe by itself. To make them fully
>> safe, you have to have strong access ordering (for instance, the onion skin
>> model), which no programming language and probably no static tool can
>> enforce. (Proof of safety requires verification that no possible program
>> flow can cause a race condition.)
>
>You are talking about a very low level and tightly coupled design. 
>Higher level object is supposed to prevent that so that there would be 
>no need in taking several mutexes or in chains of external entry calls, 
>at least not explicitly. So an active object is entirely safe.
>
>Anyway, we do not discuss safety of using objects, we discuss safety of 
>composing new objects out of existing ones. It would be silly to argue 
>that since Positive is unsafe due to existence of the unary minus 
>operation, it shall not be used a component of a record type.
>
>>> Because the language lacks obvious abstractions like user-defined
>>> discriminants. Otherwise I see no logical reason why:
>>>
>>>     F : File_Type ("My_Ada_file.adb");
>>>
>>> should not work.
>> 
>> It does "work", but such designs put major restrictions on your clients.
>
>No, you cannot have this syntax. At best you must use Pickwickian 
>pseudo-functions:
>
>    F : File_Type := Open ("My_Ada_file.adb");
>
>> A common way my programs are structured is something like:
>> 
>>       declare
>>          Output_File : Some_File_Type;
>>       begin
>>           Create_or_Open_Output (Output_File);
>>           Write_Output (Output_File, Data);
>>           ...
>>           Close_Output (Output_File);
>>       end;
>> 
>> You can't use such a structure with your design, because you can't pass in
>> the unopened file object to open it appropriately (which can take multiple
>> attempts depending upon options,
>
>It is surprisingly easy when the type system is used as it should be. 
>Just derive a new type from Some_File_Type and provide a new constructor 
>for it.
>
>Note, that your code is already unsafe because nobody knows if 
>Create_or_Open_Output always opens the file and because there is no 
>guarantee that the file is closed, while the design
>
>    declare
>       Output_File : Some_File_Type;
>    begin
>       Write_Output (Output_File, Data);
>    end;
>
>is 100% safe.

Not in the case that your data space is exhausted, in that case
Write_Output will fail, because you have no checks of free space
before writing.


>> Discriminants are only useful for memory management (to size arrays, to make
>> components conditional). Other uses are purely mistakes.
>
>Nope. Discriminant is a parameter, the semantic of must be up to the 
>programmer. The problem with Ada is that it enforces a certain extremely 
>limited implementation of discriminants, so that even that limited use 
>you claimed is actually incorrect:
>
>    type X (Size : Natural) is record
>       S : String (1..Size + 1); -- Tell me about memory management!
>    end record;
>
>>> I simplified creating the object by removing states when the object is
>>> unusable for no other reason than language design. Cases when the file can
>>> be unreadable because of I/O errors have nothing to do with the case when
>>> the programmer did not open it.
>> 
>> There is no difference between the state of an object before it is opened
>> and the one it is in after it is closed. (And these aren't just error cases,
>> as noted by the Windows example.)
>
>Surely, in the design where you deal with open files only, you could not 
>explicitly close one. The object does not have these states. Compare it 
>with Ada 83's Standard_Input. You are not supposed to open or close it.
>
>>>> We initially trying designing Claw Window objects that way, but one had
>>>> to
>>>> handle the case where the user clicks the 'X' (close button) while a
>>>> routine
>>>> is working on the window. Windows closes the window almost immediately,
>>>> and
>>>> the GUI library has to deal with the consequences.
>>>
>>> Windows sends WM_CLOSE first.
>> 
>> Sure, but the only thing you can do at that point is make the object
>> invalid.
>
>That is crude.
>
>It depends on the design but normally Windowed GUI objects are allocated 
>on the stack and are blocking. So WM_CLOSE should simply make an exit 
>from some hidden loop in something like:
>
>    declare
>       Dialog : Dialog_Box;
>    begin
>       Dialog.Run; -- Note, ugliness of lacking constructors again!
>
>Non-modal stuff is a part of some container and thus WM_CLOSE must go to 
>the parent which then explicitly kills the child object. No problem.
>
>You do not need half-backed objects even in GUI. Such states can be 
>hidden in most cases.
>
>>>> There's little point in obsessing about designs that only work in
>>>> academic
>>>> exercises. Ada tries too hard already to accomadate designs like yours.
>>>
>>> On the contrary, it is a very practical software design problem to reduce
>>> error sources as much as possible.
>> 
>> An imaginary reduction of errors, since you have the same states that occur
>> in other usage scenarios.
>
>No they do not. The goal is to eliminate non-functional states. Things 
>like closed file, uninitialized variable, null pointer etc are artifacts 
>of the design. There is nothing in the physical world that requires them.

  reply	other threads:[~2022-05-08 17:19 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-05-04  9:02 Discriminants or Constructor Function for Limited Types R R
2022-05-04  9:40 ` Jeffrey R.Carter
2022-05-04  9:47 ` Dmitry A. Kazakov
2022-05-04 23:49   ` Randy Brukardt
2022-05-05  6:56     ` Dmitry A. Kazakov
2022-05-06  1:53       ` Randy Brukardt
2022-05-06  8:48         ` Dmitry A. Kazakov
2022-05-07  3:26           ` Randy Brukardt
2022-05-07 14:55             ` Dmitry A. Kazakov
2022-05-08  2:32               ` Randy Brukardt
2022-05-08  8:37                 ` Dmitry A. Kazakov
2022-05-08 17:19                   ` Doctor Who [this message]
2022-05-08 18:00                     ` Dmitry A. Kazakov
2022-05-08 18:07                       ` Doctor Who
2022-05-09  8:52                       ` Niklas Holsti
2022-05-09  9:45                         ` Dmitry A. Kazakov
2022-05-09 10:19                       ` Doctor Who
2022-05-09 11:15                         ` Dmitry A. Kazakov
2022-05-09 12:05                           ` Doctor Who
2022-05-09 12:31                             ` Dmitry A. Kazakov
2022-05-10  4:48                   ` Randy Brukardt
2022-05-10  6:18                     ` Dmitry A. Kazakov
2022-05-04 15:05 ` AdaMagica
2022-05-05  9:59 ` R R
replies disabled

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