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.
next prev parent 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