From: Robert A Duff on
Jeffrey Carter <spam.jrcarter.not(a)spam.not.acm.org> writes:

> On 08/09/2010 11:32 AM, Natacha Kerensikova wrote:
>>
>> In C for such things I usually use a struct bitfield. I guess the Ada
>> equivalent would be a record of Booleans, with a pragma or something
>> to have them packed together. Would there be anything wrong with that?
>> It seems to me more readable than the above IFs, though from what I
>> understood from the rest of the thread it would make CASE on multiple
>> bit difficult, and it won't allow slicing (which I'm not sure is a bad
>> thing, readability-wise). Is there anything else?
>
> Typically, I would address it using:
>
> type Mode_ID is (Alarm, ...);
>
> type Mode_Set is array (Mode_ID) of Boolean;
> for Mode_Set'Component_Size use 1;
>
> Mode : Mode_Set;
>
> if Mode (Alarm) then ...
>
> Of course, I'd usually leave off the 'Component_Size definition; memory
> is usually cheap and plentiful these days. Only if I had to match an
> existing bit-packed representation, or Mode_ID was very large [array
> (Integer) of Boolean, anyone?] would I worry about the representation.

Well, if you're doing "and"s and "or"s (i.e. intersections and unions),
then the packed representation is likely more efficient. Memory is
cheap in terms of money, but in terms of efficiency, using more
memory can make your program run slower (e.g. worse cache behavior).

I'd use "pragma Pack" instead of the rep clause in this case.
It's guaranteed to do the same thing, but the pragma has more
of a flavor of "for efficiency reasons". I'd use the Component_Size
clause if I were interfacing to some existing representation,
i.e., "for correctness reasons".

- Bob
From: (see below) on
On 09/08/2010 19:32, in article
d8933d54-7fee-4923-8a0c-ce9c5b1b9383(a)14g2000yqa.googlegroups.com, "Natacha
Kerensikova" <lithiumcat(a)gmail.com> wrote:

> On Aug 9, 5:14�pm, Georg Bauhaus <rm.dash-bauh...(a)futureapps.de>
> wrote:
>> On 09.08.10 16:38, Dmitry A. Kazakov wrote:
>>
>>> Just one example from a huge list, why "in" is not an operation?
>>
>>> � �if 0 /= (Mode and Alarm) then �-- Isn't it awful?
>>
>>> why am I not allowed to have:
>>
>>> � �if Alarm in Mode then
>>
>> Is anything wrong with packed arrays of Booleans for status thingies?

I define a function "/" that takes the types of Mode and Alarm and returns
Boolean, so I can say things like:

if Alarm/Mode then ...

Or (real code)

if INS.jump_target/starts_a_code_block then ...

--
Bill Findlay
<surname><forename> chez blueyonder.co.uk


From: Dmitry A. Kazakov on
On Mon, 09 Aug 2010 12:47:45 -0400, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:
>
>> 1. The membership/subset tests look even worse
>
> We're talking about bit maps now, right?

Yes

> Membership is "if Flags(X)...". Subset is
> "if Is_Subset(These_Flags, Those_Flags)...".
> The body of Is_Subset says, "(X and Y) = X".
>
> Not so horrible.

But a lot of manual work. The type should just do what you expect it to do.

>> 2. No ranges
>> 3. No loops
>
> I don't know what you want ranges and loops for.

A subset of flags. E.g. Critical_Errors, Warnings, Any_Error.

> If you really want these, you can Unchecked_Convert to
> integer (signed range 0..2**something). But only if
> something is small.
>
>> 4. No case statement
>
> Yeah, that's a shame. I'd like to have case statements
> on bit maps, but also on other composite types.

Yes, it is a type property that the domain is a set of identifiable values,
in fact, some mapping to an enumeration.

The language should provide means to implement this interface with any
type. E.g. why I cannot specify this interface for String to be able to
write:

case Get_Token is
when "type" => ...
when "package" => ...
when others => raise Syntax_Error;
end case;

>> 6. No discriminants of
>
> I'm not sure why you'd want discriminants of bit maps,
> but I agree that discriminants should be more general.

type Message (Urgency : Alarm_Type) is ...

>> Note that array must be a view of a modular type with the modulus 2**N, but
>> the type itself must remain scalar.
>
> All Ada compilers support:
>
> type Index is range 0..100;
> type Bit_Map is array (Index) of Boolean;".
>
> And this:
>
> type Bit_Map is array (Character) of Boolean;".
>
> But no Ada compilers support this:
>
> type Bit_Map is mod 2**100;

Why not? It is not that difficult to implement mod 2**100 or range
-2**1_000_000..2**1_000_000+1. I think the standard should require it on
any hardware.

>> Most of modular types should have no + at all. There should be a readable
>> notation for X+1 instead of infernal T'Succ(X)
>
> What notation would you like?
>
> How about:
>
> function Succ (...) return ... renames T'Succ;

It should be something more like an operator. The problem is that generics
should understand it without passing around as an extra parameter.

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
From: Natacha Kerensikova on
On Aug 9, 8:49 pm, Ludovic Brenta <ludo...(a)ludovic-brenta.org> wrote:
> I pursued that idea a little further and actually wrote an embryonic
> S-Expression library.  I'm not entirely satisfied with it because it
> uses copy semantics instead of reference semantics and so is probably
> inefficient.  But it does demonstrate how to read and write
> S-Expressions on a stream (e.g. a file).  Also, it shows how to
> hex-encode and hex-decode blobs, which I've modelled as Storage_Arrays.
>
> You can browse the sources here:
>
> http://green.ada-france.org:8081/branch/changes/org.ludovic-brenta.s_...
>
> Enjoy.  (the license is the GPLv3 or later).

Interesting, though it seems your code won't like strings containing a
double-quote.

However, the principal conclusion I draw from reading this is that I'm
still far from having the Ada level required to write anything like
that (since I can't even understand everything while reading it).

Still, from what I understood, I'm not fond of the idea of having to
write type-to-atom conversion procedure while they already exist.

It occurred to me that most types already know how to serialize
themselves, through the Stream subsystem. Strings, Unbounded_strings,
Integers, Float, etc, can all be read from and written into a stream.
So the code to convert them into file-suitable Stream_Element_Array
exist. Won't be a pity not to reuse it?

Pursuing this idea leads to a library quite different from what I had
in mind when I started this thread. Let's call it Sexp_Stream, which
would be derived from Root_Stream_Type. Then Read and Write procedure
are called (from what I understand) by type'Read and type'Write after
said type has turned itself into a Stream_Element_Array. That would
cover atom I/O, and some procedures must be added to cover the list I/
O part.

I think I can imagine how the writing part would happen:
after having initialized a Sexp_Stream object with various
information, including an underlying stream where the S-expression
would be actually written, the application would use the Write
procedure to append an object as an atom to the current node, and the
newly appended atom would become the current node. List procedure
would be called something like List_Open, to open a new list and
append following nodes into it, and List_Close, to close the current
list and come back to the previous list.

Using my tcp-connect example, it would look like this (please excuse
Ada syntax error and focus on the idea):

Sexp_Stream.Open(SxStream, underlying_stream, ...);
Sexp_Stream.Open_List(SxStream);
String'Write(SxStream, "tcp-connect");
Sexp_Stream.Open_List(SxStream);
String'Write(SxStream, "host");
String'Write(SxStream, Hostname);
Sexp_Stream.Close_List(SxStream);
Sexp_Strean.Open_List(SxStream);
String'Write(SxStream, "port");
Integer'Write(SxStream, PortNumber);
Sexp_Stream.Close_List(SxStream);
Sexp_Stream.Close_List(SxStream);

Now I have to admit I don't know how to specify the reading part of
such a Sexp_Stream. I guess I would need the notion of a current node,
with a function telling the application whether the current node is a
list or an atom, type'Read converting the current atom into said type
(and raising an exception when the current atom is a list), and some
procedures to get to the next node, to the frist node following the
current list (i.e. up one level), and when the current node is a list
to go the first node of the list (i.e. one level deeper).

However such a library wouldn't cover all my S-expression needs,
because I sometimes need to keep S-expressions into memory, so there
would be another package for in-memory S-expressions, which would have
to interact nicely with Sexp_Stream.

So, how does it sound? Is it totally crazy? Is it totally not-Ada? Is
there something right in there?

For Jeffry Carter (and anybody interested in helping me understand the
Ada way): here is how it looks like when I haven't thought much about
it. Notice that all this is completely from the point of view of the
application using the package, with very few implementation choices.
If I knew Ada, wouldn't these explanations be pretty much the contents
of the specification file, with about everything from the body being
still to invent? How Ada-ish is that thought process?


Thanks in advance for your reviews of my ideas,
Natacha
From: Dmitry A. Kazakov on
On Mon, 09 Aug 2010 13:00:38 -0400, Robert A Duff wrote:

> "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:
>
>> On Mon, 09 Aug 2010 09:48:02 -0400, Robert A Duff wrote:
>>
>>> "Dmitry A. Kazakov" <mailbox(a)dmitry-kazakov.de> writes:
>>>
>>>> The implementation or the idea? Would you agree that objects with some
>>>> properties of modular integers have place in Ada programs which do not
>>>> interface C?
>>>
>>> No. I do not like implicit "mod". But that's the essence of
>>> modular types.
>>>
>>> If I ran the circus, then this:
>>>
>>> M : constant := 2**64;
>>> type My_Unsigned is range 0..M-1;
>>> pragma Assert(My_Unsigned'Size = 64);
>>>
>>> X : My_Unsigned := ...;
>>> Y : My_Unsigned := (X + 1) mod M;
>>>
>>> would be legal, and would not raise any exceptions, even when
>>> X = M-1. (And I'd want "(X + 1) mod M" to be implemented
>>> as a single "add" instruction on a typical 64-bit machine.)
>>
>> What does "+" above return?
>
> A value of type My_Unsigned. The values of this type are
> the infinite set of all integers -- that's already the
> case in Ada, except that the RM allows (not requires)
> certain calculations to overflow and raise C_E.

OK, but it is not modular, it is natural. And it is just a different case
where modular types should not be used in first place, like size_t.
Equivalent Ada types like Storage_Offset are not modular.

>>...Is "mod M" a required part of the notation or
>> not?
>
> No, not required -- my idea is that if you want to
> perform some operation ("mod" or "+" or "*" or anything),
> you write that explicitly in the code. No change there
> from the way signed integers already work.

Yes, but not for modular types! (:-))

>>>>> Perhaps they _should_ be unordered, but I won't agree or disagree,
>>>>> since I think in an ideal world they should be banished.
>>>>
>>>> I think they could be fixed.
>>>
>>> How? And having fixed them, when would you use them?
>>> That is, when would you prefer them over signed integers?
>>
>> Ring buffer indexing,
>
> I prefer an explicit "mod" there.

This is will be a source of errors like forgetting mod or specifying wrong
modulus. The idea of modular types is to prevent such errors.

>>...flags (by-value sets actually),
>
> I prefer array-of-Boolean over modular. Even better would
> be a proper user-defined abstraction, with notations like "in".

Agree

>>...cryptography,
>
> Explicit "mod".

Disagree.

>> interfacing, communication.
>
> For these, you don't want modular semantics -- you just want
> a data type whose representation matches what you're
> interfacing/communicating with, such as "type Octet is
> range 0..2**8-1;"

The problem is that these things require both array-of-Boolean view and
arithmetic. I agree that when arithmetic is used, then it has to be wide.
E.g. when interpreting sequences of octets as little/big endian numbers, we
never use modular arithmetic. But integer arithmetic is incompatible with
array/set view. I.e. once you added something it is another type integer:

function "+" (Left, Right : Octet) return Universal_Integer;

>> I think that all these usages require different types of modular types with
>> different sets of operations. So I would prefer a language extension which
>> would allow me construction of such types rather than built-in ones, which
>> satisfy no one.
>
> I certainly agree with that. But it sounds like you are
> agreeing with my point -- that modular types should not
> be in the language.

Yes, but what I want will never become Ada, so I prefer that minimum I can
get. (:-))

--
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de
First  |  Prev  |  Next  |  Last
Pages: 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
Prev: GPRbuild compatibility
Next: Irony?