* How can I avoid Using a Semaphore? (long) @ 2001-01-13 16:18 DuckE 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts ` (2 more replies) 0 siblings, 3 replies; 36+ messages in thread From: DuckE @ 2001-01-13 16:18 UTC (permalink / raw) I have an application that receives a streams of data from TCP/IP sockets. The stream of data is separated into "packets" each beginning with a 32 bit length value. For each of these sockets I have a task that receives the length, then gets a pre-allocated data buffer that is large enough to hold the data, receives the data into the data buffer, and then puts a reference to the buffer into a queue for processing by other tasks. Pseudo code for the main loop for the receive task is something like: Loop Receive 4 bytes of data from the socket Convert the 4 bytes to an integer value Get a buffer from available buffers that is large enough to hold remaining data in message Receive remaining part of message into buffer Queue the message for processing by other tasks End Loop To avoid memory leaks I am using a controlled type with reference counting to implement my data buffer. Since multiple threads may simultaneously have access to the buffer, I use a protected type for reference counting. Since I am using a protected type for reference counting, I cannot assign packets within a protected type (to implement queue's of packets for instance) since these assignments would be attempting to do a protected operation within a protected type. I have worked around this using a semaphore (the semaphore is created using a protected type) around the assignment of packets: lock semaphore assign packet unlock semaphore This technique has proven reliable in production code, but I don't find it to be very "clean". Suggestions? Here is a subset of my packet implementation: package NPUnetworkPacketUtil is type aPacketNPU is private; private protected type aRefCounterNPU is procedure PlaseHoldNPU; procedure ReleaseHoldNPU( lastHoldNPU : out boolean ); private referenceCountNPU : Natural := 0; end aRefCounterNPU; type aPacketBufNPU( bufSizeNPU : Positive ); type aPacketBUfPtrNPU is accesss all aPacketBufNPU; type aPacketNPU is new Ada.Finalization.Controlled with record packetBufPtrNPU : aPacketBufPtrNPU; end record; procedure Initialize( object : in out aPacketNPU ); procedure Adjust( object : in out aPacketNPU ); procedure Finalize( object : in out aPacketNPU ); type aPacketBufNPU( bufSizeNPU : Positive ) is limited record dataBufferNPU : aliased aDataArrayNPU( 1 .. bufSizeNPU ); holdLockNPU : aRefCounterNPU; end record; end NPUnetworkPacketUtil ; package body NPUnetworkPacketUtil is protected body aRefCounterNPU is procedure PlaceHoldNPU is begin referenceCountNPU := referenceCountNPU + 1; end PlaceHoldNPU; procedure ReleaseHoldNPU( lastHoldNPU : out boolean ) is begin referenceCountNPU := referenceCountNPU - 1; lastHoldNPU := referenceCountNPU = 0; end ReleaseHoldNPU; end aRefCounterNPU; procedure Initialize( object : in out aPacketNPU ) is begin object.packetBufPtrNPU := null; end Initialize; procedure Adjust( object : in out aPacketNPU ) is begin if object.packetBufPtrNPU /= null then packetBufPtrNPU.holdLockNPU.PlaceHoldNPU; end if; end Adjust; procedure Finalize( object : in out aPacketNPU ) is lastHold : boolean; begin if object.packetBufPtrNPU /= null then packetBufNPU.holdLockNPU.ReleaseHoldNPU( lastHold ); if lastHold then -- Take action to put buffer in the free pool end if; end if; end Finalize; end NPUnetworkPacketUtil; Thank's in advance, SteveD ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE @ 2001-01-15 1:06 ` Nick Roberts 2001-01-15 3:17 ` Robert Dewar 2001-01-16 3:53 ` DuckE 2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist 2001-02-02 21:38 ` Niklas Holsti 2 siblings, 2 replies; 36+ messages in thread From: Nick Roberts @ 2001-01-15 1:06 UTC (permalink / raw) Please find attached my first quick attempt at a slightly neater solution. It's untested, so don't say I didn't warn you! The essential idea is that the task reading the socket does something like this: loop get length of buffer call Create to allocate a buffer in the queue (and in memory) read data into buffer call Commit to allow other tasks to obtain the buffer end loop Each task handling messages does the following: loop call Obtain to get an unprocessed buffer process the buffer as required call Delete to release the buffer (from the queue and memory) end loop Does this vaguely cut it? I use the trick of passing out a 'token' from Create and Obtain, which is passed into Commit or Delete to identify the buffer in the queue. Create and Obtain are both entries: Create blocks whilst the queue is full; Obtain blocks whilst there are no buffers in the queue awaiting processing. There can be any number of message-handling tasks, as they will be arbitrated between properly by their calls to Obtain. Of course, the call to Commit is very like clearing a semaphore to permit the second phase of processing of a buffer. Now I come to think of it, buffers are obtained from the queue in no particular order, so 'queue' is the wrong term, really. Perhaps Protected_Array_Queueing isn't really the right name for this package. Maybe Buffer_Pooling or Buffer_Distribution would be better. (Or Grab_Bag? ;-) -- Nick Roberts http://www.AdaOS.org "DuckE" <nospam_steved94@home.com> wrote in message news:cd%76.260429$U46.8278617@news1.sttls1.wa.home.com... > I have an application that receives a streams of data from TCP/IP sockets. > The stream of data is separated into "packets" each beginning with a 32 bit > length value. > ... ===== -- (c) 2000 Nicholas James Roberts -- All rights in this work are hereby granted into the PUBLIC DOMAIN -- by the author. The author asserts his moral rights over this work. generic type Datum_Type is private; package Protected_Array_Queueing is type Data_Array is array (Positive range <>) of Datum_Type; type Array_Access is access Data_Array; type Buffer_Token is private; -- Convenience declarations: type Array_Access_Array is array (Positive range <>) of Array_Access; type Boolean_Array is array (Positive range <>) of Boolean; protected type Buffer_Queue (Capacity: Natural) is entry Create (Length: in Natural; Token: out Buffer_Token; Buffer: out Array_Access); procedure Commit (Token: in Buffer_Token); entry Obtain (Token: out Buffer_Token; Buffer: out Array_Access); procedure Delete (Token: in Buffer_Token); procedure Reset; private Queue: Array_Access_Array(1..Capacity); Allocated: Boolean_Array(1..Capacity) := (others => False); Available: Boolean_Array(1..Capacity) := (others => False); Create_Here: Positive := 1; Obtain_Here: Positive := 1; Alloc_Count: Natural := 0; Avail_Count: Natural := 0; end Buffer_Queue; Invalid_Token: exception; private type Buffer_Token is new Positive; end Protected_Array_Queueing; ===== with Unchecked_Deallocation; package body Protected_Array_Queueing is procedure Free is new Unchecked_Deallocation(Data_Array,Array_Access); protected body Buffer_Queue is function Next (Here: in Positive) return Positive is begin if Here = Capacity then return 1; else return Here+1; end if; end Next; entry Create (Length: in Natural; Token: out Buffer_Token; Buffer: out Array_Access) when Alloc_Count < Capacity is begin while Allocated(Create_Here) loop Create_Here := Next(Create_Here); end loop; Token := Buffer_Token(Create_Here); Buffer := new Data_Array(1..Length); Queue(Create_Here) := Buffer; Alloc_Count := Alloc_Count+1; Allocated(Create_Here) := True; Available(Create_Here) := False; end Create; procedure Commit (Token: in Buffer_Token) is Commit_Here: Positive range 1..Capacity := Positive(Token); begin if not Allocated(Commit_Here) then raise Invalid_Token; end if; if not Available(Commit_Here) then Available(Commit_Here) := True; Avail_Count := Avail_Count+1; end if; end Commit; entry Obtain (Token: out Buffer_Token; Buffer: out Array_Access) when Avail_Count > 0 is begin while not Available(Obtain_Here) loop Obtain_Here := Next(Obtain_Here); end loop; Token := Buffer_Token(Obtain_Here); Buffer := Queue(Obtain_Here); Avail_Count := Avail_Count-1; Available(Obtain_Here) := False; end Obtain; procedure Delete (Token: in Buffer_Token) is Delete_Here: Positive range 1..Capacity := Positive(Token); begin if not Allocated(Delete_Here) then raise Invalid_Token; end if; Free(Queue(Delete_Here)); -- Queue(Delete_Here) := null; if Available(Delete_Here) then Avail_Count := Avail_Count-1; end if; Allocated(Delete_Here) := False; Alloc_Count := Alloc_Count-1; end Delete; procedure Reset is begin for i in 1..Capacity loop Free(Queue(i)); -- Queue(i) := null; end loop; Allocated := (others => False); Available := (others => False); Create_Here := 1; -- not really necessary Obtain_Here := 1; -- not really necessary Alloc_Count := 0; Avail_Count := 0; end Reset; end Buffer_Queue; end Protected_Array_Queueing; ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts @ 2001-01-15 3:17 ` Robert Dewar 2001-01-16 3:53 ` DuckE 1 sibling, 0 replies; 36+ messages in thread From: Robert Dewar @ 2001-01-15 3:17 UTC (permalink / raw) In article <93ti8b$bjpps$1@ID-25716.news.dfncis.de>, "Nick Roberts" <nickroberts@callnetuk.com> wrote: > -- (c) 2000 Nicholas James Roberts > -- All rights in this work are hereby granted into the PUBLIC > -- DOMAIN by the author. The author asserts his moral rights > -- over this work. This is about the most confusing copyright notice I have seen. The first line is straightforward, and seems to be asserting a copyright interest. The second statement contradicts this by saying it is in the public domain. The only way something is in the public domain is if the author specificially give up the copyright. Once something is in the public domain, the author no longer has any rights over it. The third sentence may have some significance in the EU, but in the US, it hs meaningless. The only rights of an author are those granted by congress under the copyright act. And we are confused as to whether this work is copyrighted or not. The best advice reacting to this notice is to assume that the copyright is fully in effect, and that this work should not be copied or otherwise infringed on. I am not sure that is the intent, but no other interpretation is legally safe. It all goes to show that in any case you should not trust the notices you find in software units, the copyright status is not formally affected by such notices in any case (though in a court case, the existence of such a statement may be used as evidence, for instance in this case, if someone does infringe the copyright, then as a defendant, they could try to persaude a jury that the work was indeed in the public domain, and if the jury was convinced that would be that :-) Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts 2001-01-15 3:17 ` Robert Dewar @ 2001-01-16 3:53 ` DuckE 2001-01-17 15:42 ` Nick Roberts 1 sibling, 1 reply; 36+ messages in thread From: DuckE @ 2001-01-16 3:53 UTC (permalink / raw) "Nick Roberts" <nickroberts@callnetuk.com> wrote in message news:93ti8b$bjpps$1@ID-25716.news.dfncis.de... > Please find attached my first quick attempt at a slightly neater solution. > It's untested, so don't say I didn't warn you! > > The essential idea is that the task reading the socket does something like > this: > > loop > get length of buffer > call Create to allocate a buffer in the queue (and in memory) > read data into buffer > call Commit to allow other tasks to obtain the buffer > end loop > > Each task handling messages does the following: > > loop > call Obtain to get an unprocessed buffer > process the buffer as required > call Delete to release the buffer (from the queue and memory) > end loop > > Does this vaguely cut it? No. One of the things I'm attempting to avoid (which is perhaps creating some difficulty) is dynamic allocation and deallocation at runtime. Perhaps I cut out too much implementation. What you will find below is a more complete sample. As you will see below I set up a table containing packets of different sizes. When a request is made for a new packet "NewPacketNPU( size )" the list is searched for the smallest available packet to meet the request. To the user of this it's associated modules using packets is simple: packet := NewPacketNPU( maxPacketSize ); PutNPU( packet, integerValue ); PutNPU( packet, floatValue ); FinishPacketNPU( packet ); SendPacketTGM( service, packet ); With no concern of memory leaks. SteveD -- Network Packet Utility -- This module contains routines for manipulating "network packets". -- The network packet type "aPacketNPU" is limited private and defined -- within this module. -- -- Functions are provided to "Put" data to a packet and to "Get" data -- from a packet. A primative set of data types are defined with get -- and put operations overloaded for each of these types. -- -- A task safe data packet pool is also maintained by this module. -- WITH Ada.Finalization; WITH Interfaces.C; WITH System; WITH BDTbaseDataTypes; USE BDTbaseDataTypes; PACKAGE NPUnetworkPacketUtil IS -- packetOverflowNPU is raised if there is an attempt to store more data into -- a packet than the size of the buffer allows. -- packetUnderflowNPU is raised if there is an attempt to read past the end -- of the packet. packetUnderflowNPU : EXCEPTION; packetOverflowNPU : EXCEPTION; noAvailablePacketsNPU : EXCEPTION; packetTooBigNPU : EXCEPTION; -- In the TimberGrafx protocol each message is sent with a command code -- to a node address. SUBTYPE aCommandCodeNPU IS aUInt16NPU; TYPE aNodeAddressNPU IS PRIVATE; TYPE aPacketNPU IS PRIVATE; package C renames Interfaces.C; TYPE aDataArrayNPU IS ARRAY( Positive RANGE <> ) OF ALIASED C.Char; -- Gets a new packet from the available packets that is a size greater than -- or equal to the size given by packetSizeNPU. -- The "get" operation places a "hold" on the entry. -- If no packets are available raises the exception: noAvailablePacketsNPU FUNCTION NewPacketNPU( packetSizeNPU : Natural ) RETURN aPacketNPU; -- Release a packet by assigning to Null FUNCTION NullPacketNPU RETURN aPacketNPU; PRIVATE PROCEDURE ResetPacketToHeaderNPU( packetNPU : aPacketNPU ); TYPE aNodeAddressNPU IS NEW aUInt16NPU; broadcastAddressNPU : CONSTANT aNodeAddressNPU := 16#FFFF#; routerAddressNPU : CONSTANT aNodeAddressNPU := 0; PROTECTED TYPE aRefCounterNPU IS PROCEDURE PlaceHoldNPU; PROCEDURE ReleaseHoldNPU( lastHoldNPU : out BOOLEAN ); PRIVATE referenceCountNPU : Natural := 0; END aRefCounterNPU; -- NOTE: All references in the public portion of is module refer to packets as if they -- were all data. Internally dataBufferNPU reserves headerLengthNPU bytes at the beginning -- of the data array for the header. headerLengthNPU : CONSTANT := 8; -- size of packet header TYPE aPacketBufNPU( bufSizeNPU : Positive ); TYPE aPacketBufPtrNPU IS ACCESS ALL aPacketBufNPU; TYPE aPacketNPU IS NEW Ada.Finalization.Controlled WITH RECORD packetBufPtrNPU : aPacketBufPtrNPU; END RECORD; PROCEDURE Initialize( object : in out aPacketNPU ); PROCEDURE Adjust( object : in out aPacketNPU ); PROCEDURE Finalize( object : in out aPacketNPU ); TYPE aPacketBufNPU( bufSizeNPU : Positive ) IS LIMITED RECORD dataBufferNPU : aliased aDataArrayNPU(1..bufSizeNPU); -- Buffered data nbBytesNPU : Natural := 0; -- Bytes currently in the buffer positionNPU : Positive := 1; -- Position where next data is to be stored nextPacketNPU : aPacketBufPtrNPU := NULL; -- Pointer for keeping buffers in a linked list holdLockNPU : aRefCounterNPU; -- Reference counter for the packet buffer packetFinishedNPU : BOOLEAN := FALSE; -- Packet has been finished, for sending END RECORD; END NPUnetworkPacketUtil; WITH Interfaces.C; WITH System; WITH Unchecked_Conversion; WITH Ada.Strings; WITH Ada.Strings.Fixed; WITH BDTbaseDataTypes; USE BDTbaseDataTypes; PACKAGE BODY NPUnetworkPacketUtil IS PACKAGE Fixed RENAMES Ada.Strings.Fixed; PACKAGE Strings RENAMES Ada.Strings; -------------------------------------------------------------------------- ------ -- -- The reference count is put inside a protected type to make it task safe. -- PROTECTED BODY aRefCounterNPU IS PROCEDURE PlaceHoldNPU IS BEGIN referenceCountNPU := referenceCountNPU + 1; END PlaceHoldNPU; PROCEDURE ReleaseHoldNPU( lastHoldNPU : out BOOLEAN ) IS BEGIN referenceCountNPU := referenceCountNPU - 1; lastHoldNPU := referenceCountNPU = 0; END ReleaseHoldNPU; END aRefCounterNPU; -------------------------------------------------------------------------- -------------- -- -- Keep a table of free packet lists. All socket communications use these packets -- The number of entries in each list may grow based on demand until the limit is reached TYPE anAvailablePacketEntry IS RECORD packets : aPacketBufPtrNPU := NULL; -- Pointer to list of unallocated packets of this size packetSize : Natural; -- Size of packets in this list nbAllocPackets : Natural; -- Nb of packets to allocated of this size maxNbPackets : Natural; -- Max nb of packets to allocate of this size END RECORD; TYPE anAvailablePacketTable IS ARRAY( Positive RANGE <> ) OF anAvailablePacketEntry; availablePacketTable : anAvailablePacketTable := ( 1 => ( NULL, 2**5, 0, 64 ), -- 32 2 => ( NULL, 2**6, 0, 32 ), -- 64 3 => ( NULL, 2**7, 0, 32 ), -- 128 4 => ( NULL, 2**8, 0, 16 ), -- 256 5 => ( NULL, 2**9, 0, 16 ), -- 512 6 => ( NULL, 2**10, 0, 16 ), -- 1024 7 => ( NULL, 2**11, 0, 16 ), -- 2048 8 => ( NULL, 2**12, 0, 16 ), -- 4096 9 => ( NULL, 2**13, 0, 16 ), -- 8192 10 => ( NULL, 2**14, 0, 16 ), -- 16384 11 => ( NULL, 2**15, 0, 16 ), -- 32768 12 => ( NULL, 2**16, 0, 16 ), -- 65536 13 => ( NULL, 2**17, 0, 16 ), -- 131072 14 => ( NULL, 2**18, 0, 16 ), -- 262144 15 => ( NULL, 2**19, 0, 16 ), -- 524288 16 => ( NULL, 2**20, 0, 16 ) -- 1048576 ); PROTECTED TYPE aMutex IS ENTRY LockMutex; PROCEDURE UnlockMutex; PRIVATE isLocked : BOOLEAN := FALSE; END aMutex; PROTECTED BODY aMutex IS ENTRY LockMutex WHEN NOT isLocked IS BEGIN isLocked := TRUE; END LockMutex; PROCEDURE UnlockMutex IS BEGIN isLocked := FALSE; END UnlockMutex; END aMutex; tableProtect : ARRAY ( availablePacketTable'RANGE ) OF aMutex; -- Gets a new packet from the available packets that is a size greater than -- or equal to the size given by packetSizeNPU. -- The "get" operation places a "hold" on the entry. FUNCTION NewPacketNPU( packetSizeNPU : Natural ) RETURN aPacketNPU IS newPacket : aPacketNPU; retPtr : aPacketBufPtrNPU RENAMES newPacket.packetBufPtrNPU; actualSize : Natural := packetSizeNPU + headerLengthNPU; BEGIN retPtr := NULL; TableSearch: FOR ii IN availablePacketTable'RANGE LOOP DECLARE tableEntry : anAvailablePacketEntry RENAMES availablePacketTable( ii ); BEGIN IF tableEntry.packetSize > actualSize THEN tableProtect( ii ).LockMutex; IF tableEntry.packets /= NULL THEN retPtr := tableEntry.packets; tableEntry.packets := tableEntry.packets.nextPacketNPU; retPtr.nextPacketNPU := NULL; retPtr.holdLockNPU.PlaceHoldNPU; ELSIF tableEntry.nbAllocPackets < tableEntry.maxNbPackets THEN tableEntry.nbAllocPackets := tableEntry.nbAllocPackets + 1; retPtr := NEW aPacketBufNPU( tableEntry.packetSize ); retPtr.holdLockNPU.PlaceHoldNPU; END IF; tableProtect( ii ).UnlockMutex; EXIT tableSearch; END IF; END; END LOOP tableSearch; IF retPtr /= NULL THEN RETURN newPacket; ELSE RAISE noAvailablePacketsNPU; END IF; END NewPacketNPU; -- Places an additional "hold" on an entry that was obtained using -- "NewPacketNPU" PROCEDURE HoldPacketBuf( packetBufNPU : aPacketBufPtrNPU ) IS BEGIN packetBufNPU.holdLockNPU.PlaceHoldNPU; END HoldPacketBuf; -- Removes the "hold" on an entry. When all holds are removed the -- entry automatically returns to the free pool. PROCEDURE ReleasePacketBuf( packetBufNPU : in out aPacketBufPtrNPU ) IS lastHold : BOOLEAN; BEGIN IF packetBufNPU /= NULL THEN packetBufNPU.holdLockNPU.ReleaseHoldNPU( lastHold ); IF lastHold THEN TableSearch: FOR ii IN availablePacketTable'RANGE LOOP DECLARE tableEntry : anAvailablePacketEntry RENAMES availablePacketTable( ii ); BEGIN IF tableEntry.packetSize = packetBufNPU.bufSizeNPU THEN tableProtect( ii ).LockMutex; packetBufNPU.nextPacketNPU := tableEntry.packets; tableEntry.packets := packetBufNPU; packetBufNPU := NULL; tableProtect( ii ).UnlockMutex; EXIT tableSearch; END IF; END; END LOOP tableSearch; END IF; END IF; END ReleasePacketBuf; PROCEDURE Initialize( object : in out aPacketNPU ) IS BEGIN object.packetBufPtrNPU := NULL; END Initialize; PROCEDURE Adjust( object : in out aPacketNPU ) IS BEGIN IF object.packetBufPtrNPU /= NULL THEN HoldPacketBuf( object.packetBufPtrNPU ); END IF; END Adjust; PROCEDURE Finalize( object : in out aPacketNPU ) IS BEGIN IF object.packetBufPtrNPU /= NULL THEN ReleasePacketBuf( object.packetBufPtrNPU ); END IF; END Finalize; FUNCTION NullPacketNPU RETURN aPacketNPU IS packet : aPacketNPU; BEGIN RETURN packet; END NullPacketNPU; END NPUnetworkPacketUtil; ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-16 3:53 ` DuckE @ 2001-01-17 15:42 ` Nick Roberts 2001-01-20 18:16 ` DuckE 0 siblings, 1 reply; 36+ messages in thread From: Nick Roberts @ 2001-01-17 15:42 UTC (permalink / raw) Steve, what you're doing IS dynamic run-time allocation! The only difference is that you are doing it yourself, rather than getting Ada (or its runtime system) to do it for you. In this case, the problem of buffer allocation is 'orthogonal' to the problem of the synchronisation of tasks in passing data to one another through a buffer queue (perhaps 'pool' would be a better name then 'queue'). If you need to replace the default Ada allocation system with one of your own (e.g. for reasons of speed), you can do so by modifying my solution in two ways: (a) you can use "for Array_Access'Storage_Pool use My_Fast_Pool;" and then implement your own storage pool, My_Fast_Pool, according to RM95 13.11; (b) you can have a fixed-size byte array (preferably as a component inside the protected type Buffer_Queue, I think), and allocate and deallocate bytes within this array (doing so inside the protected entry Create and procedures Delete and Reset, to prevent inter-task interference), perhaps using the 'binary chop' scheme you use at the moment. As to writing data into the buffers (and then reading it back out), I'm pretty certain you want to use streams, instead of doing all the hard work yourself. See RM95 13.13. I hope this helps. (Am I missing something?*) PS: Purely out of idle curiosity, does your identifier style come from Smalltalk? (Or Modula?) Also, have you considered using UDP instead of TCP? -- Nick Roberts http://www.AdaOS.org *Yes I know, but am I missing something in Steve's problem? ;-) ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-17 15:42 ` Nick Roberts @ 2001-01-20 18:16 ` DuckE 2001-01-20 19:16 ` Robert Dewar 2001-01-22 0:16 ` mark_lundquist 0 siblings, 2 replies; 36+ messages in thread From: DuckE @ 2001-01-20 18:16 UTC (permalink / raw) "Nick Roberts" <nickroberts@callnetuk.com> wrote in message news:94563n$cb6kp$1@ID-25716.news.dfncis.de... > Steve, what you're doing IS dynamic run-time allocation! The only difference > is that you are doing it yourself, rather than getting Ada (or its runtime > system) to do it for you. > > In this case, the problem of buffer allocation is 'orthogonal' to the > problem of the synchronisation of tasks in passing data to one another > through a buffer queue (perhaps 'pool' would be a better name then 'queue'). > If I the data was only being referenced by one task at a time, I would agree. But to expand a little on my example, we have code that does something like: packet := NewPacketNPU( 10000 ); PutNPU( packet, value1 ); PutNPU( packet, value2 ); SendPacketTGM( port1, packet ); SendPacketTGM( port2, packet ); SendPacketTGM( port3, packet ); In this arrangement the packet is sent to three separate tasks, and may only be released when all three are no longer referencing the data. The reason I chose not to use Ada serialization, is that items are inserted into the packet in "network byte order". Unfortunately in Ada 95 the 'input and 'output attributes are pre-defined for the built in data types, so I have no control over byte ordering. I know that GNAT works around this when you use their DSA, but they do so by using a "special" version of the RTL that makes ALL streams in network byte order. In my opinion this is one of the weak points of Ada 95. It would have been better to not have the 'input and 'output pre-defined for built in types (as a part of the language) but to include a package for defining these attributes. That way an arbitrary representation of built in types could be used with streams when desired. SteveD ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-20 18:16 ` DuckE @ 2001-01-20 19:16 ` Robert Dewar 2001-01-21 1:28 ` DuckE 2001-01-21 16:53 ` Nick Roberts 2001-01-22 0:16 ` mark_lundquist 1 sibling, 2 replies; 36+ messages in thread From: Robert Dewar @ 2001-01-20 19:16 UTC (permalink / raw) In article <0Cka6.290338$U46.9207275@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > In my opinion this is one of the weak points of Ada 95. It > would have been better to not have the 'input and 'output > pre-defined for built in types (as a part of the language) > but to include a package for defining these > attributes. That way an arbitrary representation of built in > types could be used with streams when desired. I don't see your point here. Surely you are not arguing in favor of REQUIRING people to define their own stream attributes for types, that would be a huge pain for the most common use of stream attributes. There are two possibilities 1. You want to control stream behavior on a type by type basis. This you can do perfectly fine, by just avoiding built in types like Integer, which is good practice anyway, and then define the stream attributes to work however you want. 2. You want to control stream attributes globally (as is permitted in GNAT by replacing the System.Stream_Attributes unit), but you seem to say in the same message that you do NOT like the fact that in GNAT this approach results in the default routines applying to everything. It really seems like Ada 95 does EXACTLY the right think in the terms you have layed out here, you will have to be a lot clearer in making your acase that something is missing. Perhaps you can give at least a sketch of what you would like to see. From where I sit, it seems like your problem is reasonable, and easily addressed with the current language features, and i can't see any addition to these features which would be helpful in this particular case. Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-20 19:16 ` Robert Dewar @ 2001-01-21 1:28 ` DuckE 2001-01-21 16:04 ` Robert Dewar 2001-01-21 16:53 ` Nick Roberts 1 sibling, 1 reply; 36+ messages in thread From: DuckE @ 2001-01-21 1:28 UTC (permalink / raw) "Robert Dewar" <robert_dewar@my-deja.com> wrote in message news:94co6t$v27$1@nnrp1.deja.com... > In article <0Cka6.290338$U46.9207275@news1.sttls1.wa.home.com>, > "DuckE" <nospam_steved94@home.com> wrote: > > In my opinion this is one of the weak points of Ada 95. It > > would have been better to not have the 'input and 'output > > pre-defined for built in types (as a part of the language) > > but to include a package for defining these > > attributes. That way an arbitrary representation of built in > > types could be used with streams when desired. > > > I don't see your point here. Surely you are not arguing in > favor of REQUIRING people to define their own stream attributes > for types, that would be a huge pain for the most common use > of stream attributes. No I'm not in favor of requiring people to define their own stream attributes. > > There are two possibilities > > 1. You want to control stream behavior on a type by type basis. > This you can do perfectly fine, by just avoiding built in types > like Integer, which is good practice anyway, and then define > the stream attributes to work however you want. > > 2. You want to control stream attributes globally (as is > permitted in GNAT by replacing the System.Stream_Attributes > unit), but you seem to say in the same message that you do NOT > like the fact that in GNAT this approach results in the default > routines applying to everything. > I believe there's a third: 3. You want to control stream behavior on a type by type basis for all types including built in types. You also include a package containing streaming definitions for built in types that may be included using a WITH statement. This behavior would be more consistent with operation of functions like "sin" and "cos" that are not pre-defined, but included in a standard package. > It really seems like Ada 95 does EXACTLY the right think in the > terms you have layed out here, you will have to be a lot > clearer in making your acase that something is missing. Perhaps > you can give at least a sketch of what you would like to see. > Perhaps I would like to see something like: package Ada.Streams.Built_In_Types is -- -- Define 'Input, 'Output for built in types -- end Ada.Streams.Built_In_Types; And then in my code I have the control to create: package Steves_Streaming_For_Built_In_Types is -- -- Define 'Input, 'Output for built in types -- end Steves_Streaming_For_Built_In_Types; > From where I sit, it seems like your problem is reasonable, > and easily addressed with the current language features, and > i can't see any addition to these features which would be > helpful in this particular case. > For me it's easier to just stay away from streaming. For one thing, the behavior is implementation dependent. For another, I have been quite effective at getting things done without it. > > Sent via Deja.com > http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 1:28 ` DuckE @ 2001-01-21 16:04 ` Robert Dewar 2001-01-21 23:23 ` DuckE 2001-01-22 0:35 ` Built-in types (was " mark_lundquist 0 siblings, 2 replies; 36+ messages in thread From: Robert Dewar @ 2001-01-21 16:04 UTC (permalink / raw) In article <tXqa6.290632$U46.9271836@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > 3. You want to control stream behavior on a type by type > basis for all types including built in types. I don't see the point in adding a rather complex feature to the language whose only purpose is to encourage increased usage of bulit in primitive types, when we generally want to discourage such use. Carefully written Ada programs should not use the built-in types in any case. Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 16:04 ` Robert Dewar @ 2001-01-21 23:23 ` DuckE 2001-01-22 0:28 ` mark_lundquist 2001-01-22 1:51 ` Robert Dewar 2001-01-22 0:35 ` Built-in types (was " mark_lundquist 1 sibling, 2 replies; 36+ messages in thread From: DuckE @ 2001-01-21 23:23 UTC (permalink / raw) "Robert Dewar" <robert_dewar@my-deja.com> wrote in message news:94f1a8$k9r$1@nnrp1.deja.com... > In article <tXqa6.290632$U46.9271836@news1.sttls1.wa.home.com>, > "DuckE" <nospam_steved94@home.com> wrote: > > > 3. You want to control stream behavior on a type by type > > basis for all types including built in types. > > I don't see the point in adding a rather complex feature to > the language whose only purpose is to encourage increased > usage of bulit in primitive types, when we generally want > to discourage such use. Carefully written Ada programs should > not use the built-in types in any case. > After a little more reflection it occurs to me that what I really want is for the format of data on a stream to be dependent on the stream, or at least be capable of being dependent on the stream. For example, within one application I may want to stream information to a network in big endian format and stream information to files in little endian format. From what I understand (I may certainly be wrong) I cannot do this in Ada. If I want this functionality I must resort to C++. SteveD > > Sent via Deja.com > http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 23:23 ` DuckE @ 2001-01-22 0:28 ` mark_lundquist 2001-01-22 1:51 ` Robert Dewar 1 sibling, 0 replies; 36+ messages in thread From: mark_lundquist @ 2001-01-22 0:28 UTC (permalink / raw) In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > > > After a little more reflection it occurs to me that what I really want is > for the format of data on a stream to be dependent on the stream, or at > least be capable of being dependent on the stream. Yes... > > For example, within one application I may want to stream information to a > network in big endian format and stream information to files in little > endian format. From what I understand (I may certainly be wrong) I cannot > do this in Ada. Certainly you can! You do it by creating a new type derived from Ada.Streams.Root_Stream_Type (or one of its descendants) and overriding its primitives (like Read and Write). > If I want this functionality I must resort to C++. > Ye gads! :-) :-) Mark Lundquist Rational Software Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 23:23 ` DuckE 2001-01-22 0:28 ` mark_lundquist @ 2001-01-22 1:51 ` Robert Dewar 2001-01-23 2:36 ` DuckE 1 sibling, 1 reply; 36+ messages in thread From: Robert Dewar @ 2001-01-22 1:51 UTC (permalink / raw) In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > For example, within one application I may want to stream > information to a network in big endian format and stream > information to files in little endian format. From what I > understand (I may certainly be wrong) I cannot do this in > Ada. If I want this functionality I must resort to C++. Sure you can do this in Ada, just define two types (use derived types if you want to be able to convert between them) and specify different stream routines for the two types (or sets of types). To what feature are you referring in C++ here that will help you solve this feature. I am unaware of any feature in standard C++ that would provide any automatic solution, but I certainly don't know all of C++ :-) Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-22 1:51 ` Robert Dewar @ 2001-01-23 2:36 ` DuckE 0 siblings, 0 replies; 36+ messages in thread From: DuckE @ 2001-01-23 2:36 UTC (permalink / raw) "Robert Dewar" <robert_dewar@my-deja.com> wrote in message news:94g3n9$g2p$1@nnrp1.deja.com... > In article <CbKa6.294821$U46.9394163@news1.sttls1.wa.home.com>, > "DuckE" <nospam_steved94@home.com> wrote: > > For example, within one application I may want to stream > > information to a network in big endian format and stream > > information to files in little endian format. From what I > > understand (I may certainly be wrong) I cannot do this in > > Ada. If I want this functionality I must resort to C++. > > Sure you can do this in Ada, just define two types (use > derived types if you want to be able to convert between them) > and specify different stream routines for the two types (or > sets of types). I stand corrected. I see that I can derive different types from Root_Stream_Type that permit the different behavior. But... I still think that the inability to define the ordering for built in types is a limitation. If this limitation were not present then a special version of library would not be required for GLADE. SteveD ^ permalink raw reply [flat|nested] 36+ messages in thread
* Built-in types (was Re: How can I avoid Using a Semaphore? 2001-01-21 16:04 ` Robert Dewar 2001-01-21 23:23 ` DuckE @ 2001-01-22 0:35 ` mark_lundquist 2001-01-22 1:54 ` Robert Dewar 1 sibling, 1 reply; 36+ messages in thread From: mark_lundquist @ 2001-01-22 0:35 UTC (permalink / raw) In article <94f1a8$k9r$1@nnrp1.deja.com>, Robert Dewar <robert_dewar@my-deja.com> wrote: > > Carefully written Ada programs should > not use the built-in types in any case. > That seems a little broad... When a careful Ada programmer writes 'Integer', he's saying that he understands the things about Integer that are implementation-defined and that those things are "don't cares" for him in this instance. It's not careless to say that and mean it. Need I elaborate? (I don't feel like a lot of typing this afternoon :-) -- mark Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? 2001-01-22 0:35 ` Built-in types (was " mark_lundquist @ 2001-01-22 1:54 ` Robert Dewar 2001-01-22 16:18 ` mark_lundquist 0 siblings, 1 reply; 36+ messages in thread From: Robert Dewar @ 2001-01-22 1:54 UTC (permalink / raw) In article <94fv9d$cjt$1@nnrp1.deja.com>, mark_lundquist@my-deja.com wrote: > In article <94f1a8$k9r$1@nnrp1.deja.com>, > Robert Dewar <robert_dewar@my-deja.com> wrote: > > > > Carefully written Ada programs should > > not use the built-in types in any case. > > > > That seems a little broad... > > When a careful Ada programmer writes 'Integer', he's saying > that he understands the things about Integer that are > implementation-defined and that those things are "don't > cares" for him in this instance. It's not careless to say > that and mean it. It is never actively *useful* to be able to do this, since you certainly have *some* requirements on any type you supply, and you may as well make them explicit. The trouble is that 90% of programmers writing Integer explicitly do NOT know what they are saying, and make a mess. That is why most coding standards wisely suggest not using type Integer. There are some exceptions, e.g. as the subscript of the standard type String, and you cannot get away from this built in type, because of library usage. P.S. Jean Ichbiah feels it was a bad mistake to have had the type Standard.String depend on Integer in this way, but it was too late to change. Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? 2001-01-22 1:54 ` Robert Dewar @ 2001-01-22 16:18 ` mark_lundquist 2001-01-22 17:20 ` Robert Dewar 0 siblings, 1 reply; 36+ messages in thread From: mark_lundquist @ 2001-01-22 16:18 UTC (permalink / raw) In article <94g3tf$gb9$1@nnrp1.deja.com>, Robert Dewar <robert_dewar@my-deja.com> wrote: > In article <94fv9d$cjt$1@nnrp1.deja.com>, > mark_lundquist@my-deja.com wrote: > > > > When a careful Ada programmer writes 'Integer', he's saying > > that he understands the things about Integer that are > > implementation-defined and that those things are "don't > > cares" for him in this instance. It's not careless to say > > that and mean it. > > It is never actively *useful* to be able to do this, since > you certainly have *some* requirements on any type you supply, > and you may as well make them explicit. Couldn't it be that my only requirement is that this be (using the example of integer types) the "whatever integer"? If that's my only requirement, then I'm being explicit about it when I write "Integer", because that's what Integer is supposed to be -- the "whatever integer". Anything else that I might specify is in fact *not* a requirement for me. (Let's see, just for integer types, what can the programmer specify? There's base range, size, alignment, stream I/O attributes... anything else?) > > The trouble is that 90% of programmers writing Integer > explicitly do NOT know what they are saying, and make a mess. > That is why most coding standards wisely suggest not using > type Integer. Well that's just it... it seems like if the programmer is sharp enough to specify all this stuff, then he also ought to be sharp enough to know when he means the "whatever" types and to use them when that's what he means. I suppose if it were a choice between the programmer blindly using Integer for everything (considerations of scalar abstraction aside), and blindly specifying everything because a style guide told him to do so, then I guess I'd prefer the latter (but not by much; see below...) However, that is a truly bonehead operating level and if these were really the only alternatives I doubt I'd want that programmer writing code for anything I cared about! :-) I mean, if you're going to go to the trouble to make a style guide that tells them to specify down to the gn@t'$ @$$ whether they depend on it or not, and expect them to follow it, then is it really that hard to teach them what Integer means? Then give advice with some substance, like "don't write a record component of type Integer if you're going to apply a representation clause" -- in which case you know your code will still compile if it's ported to another platform. You may or may not care about slightly different behavior, but you do care that it compile! :-) Is it OK to use the predefined Float type? :-) Suppose I nail down the precision and/or range to something I think makes sense for a particular architecture... might that not result in less-than-optimal performance if my code is ported to joe random architecture? So that's the whole point of having the "whatever" types. You need to be able to say "whatever". The issue is that people know when they're saying "whatever" and that they don't say it when they don't mean it. There was a thread here last year, in which someone was lamenting that Ada's integer types were not as "portable" as Java's because the language doesn't nail standardize the sizes/ranges. I argued that (a) there are different kinds of portability, and (b) of the two kinds relevant to the argument, Java provides one, and Ada provides both, but that (c) the objector was looking in the wrong place in Ada for the Java-style portable integer types -- the right place is not the Standard integer types but the ones in package Interfaces. Once again, you want to be able to say "whatever". Now, I do have a beef with overspecification, because it obscures. I'm always looking for communication of design intent. So if I see an integer type declared, and there's no abstraction involved, and we're nailing down the size, then I say "OK, what intent is being captured here -- where are the bits that depend on this?" It's quite annoying when the answer is "Nothing really depends on it, we just specified because it's bad not to specify everything". > There are some exceptions, e.g. as the subscript > of the standard type String, and you cannot get away from this > built in type, because of library usage. > > P.S. Jean Ichbiah feels it was a bad mistake to have had the > type Standard.String depend on Integer in this way, but it was > too late to change. Changing the subject, speaking of strings... it seems a little unfortunate that Ada95 has 3 kinds of strings (not counting the dimension of standard vs. wide), all with essentially the same interface, and no abstraction of that interface. As a result, generic programming across the string types doesn't come naturally, although I guess this can be more-or-less fixed outside the language with wrapper classes. Best Regards, mark Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? 2001-01-22 16:18 ` mark_lundquist @ 2001-01-22 17:20 ` Robert Dewar 2001-01-22 23:17 ` Mark Lundquist 0 siblings, 1 reply; 36+ messages in thread From: Robert Dewar @ 2001-01-22 17:20 UTC (permalink / raw) In article <94hmgo$o2k$1@nnrp1.deja.com>, mark_lundquist@my-deja.com wrote: > If that's my only > requirement, then I'm being explicit about it when I write > "Integer", because that's what Integer is supposed to be -- > the "whatever integer". In this very unlikely scenario, I would suggest writing type My_Int is new Integer; -- Use standard default (and presumably efficient) integer so that if there are porting problems, or if you do need to specify additional attributes, then it is easily done without major rewriting. > (Let's see, just for integer types, what can the programmer > specify? There's base range, size, alignment, stream I/O > attributes... anything else?) Yes, there are other things, but the point is that we are specifically talking here about a complaint that you can NOT specify them for the standard type Integer. That's what this thread is about. It is curious logic to be in a position of saying 1. I want to use Integer when I don't want to specify any additional stuff. 2. It is annoying that for type Integer, I cannot specify additional stuff that makes little sense to me! > Well that's just it... it seems like if the programmer is > sharp enough to specify all this stuff, then he also ought to > be sharp enough to know when he means the "whatever" types > and to use them when that's what he means. Please give a VERY clear example of why it is good EVER to use type Integer (other than when constrained by a library)? Even if efficiency is a concern, the proper approach is to write something like type Temp_Int is range min-required .. max-required; type My_Int is new Temp_Int'Base; Now use My_Int. That's really MUCH better than using Integer directly. > There was a thread here last year, in which someone was > lamenting that Ada's integer types were not as "portable" as > Java's because the language doesn't nail standardize the > sizes/ranges. Well this of course makes no sense. In Java you only have the standard types, so it is important to standardize them. In serious Ada, you don't use these standard types anyway, so the fact that they are not defined is not relevant to serious programs. Of course at this stage, it would in practice be fine to define type Integer as being always 32 bits, precisely because serious code is not going to use this much anyway. Well to be honest (as they say in the AARM), we can't do that *because* of the involvement of Integer with Standard.String. Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? 2001-01-22 17:20 ` Robert Dewar @ 2001-01-22 23:17 ` Mark Lundquist [not found] ` <m33deaaeks.fsf@ns40.infomatch.bc.ca> [not found] ` <94km00$bv8$1@nnrp1.deja.com> 0 siblings, 2 replies; 36+ messages in thread From: Mark Lundquist @ 2001-01-22 23:17 UTC (permalink / raw) Robert Dewar <robert_dewar@my-deja.com> wrote in message news:94hq56$rlv$1@nnrp1.deja.com... > In article <94hmgo$o2k$1@nnrp1.deja.com>, > mark_lundquist@my-deja.com wrote: > > If that's my only > > requirement, then I'm being explicit about it when I write > > "Integer", because that's what Integer is supposed to be -- > > the "whatever integer". > > In this very unlikely scenario, I would suggest writing > > type My_Int is new Integer; > -- Use standard default (and presumably efficient) integer > > so that if there are porting problems, or if you do need to > specify additional attributes, then it is easily done without > major rewriting. You've almost convinced me :-) First I would have to figure out how to think up type names that are not so cheesy as "My_Int" :-) And the names shouldn't "encode" specifics about their implementation properties, e.g. "Int16" is going to be a bad choice if I later decide it has to be 32 bits! Also -- in this example, you've defined your own integer type so that you have the flexibility to change it later. Isn't there still always a problem, in that you still assume that you'll always be able to use the same type for all the same things? Let's say you go and use My_Int everywhere instead of Integer. Now you find that for certain of those uses, the current definition of My_Int isn't going to cut it. Well, the ability to change the definition of My_Int only helps you if the new definition is also what you want for all the uses of My_Int. Maybe you can't really change My_Int in the way you require for a particular use, without screwing it up in its other uses. So My_Int is not a great Integer substitute. It's certainly no worse than Integer, but I'm not convinced that it's all *that* much better from the standpoint of portability, resilience to change etc. (remember, this is the case where I truly *don't* *care* about the unspecified properties). > > (Let's see, just for integer types, what can the programmer > > specify? There's base range, size, alignment, stream I/O > > attributes... anything else?) > > Yes, there are other things, What are they? I'm trying to see what it would take to define an integer type that is fully specified, leaving nothing to the implementation-specific defaults. (I think that leaves out anything specified by a pragma, right?) > but the point is that we are > specifically talking here about a complaint that you can NOT > specify them for the standard type Integer. That's what this > thread is about. *was* about, and then only briefly (_I_ was the one who changed the subject line...) :-) My original response was to your statement that carefully written Ada programs don't (within reeason of course) use predefined types. But you use Deja and it doesn't do a good job with changed subject lines :-) > > It is curious logic to be in a position of saying > > 1. I want to use Integer when I don't want to specify any > additional stuff. > > 2. It is annoying that for type Integer, I cannot specify > additional stuff > > that makes little sense to me! I said no such thing, nor implied it! What you say there is exactly the point I made to "DuckE" however many posts ago, when he said it was a weak point of Ada that you can't write 'Input etc. for the predefined types :-) > > > > Well that's just it... it seems like if the programmer is > > sharp enough to specify all this stuff, then he also ought to > > be sharp enough to know when he means the "whatever" types > > and to use them when that's what he means. > > Please give a VERY clear example of why it is good EVER to > use type Integer (other than when constrained by a library)? OK procedure Append ( This : in Element; Instances : Natural; -- subtype of Integer anyway To : Collection ); > > Even if efficiency is a concern, the proper approach is to > write something like > > type Temp_Int is range min-required .. max-required; > type My_Int is new Temp_Int'Base; > > Now use My_Int. That's really MUCH better than using Integer > directly. [OK, I'm not debating you right now :-) Just a question, because I really don't know...] Why did you derive My_Int from Temp_Int, instead of defining it as you did Temp_Int? [OK, I'm debating you again :-)] If I really have no requirements on the range, won't I just say type Temp_Int is range Integer'first .. Integer'last; ??? (I suppose there *might* be occasions where I have no requirements on the range, but where that might someday change...) OTOH, if I nail it down to something else, am I not saying that I want constraint checks if this is ported to an architecture where overflow won't take of it? > > > > There was a thread here last year, in which someone was > > lamenting that Ada's integer types were not as "portable" as > > Java's because the language doesn't nail standardize the > > sizes/ranges. > > Well this of course makes no sense. of course... > In Java you only have the > standard types, so it is important to standardize them. True, if you can't define your own elementary types then the standard ones ought to be standardized. Also, Java is meant to run on one machine (the JVM), so in a sense the standard types are defined the way they are because they're natural for the target machine. ^ permalink raw reply [flat|nested] 36+ messages in thread
[parent not found: <m33deaaeks.fsf@ns40.infomatch.bc.ca>]
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? [not found] ` <m33deaaeks.fsf@ns40.infomatch.bc.ca> @ 2001-02-02 22:01 ` Mark Lundquist 0 siblings, 0 replies; 36+ messages in thread From: Mark Lundquist @ 2001-02-02 22:01 UTC (permalink / raw) Ray Blaak <blaak@infomatch.com> wrote in message news:m33deaaeks.fsf@ns40.infomatch.bc.ca... > "Mark Lundquist" <mark@rational.com> writes: > > > > First I would have to figure out how to think up type names that are not so > > cheesy as "My_Int" :-) And the names shouldn't "encode" specifics about > > their implementation properties, e.g. "Int16" > > Well, you try to have a name that indicates what it is to be used for, about, > etc. e.g, > > type Instance_Count is new Natural; > > Such names should be independent of the specifics of the type itself. > > Note that you would also have the very important benefit of not accidentially > mixing up various different "whatever" integers. Hi Ray, What we're debating is what to do after all the reasonable scalar abstraction is done, if indeed there is anything left at that point. It's felt by many that it is a mistake to create a new type for every last thing under the sun (a mistake characteristic of the "wild-eyed proselyte" stage, it goes along with making everything a task :-)) Dewar asked for a counterexample, and the one I gave was of an STL-style collection insert operation that creates multiple copies of a value. This is just the kind of situation where creating a new type as you describe above is exactly what you don't want to do, because it adds absolutely no benefit whatsoever -- the only effect is to force a lot of explicit conversions. What you want is the "whatever integer", and I think Integer is fine for this because that is the meaning of Integer, while Dewar thinks I should define the "whatever integer" type explicitly. But Dewar's way does not result in gratuitous explicit conversions, because as this is intentionally the "whatever integer" type, it would be used anywhere "whatever" is needed (which certainly will not be everywhere an integer type is needed, so there will still be conversions, but those would be required anyway whether you write it his way or my way). > > > Also -- in this example, you've defined your own integer type so that you > > have the flexibility to change it later. Isn't there still always a problem, > > in that you still assume that you'll always be able to use the same type for > > all the same things? Let's say you go and use My_Int everywhere instead of > > Integer. Now you find that for certain of those uses, the current definition > > of My_Int isn't going to cut it. Well, the ability to change the definition > > of My_Int only helps you if the new definition is also what you want for all > > the uses of My_Int. > > You have the exact problem if you use the "whatever" Integer. As soon as some > of the uses differ from the "whatever" usage, then you have to rename things > anyway. Yes sir, that's absolutely right -- you have the same problem! The point I was trying to make (and didn't make very well :-) was not that Integer makes it any better, but that My_Int *doesn't* make it any better. Really, the problem with what I wrote was that I contradicted myself -- if indeed all the uses of "whatever integer" don't care, then they cannot possibly be broken if the definition changes for the sake of one usage that suddenly starts to care. But as you point out, the right solution is not to change the definition anyway, it's to use a different type. Changing the definition only obscures the code, since now we have a documented intent of "don't care" even as it now does care. So My_Int is not better with respect to "resilience to change". ^ permalink raw reply [flat|nested] 36+ messages in thread
[parent not found: <94km00$bv8$1@nnrp1.deja.com>]
* Re: Built-in types (was Re: How can I avoid Using a Semaphore? [not found] ` <94km00$bv8$1@nnrp1.deja.com> @ 2001-02-02 22:03 ` Mark Lundquist 0 siblings, 0 replies; 36+ messages in thread From: Mark Lundquist @ 2001-02-02 22:03 UTC (permalink / raw) Robert Dewar <robert_dewar@my-deja.com> wrote in message news:94km00$bv8$1@nnrp1.deja.com... > In article <94ifq8$uu$1@usenet.rational.com>, > "Mark Lundquist" <mark@rational.com> wrote: > > It's certainly no worse than Integer, but I'm not > > convinced that it's all *that* much better from the > > standpoint of > > portability, resilience to change etc. (remember, this is the > > case where I > > truly *don't* *care* about the unspecified properties). > > The point is that it emphasizes to the reader what is going on, > and indeed it is more portable than Integer, if for example, > the range is greater than 16 bits (remember that that is all > you can depend on from type Integer). If you need it to be "portable" in this aspect, then you do "care", and you should not use Integer which means "don't care". But I am talking about when you -- one more time :-) -- don't care. > > The trouble once again with using naked Integer is that I > cannot tell *why* you made this choice, and likely the reason > is just incompetence :-) Yeah, probably so :-) But I can't see how overspecification leaves the reader any less blind to the author's intent. How is the reader to distinguish specification of things you are depending on from that of things that you don't depend on? > > > > type that is fully specified, leaving nothing to the > > implementation-specific defaults. > > Such as the representation in bits, which can NOT be > specified??? Of course not. Read carefully, I said "leaving nothing to the implementation-specific *defaults*" (if you can't specify it, it's not a default, it's just implementation-specific). Once again, what are all the things that can be specified? I said what I thought after consulting the RM, and you said there were more things that I missed -- what are they? And in your standard technique, do you define all those things for your "My_Int"? If not, why not? > > > Why did you derive My_Int from Temp_Int, instead of defining > > it as you did Temp_Int? > > You completely missed the point of my declarations, have a look > at them again! The 'Base is the WHOLE POINT of these > declarations. So perhaps you want to look again, and perhaps > your comments were based on not understanding the technique > here (which for me is an absolutely standard one). That's just the thing, I don't understand the technique :-). I admit to being clueless about it, and I would like to have someone explain it to me. > > > type Temp_Int is range Integer'first .. Integer'last; > > That's pointless, it is just equivalent to > > type Temp_Int is new Integer; Yes, just as I thought... that's why I elaborated, I'm trying to figure out at what point you object to Integer -- is it just that the range is not nailed to the floor? Best Regards Mark Lundquist ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-20 19:16 ` Robert Dewar 2001-01-21 1:28 ` DuckE @ 2001-01-21 16:53 ` Nick Roberts 2001-01-21 18:24 ` Robert Dewar 1 sibling, 1 reply; 36+ messages in thread From: Nick Roberts @ 2001-01-21 16:53 UTC (permalink / raw) I concur with Robert's comments on Ada's stream facilities. I would have thought some companies which sell Ada compilers might (depending on their clientele etc.) consider it a good idea to provide a facility like GNAT's for changing all the default representations to the network format, as well as (or by means of) providing something like System.Stream_Attributes. To solve your buffer synchronisation problem, Steve, please see the generic package spec attached. The idea here is that the packet picking task(s) does/do something like this: loop read the packet's length call Create to create a buffer of the correct length read the packet's data into the buffer call Dispatch to cause the buffer to be serviced (further calls to Dispatch on the buffer possible) end loop Each servicing task does something like this: loop call Obtain to get a buffer that needs a specific service perform the service (calls to Dispatch possible, to cause further servicing of the buffer) call Release to signal that the service has been completed end loop; A buffer is deleted automatically whenever a call to Release makes its Disp_Count go down to zero. This scheme has a lot of flexibility. It enables service tasks to dispatch a buffer for further processing. It enables several tasks to perform the same service, and it could enable one task to perform many services under some circumstances. It makes it possible to have several packet picking tasks, provided you ensure they actually pick the packets atomically. I have left the package body, and the details of implementation, to you. However, I've suggested that you would need two arrays, one for the allocation of buffers, and one for the allocation of 'dispatches'. Incidentally, I think you will need: type Array_Access is access all Data_Array; if you are going to use an internal array for the buffer data, instead of allocation with 'new'. The internal array will have to be aliased. Hope this is helpful, -- Nick Roberts http://www.AdaOS.org ===== generic type Datum_Type is private; type Service_Type is (<>); package Buffer_Distribution_Management is type Data_Array is array (Positive range <>) of Datum_Type; type Array_Access is access Data_Array; type Buffer_Token is private; type Dispatch_Token is private; -- Utility declarations (effectively private): type Buffer_Index is new Positive; type Dispatch_Index is new Positive; type Buffer_Descriptor is record Allocated: Boolean := False; Data: Array_Access; Disp_Count: Natural := 0; end record; type Dispatch_Descriptor is record Allocated: Boolean := False; Buffer: Buffer_Index; Service: Service_Type; end record; type Buffer_Array is (Buffer_Index range <>) of Buffer_Descriptor; type Dispatch_Array is (Dispatch_Index range <>) of Dispatch_Descriptor; -- The most important declaration for this package: protected type Buffer_Distributor (Buffer_Cap, Dispatch_Cap: Natural) is entry Create (Length: in Natural; Buffer: out Array_Access; Token: out Buffer_Token); procedure Delete (Token: in Buffer_Token); entry Dispatch (Token: in Buffer_Token; Service: in Service_Type); entry Obtain (Service: in Service_Type; Buffer: out Array_Access; Token: out Dispatch_Token); procedure Release (Token: in Dispatch_Token); procedure Reset; private Buffers: Buffer_Array (1..Buffer_Cap); Dispatches: Dispatch_Array (1..Dispatch_Cap); ... end Buffer_Distributor; private type Buffer_Token is new Buffer_Index; type Dispatch_Token is new Dispatch_Index; end Buffer_Distribution_Management; ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 16:53 ` Nick Roberts @ 2001-01-21 18:24 ` Robert Dewar 2001-01-23 0:21 ` Nick Roberts 0 siblings, 1 reply; 36+ messages in thread From: Robert Dewar @ 2001-01-21 18:24 UTC (permalink / raw) In article <94f577$d9s66$1@ID-25716.news.dfncis.de>, "Nick Roberts" <nickroberts@callnetuk.com> wrote: > I would have thought some companies which sell Ada compilers ^ other (than Ada Core Technologies) is presumably what you meant here. Naturally GNAT Professional does include this capability, just so that this is absolutely clear, and the need (and hence the reason that this facility is provided), comes from our customers who need to be able to use GLADE (Annex E capabilities) for heterogenous distribution. Probably since GNAT Professional is the only commercial compiler that provides Annex E support, the requirement is less significant for other technologies. Yes, I realize there are other uses of this capability, which is why we provided it in a generalized form, but they are not so compelling, since, as I pointed out in my earlier message, you can usually do what you want by avoiding the use of predefined types (which generally is a good idea in any case). Robert Dewar Ada Core Technologies Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-21 18:24 ` Robert Dewar @ 2001-01-23 0:21 ` Nick Roberts 0 siblings, 0 replies; 36+ messages in thread From: Nick Roberts @ 2001-01-23 0:21 UTC (permalink / raw) "Robert Dewar" <robert_dewar@my-deja.com> wrote in message news:94f9h7$qpk$1@nnrp1.deja.com... > > I would have thought some companies which sell Ada compilers > ^ > other (than Ada Core Technologies) > > is presumably what you meant here. Yes, that is what I meant. (Sorry :-) -- Nick Roberts ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? 2001-01-20 18:16 ` DuckE 2001-01-20 19:16 ` Robert Dewar @ 2001-01-22 0:16 ` mark_lundquist 1 sibling, 0 replies; 36+ messages in thread From: mark_lundquist @ 2001-01-22 0:16 UTC (permalink / raw) > In my opinion this is one of the weak points of Ada 95. It would have been > better to not have the 'input and 'output pre-defined for built in types (as > a part of the language) but to include a package for defining these > attributes. That way an arbitrary representation of built in types could be > used with streams when desired. Why don't you just derive from the predefined type, then override the stream attributes on your derived type? That doesn't seem like a huge inconvenience... OTOH, it seems like Ada is helping, not hurting, by supplying predefined implementations of those attributes for predefined types (for when you *don't* care how they are implemented!) Maybe I'm missing your point when you say this is a weak point...? If so, try again and I'll try to follow :-) Said another way, if you say you want different stream I/O methods for Integer than the predefined ones, what you really mean is that you don't want an Integer! :-) What you want is something that is just like an Integer but has different I/O methods. Mark Lundquist Rational Software Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts @ 2001-01-22 16:51 ` mark_lundquist 2001-01-23 6:02 ` DuckE 2001-02-02 21:38 ` Niklas Holsti 2 siblings, 1 reply; 36+ messages in thread From: mark_lundquist @ 2001-01-22 16:51 UTC (permalink / raw) Hey Steve, I'd like to take up your original question: "How can I avoid using a semaphore?" In article <cd%76.260429$U46.8278617@news1.sttls1.wa.home.com>, "DuckE" <nospam_steved94@home.com> wrote: > > To avoid memory leaks I am using a controlled type with reference counting > to implement my data buffer. Since multiple threads may simultaneously have > access to the buffer, I use a protected type for reference counting. > > Since I am using a protected type for reference counting, I cannot assign > packets within a protected type (to implement queue's of packets for > instance) since these assignments would be attempting to do a protected > operation within a protected type. I don't get it! Can you explain that? Are you talking about the "potentially blocking" rule? I don't see how the scenario you described would run afoul of that rule, and I couldn't find anything in your example code to help me understand what you meant... > > I have worked around this using a semaphore (the semaphore is created using > a protected type) around the assignment of packets: > > lock semaphore > assign packet > unlock semaphore I didn't see anything like that in your example -- it looked like you were using your Mutex type (or aMutex or whatever) to protect your free block lists. So help me understand more about this semaphore problem... In the meantime, a couple of notes: 1) You've said you want to avoid heap allocation -- is that for performance reasons? If so, do you know for sure that heap allocation is going to cause you to miss deadlines or cause a performance bottleneck? If you don't know for sure, you might just go ahead and write it using heap allocation and without all this extra complexity. Then, if that turns out to be not good enough, you can always implement your own allocation scheme (and the right way to encapsulate that is probably with your own Storage_Pool type -- it's easy and direct, no "magic" to worry about). 2) Also if you care about performance, implementing a mutex as a protected record is generally a case of "abstraction inversion" with an attendant performance penalty -- my guess is that that's going to hit you harder than heap allocation would. The Ada runtime is implementing protected records on top of mutexes and condition variables and stuff provided by the OS, and it's probably doing all kinds of checks for pending aborts and other stuff that it has to do, and all you want is a mutex! You might look into using the OS-supplied mutexes directly, *if* it turns out that's what you really need (needing locking to be primitive is often a red flag that some part of the design is "inside out"). 3) You have an array of free block lists, and a "parallel" array of mutexes associated with the free block lists. Doesn't that mean that you really want a mutex to be part of a free block list? 4) Just a style point here, but to me using Interfaces.C.Char to represent a byte or octet or whatever you want to call it, seems a little weird. I like to think that Interfaces.C is for interfacing to C. A better choice might be Interfaces.Unsigned_8. Anyway, hope you give some more detail about the semaphore issue... Best Regards, Mark Lundquist P.S. Your identifier style sucks. (Why mince words? :-) :-) :-) Sent via Deja.com http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist @ 2001-01-23 6:02 ` DuckE 2001-02-02 22:00 ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist 2001-02-02 22:18 ` How can I avoid Using a Semaphore? (long) Mark Lundquist 0 siblings, 2 replies; 36+ messages in thread From: DuckE @ 2001-01-23 6:02 UTC (permalink / raw) > > To avoid memory leaks I am using a controlled type with reference counting > > to implement my data buffer. Since multiple threads may simultaneously have > > access to the buffer, I use a protected type for reference counting. > > > > Since I am using a protected type for reference counting, I cannot assign > > packets within a protected type (to implement queue's of packets for > > instance) since these assignments would be attempting to do a protected > > operation within a protected type. > > I don't get it! Can you explain that? Are you talking about > the "potentially blocking" rule? I don't see how the scenario you > described would run afoul of that rule, and I couldn't find anything in > your example code to help me understand what you meant... This is exactly the rule I'm talking about. I have defined my protected type for reference counting (aRefCounterNPU) contained in the packet buffer (aPacketBufNPU). I put my reference counter inside of a protected type since different tasks may concurrently have references to the same packet buffer and may release them asynchronously. aPacketNPU is a controlled type containing a reference to a packet buffer (aPacketBufNPU) that invokes the "PlaceHoldNPU" and "ReleaseHoldNPU" procedures durning the "Adjust" and "Finalize" routines as packets are assigned and finalized. If it were permitted, I would use a protected object to contain my pool of available packets. Something like: PROTECTED TYPE Buffer_Manager IS FUNCTION New_Packet( packetSize : Positive ) RETURN aPacketNPU; PROCEDURE Free_Packet( packet : in out aPacketNPU ); END Buffer_Manager; But in implementing this buffer manager I would be performing assignments of packet buffers inside the protected type, and thus violate the potentially blocking rule. Am I missing something here? > > > > > I have worked around this using a semaphore (the semaphore is created using > > a protected type) around the assignment of packets: > > > > lock semaphore > > assign packet > > unlock semaphore > > I didn't see anything like that in your example -- it looked like you > were using your Mutex type (or aMutex or whatever) to protect your free > block lists. > In my example the routine NewPacketNPU may be called on by different tasks in order to obtain new packets, so access to the free list must be protected. But since assignment of entries from the list requires placing a hold on the entries taken from the list, I run into the potentially blocking rule. That was my reasoning when I wrote the code. But now I'm starting to think that I may be able to re-arrange things such that the reference count is adjusted outside of accessing the free lists, which would solve my problem. I'll have to look at this some more... I didn't include it in my example, but I run into a similar difficulty when I go to put packets into a queue. It seems that introducing that reference counter in the controlled type makes things tricky all around. > So help me understand more about this semaphore problem... > > In the meantime, a couple of notes: > > 1) You've said you want to avoid heap allocation -- is that for > performance reasons? If so, do you know for sure that heap allocation > is going to cause you to miss deadlines or cause a performance > bottleneck? If you don't know for sure, you might just go ahead and > write it using heap allocation and without all this extra complexity. > Then, if that turns out to be not good enough, you can always implement > your own allocation scheme (and the right way to encapsulate that is > probably with your own Storage_Pool type -- it's easy and direct, > no "magic" to worry about). This code is in a library module that is common to several pieces of software. It is one of those cases where adding a small degree of complexity may benefit the performance of several applications. > > 2) Also if you care about performance, implementing a mutex as a > protected record is generally a case of "abstraction inversion" with an > attendant performance penalty -- my guess is that that's going to hit > you harder than heap allocation would. The Ada runtime is implementing > protected records on top of mutexes and condition variables and stuff > provided by the OS, and it's probably doing all kinds of checks for > pending aborts and other stuff that it has to do, and all you want is a > mutex! You might look into using the OS-supplied mutexes directly, > *if* it turns out that's what you really need (needing locking to be > primitive is often a red flag that some part of the design is "inside > out"). That's why I posted this inquiry in the first place. > > 3) You have an array of free block lists, and a "parallel" array of > mutexes associated with the free block lists. Doesn't that mean that > you really want a mutex to be part of a free block list? > Perhaps, but as you'll notice I initialize my free block lists using: availablePacketTable : anAvailablePacketTable := ( 1 => ( NULL, 2**5, 0, 64 ), -- 32 2 => ( NULL, 2**6, 0, 32 ), -- 64 3 => ( NULL, 2**7, 0, 32 ), -- 128 4 => ( NULL, 2**8, 0, 16 ), -- 256 5 => ( NULL, 2**9, 0, 16 ), -- 512 6 => ( NULL, 2**10, 0, 16 ), -- 1024 7 => ( NULL, 2**11, 0, 16 ), -- 2048 8 => ( NULL, 2**12, 0, 16 ), -- 4096 9 => ( NULL, 2**13, 0, 16 ), -- 8192 10 => ( NULL, 2**14, 0, 16 ), -- 16384 11 => ( NULL, 2**15, 0, 16 ), -- 32768 12 => ( NULL, 2**16, 0, 16 ), -- 65536 13 => ( NULL, 2**17, 0, 16 ), -- 131072 14 => ( NULL, 2**18, 0, 16 ), -- 262144 15 => ( NULL, 2**19, 0, 16 ), -- 524288 16 => ( NULL, 2**20, 0, 16 ) -- 1048576 ); If I made the "mutex" a part of the record, how would it appear in this initializer? > 4) Just a style point here, but to me using Interfaces.C.Char to > represent a byte or octet or whatever you want to call it, seems a > little weird. I like to think that Interfaces.C is for interfacing to > C. A better choice might be Interfaces.Unsigned_8. As I recall this is just mating with the types used by the Win32Ada bindings. > > Anyway, hope you give some more detail about the semaphore issue... > > Best Regards, > Mark Lundquist > > P.S. Your identifier style sucks. (Why mince words? :-) :-) :-) Any style of code with which you are unfamiliar "sucks". Every time someone new comes to our group we hear the same comment. Usually it takes less than 2 weeks and they never know how they did without it. Thanks for your response. SteveD > > > Sent via Deja.com > http://www.deja.com/ ^ permalink raw reply [flat|nested] 36+ messages in thread
* Sucking (was Re: How can I avoid Using a Semaphore? (long)) 2001-01-23 6:02 ` DuckE @ 2001-02-02 22:00 ` Mark Lundquist 2001-02-03 1:44 ` Jeffrey Carter 2001-02-03 3:21 ` DuckE 2001-02-02 22:18 ` How can I avoid Using a Semaphore? (long) Mark Lundquist 1 sibling, 2 replies; 36+ messages in thread From: Mark Lundquist @ 2001-02-02 22:00 UTC (permalink / raw) DuckE <nospam_steved94@home.com> wrote in message news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com... > [Mark wrote:] > > > > P.S. Your identifier style sucks. (Why mince words? :-) :-) :-) > > Any style of code with which you are unfamiliar "sucks". Actually, no... :-) "This is unfamiliar", and "This sucks" are two distinctly different reactions :-) I have specific reasons for believing it sucks, which have nothing to do with unfamiliarity :-) You probably know most of them already, so unless someone wants to discuss it I won't go there :-). But what I presume you mean is that this style conveys benefits that I'm unable to appreciate without having actually worked with it for a period of time (approximately two weeks it, would appear :-). I'll just have to take your word for that! It seems clear enough what the style is... Each package has a full name, with an acronymic prefix. Then each identifier declared therein gets that same acronym as a suffix. OK... nope, sorry! :-) I think it would take me more than 2 weeks to forget how I got along without that... :-) The style of "aFoobar" and "anApteryx" for type names seems like a different form of the "The_Foobar" cop-out for parameter names -- both meant to spare us the trouble of thinking up a parameter name that would be more meaningful than just repeating the name of the type, am I right? (Interestingly, the orthography seems derived from the Smalltalk environment and the books by Adele Goldberg, et al... but in Smalltalk, the sense is completely the opposite: this style of naming is used not for types, but for method arguments, because since it's an untyped language you need a parameter name like "aList" as a cue to the reader that the actual is supposed to be of type List!) > Every time someone > new comes to our group we hear the same comment. Usually it takes less than > 2 weeks and they never know how they did without it. I just really dislike all identifier format conventions. That goes for Hungarian notation, "suffix inflectional", etc. I don't care if it's Subsaharan pluperfect transfusional or whatever, I give 'em all the heave-ho!! Just keep it natural. Yeah I know, that's just my personal preference... Like the pronunciation of "bona fide" [:-) :-)], it's ultimately a matter of taste... I used to use a format convention for identifiers, but I grew out of it. An aside, relating naming conventions to this idea of "class-oriented programming"... One of the supposed advantages of "member function" notation and distinguished-receiver syntax is that within a method, you don't have to qualify references to members of the current instance by some parameter name. It's considered lame and lowbrow and "procedural" to have to do that. Not too long ago, I was working with some C++ code where the developers had adopted a curious naming convention for member objects... they were all given names like "m_Foo", "m_Bar", where the "m_" stood for -- you guessed it -- "member". How bizarre to resort to a naming convention to work around what is supposed to be an advantage of the language. Even admitting that it isn't an advantage after all, writing "this->Foo" is so much more natural -- anyone can understand that without having to learn some convention! :-) :-) Best Regards, Mark ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long)) 2001-02-02 22:00 ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist @ 2001-02-03 1:44 ` Jeffrey Carter 2001-02-03 3:21 ` DuckE 1 sibling, 0 replies; 36+ messages in thread From: Jeffrey Carter @ 2001-02-03 1:44 UTC (permalink / raw) Mark Lundquist wrote: > The style of "aFoobar" and "anApteryx" for type names seems like a different > form of the "The_Foobar" cop-out for parameter names The first few letters of an identifier are the most important for recognition. If all your identifiers start with some kind of noise, be it "a", "The_", or the Hungarian notation crap, it makes your code harder to read. As we all know, that is A Bad Thing. Writing "aFoobar" and "anApteryx" in a language that allows underlines in identifiers is unwise. An underline between words makes them easier to read than just a case difference. Such a style in a case-insensitive language is even less wise. -- Jeff Carter "You tiny-brained wipers of other people's bottoms!" Monty Python & the Holy Grail ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long)) 2001-02-02 22:00 ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist 2001-02-03 1:44 ` Jeffrey Carter @ 2001-02-03 3:21 ` DuckE 2001-02-05 20:07 ` Mark Lundquist 1 sibling, 1 reply; 36+ messages in thread From: DuckE @ 2001-02-03 3:21 UTC (permalink / raw) > It seems clear enough what the style is... Each package has a full name, > with an acronymic prefix. Then each identifier declared therein gets that > same acronym as a suffix. OK... nope, sorry! :-) I think it would take me > more than 2 weeks to forget how I got along without that... :-) Our code started in a different language (EPascal) where external functions, procedures and type definitions were not easily discernable from local definitions. Knowing the origin of these definition "at a glance" without having to look it up has its advantages. In Ada, I could certainly see eliminating these acronyms in favor of qualifying these external definitions with their origins (ie: Ada.Text_Io.Put_Line ). > The style of "aFoobar" and "anApteryx" for type names seems like a different > form of the "The_Foobar" cop-out for parameter names -- both meant to spare > us the trouble of thinking up a parameter name that would be more meaningful > than just repeating the name of the type, am I right? Our use of "a" or "an" to start a type definition simply adds instant recognition of an identifier as a data type without regard to context. IMHO this is not much different than quickly identifying the start of a sentence with a capital letter. What these conventions really buy us is time. When I look at a block of code a great deal of information is available as hints from the coding convention that keep me from having to look elsewhere for definitions. [snip] > > Best Regards, > Mark > ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long)) 2001-02-03 3:21 ` DuckE @ 2001-02-05 20:07 ` Mark Lundquist 2001-02-06 7:16 ` Sven Nilsson 0 siblings, 1 reply; 36+ messages in thread From: Mark Lundquist @ 2001-02-05 20:07 UTC (permalink / raw) DuckE <nospam_steved94@home.com> wrote in message news:0PKe6.366080$U46.10801728@news1.sttls1.wa.home.com... > > Our code started in a different language (EPascal) where external functions, > procedures and type definitions were not easily discernable from local > definitions. Knowing the origin of these definition "at a glance" without > having to look it up has its advantages. > > In Ada, I could certainly see eliminating these acronyms in favor of > qualifying these external definitions with their origins (ie: > Ada.Text_Io.Put_Line ). There's an Ada style out there that you might find gives you the best of both... To use your code as an example, you would name your package Network_Packet_Utilities (since I'm writing it this time I get to insist on the underscores :-). Then in other units that with your package, you say package NPU renames Network_Packet_Utilites; Now you can use qualified names to explicate the name space relationships in the formal way rather than the ad hoc way of using format conventions, but it allows for a less prolix style :-). I haven't looked at a whole lot of the Ada code in the GNAT distribution, but I think I've seen that style used there, and I know it's used internally at Rational in places too. > > > The style of "aFoobar" and "anApteryx" for type names seems like a > different > > form of the "The_Foobar" cop-out for parameter names -- both meant to > spare > > us the trouble of thinking up a parameter name that would be more > meaningful > > than just repeating the name of the type, am I right? > > Our use of "a" or "an" to start a type definition simply adds instant > recognition of an identifier as a data type without regard to context. Well, I have to wonder of what use is that information ("this identifier names a type") apart from the context. If there is none, then *to*me* the "instant" recognition doesn't add value since I have to move immediately to making some use of that information, and that depends on the context anyway. (Your reply got me to thinking if there are any places in Ada where the fact that an identifier names a type is not manifest from the syntax. The only case I could think of was that of conversions. That's not saying you _shouldn't_ want "instant recognition", only that I can't relate to the reason why :-)). It can be fun and instructive to postulate variants of a language, just for the sake of argument :-). So I wonder if people who like instant recognition of types would be happier with an Ada in which occurences of a type names were all accompanied by the word "type", e.g. Foo : constant type Wumpus; type Wumpi is array (Blah range <>) of type Wumpus; Z := type Wumpus'(X + Y); (N.B. I am *not* advocating this... :-) :-) But anyway, would this provide the same level of satisfaction as building "this is a type" hints into identifiers? Some people (not I :-)) like to append "_Generic" or "_G" to generic unit declarations. In context of usage, "this is a generic" is even more apparent than "this is a type", since you can't do squat with a generic except instantiate it (or name it as a generic formal package, which looks just like an instantiation), where it's always preceded by "is new" (and "package", "procedure", or "function"). But one place that can get a little confusing is in the generic body itself. I've always sort of wished that generic bodies weren't identical to nongeneric bodies -- e.g. that you had to recapitulate the "generic" and the formal part in the body syntax. I usually do that in a comment (and then I have to accept the problem of keeping the body comment in sync with the spec). > IMHO > this is not much different than quickly identifying the start of a sentence > with a capital letter. More like the capitalization of nouns in German, I'd say :-) --mark P.S. One reason I find Ada style is so interesting is that it's the idea with Ada that the style of writing should be optimized in favor of readers rather than the writer (and "reader" of course includes the person of the "writer" in her role as a reader of her own code). So the question that immediately follows is "which reader", because you potentially have a diverse population of readers who differ in knowledge of Ada, knowledge of the problem domain, knowledge of the present source text itself (in regard to which each reader changes as their understanding increases), learning style, etc., and you're shooting for a "best fit" across all these. This relates to commenting style as well as "coding" style. Certainly it applies not only to Ada, but to programming in any language where you are attempting to be reader-friendly... ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: Sucking (was Re: How can I avoid Using a Semaphore? (long)) 2001-02-05 20:07 ` Mark Lundquist @ 2001-02-06 7:16 ` Sven Nilsson 0 siblings, 0 replies; 36+ messages in thread From: Sven Nilsson @ 2001-02-06 7:16 UTC (permalink / raw) New text follows below ;-) > There's an Ada style out there that you might find gives you the best of > both... To use your code as an example, you would name your package > Network_Packet_Utilities (since I'm writing it this time I get to insist on > the underscores :-). Then in other units that with your package, you say > > package NPU renames Network_Packet_Utilites; > > Now you can use qualified names to explicate the name space relationships in > the formal way rather than the ad hoc way of using format conventions, but > it allows for a less prolix style :-). I haven't looked at a whole lot of > the Ada code in the GNAT distribution, but I think I've seen that style used > there, and I know it's used internally at Rational in places too. We use it quite extensively as well, if mainly because we have a very complex system and package names tend to grow terribly long... > > > The style of "aFoobar" and "anApteryx" for type names seems like a > > > different > > > form of the "The_Foobar" cop-out for parameter names -- both meant to > > > spare > > > us the trouble of thinking up a parameter name that would be more > > > meaningful > > > than just repeating the name of the type, am I right? > > > > Our use of "a" or "an" to start a type definition simply adds instant > > recognition of an identifier as a data type without regard to context. At my department we (as in someone else about 6 years ago) solved this by enforcing coding rules that states that "all types shall be declared as T_XXX and all constants as C_XXX". This yields code that looks something like this: C_Max_Index : constant Natural := 25; type T_Index is new Natural range 0..C_Max_Index; procedure Foo(Index : in out T_Index); There you go! Instant recognition of what is a type, what is a constant and what is a parameter or variable or object. And you can even get it in context! > Well, I have to wonder of what use is that information ("this identifier > names a type") apart from the context. If there is none, then *to*me* the > "instant" recognition doesn't add value since I have to move immediately to > making some use of that information, and that depends on the context anyway. Actually, there is. Not if you are a compiler, of course, but if you try to read someone elses program thats written like this: function Return_Value_At_Index(Index : Index) return Index is I : Index := Index'First; begin ... end Return_Value_At_Index; That, ofcourse, won't compile as it stands, but people can get pretty imaginative trying to get around that because they want their parameter to be called something very similar to Index. > It can be fun and instructive to postulate variants of a language, just for > the sake of argument :-). So I wonder if people who like instant > recognition of types would be happier with an Ada in which occurences of a > type names were all accompanied by the word "type", e.g. > > Foo : constant type Wumpus; > type Wumpi is array (Blah range <>) of type Wumpus; > Z := type Wumpus'(X + Y); > > (N.B. I am *not* advocating this... :-) :-) But anyway, would this provide > the same level of satisfaction as building "this is a type" hints into > identifiers? That is a brilliant idea! I'll bring it up the next time we discuss coding rules... Oh and :-) to you too! > Some people (not I :-)) like to append "_Generic" or "_G" to generic unit > declarations. In context of usage, "this is a generic" is even more > apparent than "this is a type", since you can't do squat with a generic > except instantiate it (or name it as a generic formal package, which looks > just like an instantiation), where it's always preceded by "is new" (and > "package", "procedure", or "function"). But one place that can get a little > confusing is in the generic body itself. I've always sort of wished that > generic bodies weren't identical to nongeneric bodies -- e.g. that you had > to recapitulate the "generic" and the formal part in the body syntax. I > usually do that in a comment (and then I have to accept the problem of > keeping the body comment in sync with the spec). Ah, but when you're browsing through your library of packages, it can be very nice to see in the package name that it is generic. I guess you've never had to reuse someone elses code... > > IMHO > > this is not much different than quickly identifying the start of a > sentence > > with a capital letter. > > More like the capitalization of nouns in German, I'd say :-) > > --mark > > P.S. One reason I find Ada style is so interesting is that it's the idea > with Ada that the style of writing should be optimized in favor of readers > rather than the writer (and "reader" of course includes the person of the > "writer" in her role as a reader of her own code). So the question that > immediately follows is "which reader", because you potentially have a > diverse population of readers who differ in knowledge of Ada, knowledge of > the problem domain, knowledge of the present source text itself (in regard > to which each reader changes as their understanding increases), learning > style, etc., and you're shooting for a "best fit" across all these. This > relates to commenting style as well as "coding" style. Certainly it applies > not only to Ada, but to programming in any language where you are attempting > to be reader-friendly... I couldn't agree more! Our projects typically run over 3 to 5 years and in that time a lot of people will have left the actual implementation work and moved on to some sort of management. Having read-able code becomes extremly important in that perspective. Especially if you try to reuse code from a previous project. We have rather strict coding rules and naming conventions based on the Ada style guide and I can only say thank heavens for that! -Sven ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-23 6:02 ` DuckE 2001-02-02 22:00 ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist @ 2001-02-02 22:18 ` Mark Lundquist 2001-02-03 3:01 ` DuckE 1 sibling, 1 reply; 36+ messages in thread From: Mark Lundquist @ 2001-02-02 22:18 UTC (permalink / raw) Steve, sorry to take so long getting back to you. You probably have it all figured out by now... DuckE <nospam_steved94@home.com> wrote in message news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com... > >[mark wrote] > > I don't get it! Can you explain that? Are you talking about > > the "potentially blocking" rule? I don't see how the scenario you > > described would run afoul of that rule, and I couldn't find anything in > > your example code to help me understand what you meant... > > This is exactly the rule I'm talking about. Entries are potentially blocking, but protected subprograms are not. You don't need entries in your protected reference count, right? So you should be OK? > > > > 3) You have an array of free block lists, and a "parallel" array of > > mutexes associated with the free block lists. Doesn't that mean that > > you really want a mutex to be part of a free block list? > > > > Perhaps, but as you'll notice I initialize my free block lists using: > > availablePacketTable : anAvailablePacketTable := > ( 1 => ( NULL, 2**5, 0, 64 ), -- 32 > 2 => ( NULL, 2**6, 0, 32 ), -- 64 > 3 => ( NULL, 2**7, 0, 32 ), -- 128 > > If I made the "mutex" a part of the record, how would it appear in this > initializer? Well, it would look like something like: availablePacketTable : anAvailablePacketTable := ( 1 => Create_Packet_Table_Entry (Size => 2**5, Count => 64), 2 => Create_Packet_Table_Entry (Size => 2**6, Count => 32), . . . ); Best, Mark ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-02-02 22:18 ` How can I avoid Using a Semaphore? (long) Mark Lundquist @ 2001-02-03 3:01 ` DuckE 0 siblings, 0 replies; 36+ messages in thread From: DuckE @ 2001-02-03 3:01 UTC (permalink / raw) "Mark Lundquist" <mark@rational.com> wrote in message news:95fbn7$njb$1@usenet.rational.com... > Steve, sorry to take so long getting back to you. You probably have it all > figured out by now... > > DuckE <nospam_steved94@home.com> wrote in message > news:b89b6.298508$U46.9559869@news1.sttls1.wa.home.com... > > > > >[mark wrote] > > > I don't get it! Can you explain that? Are you talking about > > > the "potentially blocking" rule? I don't see how the scenario you > > > described would run afoul of that rule, and I couldn't find anything in > > > your example code to help me understand what you meant... > > > > This is exactly the rule I'm talking about. > > Entries are potentially blocking, but protected subprograms are not. You > don't > need entries in your protected reference count, right? So you should be OK? > Alas, I have been working under a misconception.... When I read: "During a protected action, it is a bounded error to invoke an operation that is potentially blocking", I incorrectly assumed this included anything that required mutual exclusion (such as protected procedures). On reviewing 9.5.1 of the RM I see that this is definitely NOT the case. In 9.5.1 the specific operations that are considered potentially blocking are listed. I re-wrote my packet buffer routine without the use of a semaphore. I was still somewhat concerned about protected operations performed within the controlled operations of my "Packet", but I now realize that there is no problem in this area. SteveD ^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: How can I avoid Using a Semaphore? (long) 2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts 2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist @ 2001-02-02 21:38 ` Niklas Holsti 2 siblings, 0 replies; 36+ messages in thread From: Niklas Holsti @ 2001-02-02 21:38 UTC (permalink / raw) Cc: Niklas Holsti DuckE wrote: > > I have an application that receives a streams of data from TCP/IP sockets. [ snip ] > > To avoid memory leaks I am using a controlled type with reference counting > to implement my data buffer. Since multiple threads may simultaneously have > access to the buffer, I use a protected type for reference counting. > > Since I am using a protected type for reference counting, I cannot assign > packets within a protected type (to implement queue's of packets for > instance) since these assignments would be attempting to do a protected > operation within a protected type. As I understand the LRM, you are allowed to use *other* protected objects from within a protected type. By LRM 9.5.1(15), a call on a protected subprogram is only considered potentially blocking if it is an "external" call and has the same target object as the action that performs the call. In your case, the caller (queue) and callee (reference counter) would be actions of different protected types, so the call would not be potentially blocking. Niklas Holsti Working at but not speaking for Space Systems Finland ^ permalink raw reply [flat|nested] 36+ messages in thread
* RE: How can I avoid Using a Semaphore? (long) @ 2001-02-07 21:55 Beard, Frank 0 siblings, 0 replies; 36+ messages in thread From: Beard, Frank @ 2001-02-07 21:55 UTC (permalink / raw) To: 'comp.lang.ada@ada.eu.org' So, according to section 9.5.1, doing I/O during a protected operation is NOT potentially blocking? For example, would it be permissible to do the following: protected body Protected_Something is procedure Do_Something (status : out Status_Type) is begin Ada.Text_Io.Open(file => file, mode => Ada.Text_Io.IN_FILE, name => "status_file", form => ""); Status_Io.Get(file => file, item => status); Ada.Text_Io.Close(file); end Do_Something; end Protected_Something; Frank -----Original Message----- From: DuckE [mailto:nospam_steved94@home.com] Sent: Friday, February 02, 2001 10:01 PM To: comp.lang.ada@ada.eu.org Subject: Re: How can I avoid Using a Semaphore? (long) On reviewing 9.5.1 of the RM I see that this is definitely NOT the case. In 9.5.1 the specific operations that are considered potentially blocking are listed. ^ permalink raw reply [flat|nested] 36+ messages in thread
* RE: How can I avoid Using a Semaphore? (long)
@ 2001-02-08 23:42 Beard, Frank
0 siblings, 0 replies; 36+ messages in thread
From: Beard, Frank @ 2001-02-08 23:42 UTC (permalink / raw)
To: 'comp.lang.ada@ada.eu.org'
It wasn't a conclusion, it was a question (hence
the question mark ('?') at the end of the sentence).
It was supposed to mean I was puzzled that I/O was
not potentially blocking. I thought I new it was
potentially blocking, but when I read 9.5.1 I quit
reading at 17 for some reason. I guess because it
started talking about bounded errors. For some
reason, it seemed like the next paragraph started
a new section.
I don't know, my brain was failing me. I was tired.
But thanks for responding. I would have gotten around
to re-reading it eventually, and hopefully I would
have noticed it the next time.
Thanks
Frank
-----Original Message-----
From: Robert Dewar [mailto:dewar@gnat.com]
> So, according to section 9.5.1, doing I/O during a protected
> operation is NOT potentially blocking?
How do you come to that odd (and wrong) conclusion :-)
^ permalink raw reply [flat|nested] 36+ messages in thread
end of thread, other threads:[~2001-02-08 23:42 UTC | newest] Thread overview: 36+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2001-01-13 16:18 How can I avoid Using a Semaphore? (long) DuckE 2001-01-15 1:06 ` How can I avoid Using a Semaphore? Nick Roberts 2001-01-15 3:17 ` Robert Dewar 2001-01-16 3:53 ` DuckE 2001-01-17 15:42 ` Nick Roberts 2001-01-20 18:16 ` DuckE 2001-01-20 19:16 ` Robert Dewar 2001-01-21 1:28 ` DuckE 2001-01-21 16:04 ` Robert Dewar 2001-01-21 23:23 ` DuckE 2001-01-22 0:28 ` mark_lundquist 2001-01-22 1:51 ` Robert Dewar 2001-01-23 2:36 ` DuckE 2001-01-22 0:35 ` Built-in types (was " mark_lundquist 2001-01-22 1:54 ` Robert Dewar 2001-01-22 16:18 ` mark_lundquist 2001-01-22 17:20 ` Robert Dewar 2001-01-22 23:17 ` Mark Lundquist [not found] ` <m33deaaeks.fsf@ns40.infomatch.bc.ca> 2001-02-02 22:01 ` Mark Lundquist [not found] ` <94km00$bv8$1@nnrp1.deja.com> 2001-02-02 22:03 ` Mark Lundquist 2001-01-21 16:53 ` Nick Roberts 2001-01-21 18:24 ` Robert Dewar 2001-01-23 0:21 ` Nick Roberts 2001-01-22 0:16 ` mark_lundquist 2001-01-22 16:51 ` How can I avoid Using a Semaphore? (long) mark_lundquist 2001-01-23 6:02 ` DuckE 2001-02-02 22:00 ` Sucking (was Re: How can I avoid Using a Semaphore? (long)) Mark Lundquist 2001-02-03 1:44 ` Jeffrey Carter 2001-02-03 3:21 ` DuckE 2001-02-05 20:07 ` Mark Lundquist 2001-02-06 7:16 ` Sven Nilsson 2001-02-02 22:18 ` How can I avoid Using a Semaphore? (long) Mark Lundquist 2001-02-03 3:01 ` DuckE 2001-02-02 21:38 ` Niklas Holsti -- strict thread matches above, loose matches on Subject: below -- 2001-02-07 21:55 Beard, Frank 2001-02-08 23:42 Beard, Frank
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox