From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: a07f3367d7,b92b95c9b5585075 X-Google-Attributes: gida07f3367d7,public,usenet X-Google-NewGroupId: yes X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news3.google.com!feeder.news-service.com!proxad.net!feeder2-2.proxad.net!newsfeed.arcor.de!newsspool1.arcor-online.net!news.arcor.de.POSTED!not-for-mail Date: Sat, 13 Aug 2011 11:37:04 +0200 From: Georg Bauhaus User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2.18) Gecko/20110613 Thunderbird/3.1.11 MIME-Version: 1.0 Newsgroups: comp.lang.c++,comp.lang.ada Subject: Re: Why use C++? References: <1e292299-2cbe-4443-86f3-b19b8af50fff@c29g2000yqd.googlegroups.com> <1fd0cc9b-859d-428e-b68a-11e34de84225@gz10g2000vbb.googlegroups.com> <9ag33sFmuaU1@mid.individual.net> <1d8wyhvpcmpkd.ggiui9vebmtl.dlg@40tude.net> <150vz10ihvb5a.1lysmewa1muz4$.dlg@40tude.net> <1q4c610mmuxn7$.1k6s78wa0r8fj.dlg@40tude.net> <4e44e50a$0$7619$9b4e6d93@newsspool1.arcor-online.net> <4e4560e7$0$6546$9b4e6d93@newsspool4.arcor-online.net> In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Message-ID: <4e4645c0$0$7629$9b4e6d93@newsspool1.arcor-online.net> Organization: Arcor NNTP-Posting-Date: 13 Aug 2011 11:37:04 CEST NNTP-Posting-Host: 607e934e.newsspool1.arcor-online.net X-Trace: DXC=YaeT32I3\[1_A0jCfgHO6>ic==]BZ:af>4Fo<]lROoR1<`=YMgDjhg28V6?4Fa=5g;PCY\c7>ejV8[>g@JBWoL>2\JSORWB?Q30 X-Complaints-To: usenet-abuse@arcor.de Xref: g2news2.google.com comp.lang.c++:92676 comp.lang.ada:21567 Date: 2011-08-13T11:37:04+02:00 List-Id: On 12.08.11 21:51, Jed wrote: >> The general idea is that you start from the problem >> without giving thought to representation. Typically, >> without loss of efficiency. Compiler makers know a fair >> bit about good choice of representation. This means: >> Describe precisely what matters to your program, on >> any machine, without reference to any representation. >> Then, and only then, and only if necessary, throw in your >> knowledge of representation. > > That doesn't work when you do IO. Specifying representation when needed, and separate from the type declaration, works perfectly well for I/O. For I/O in particular! Short summary: Declaring a type for computation does *not* require specification of representation. However, should it become necessary to specify a representation of objects of a type, the programmer should be able to do so, but *not* by forcing the representation into every existing type. (Incidentally, bit-oriented, abstracting types (bit fields in C, std::bitset in C++, bit arrays in D, or packed arrays of Booleans in a host of Pascalish languages) don't make a language 4GL.) Examples of how omitting (implied) representation from type declaration works well with I/O. 1. (I/O As-is) Suppose I/O means writing to a particular address. There is an output port to write to. It has CHAR_BIT bits, and CHAR_BIT == 8. You want to write an object of type long which happens to consists of four octets. One approach is to write a function that shifts bits into a char object and then pushes this object out the port. Using the fundamental type system of C++, you need some size computations, at compile time, or by the programmer, so that the program will perform the right number of shifts, for a given implementation. With C++ and long, long[], etc, there are idioms. They typically use the sizeof operator, and division. The very same technique is available for objects declared of a type 1e0 .. 1e5 that does not mention any other type's name! The programmer may leave it to the compiler to choose a representation for objects of type 1e0 .. 1e5 that is best on the target hardware for computation. For I/O, the programmer again uses the type system and inquires of the type how many octets there are in the type. But! He does not have to name a type for the "computational objects", such as declaring them to be "long", he just lists the values that should be stored in objects of the type, and exactly these, no more, no less. In pseudo code, type T is exactly 1e0 .. 1e5. T obj. // representation left to the compiler // compute, compute, compute, ... then, for k in [0, octet_size(T)) do x <- shift_octet_from (obj@k), write_octet(x, port_address) done. Note the declaration of T does not mention the name of any existing type. In case range types are boring, here is another bare metal type: type T is exactly 1e0 .. 1e5 if T % 2 == 0. Very low level, fairly easy to compute, nothing like 4GL, and no mention of representation. 2. (Conversion) Suppose I/O means writing a number of structured objects to a stream. A program uses many structured objects in its inner loops, requiring high speed representations. For I/O, though, a different representation would be better, or is required. For the computation, simply declare the structure and let the compiler choose an efficient layout (type sizes, alignment). type R is record struct R { x, y, z : S; S x, y, z; t : TS; TS t; end record; }; In an I/O module, though, specify the layout as needed for I/O. Doing so will establish order and size of components. It all happens in the type system, the compiler does it, and the programmer does not have to write conversion functions: -- ... I/O interface ... private -- users of public type R need not be affected type R_for_IO is new R; -- same logical data as R for R_for_IO use record -- nothing at storage unit 0, padding Z at 1 range 0 .. 7; Y at 2 range 0 .. 7; X at 3 range 0 .. 7; -- 2 storage units padding, again T at 6 range 2 .. 13; end record; All that now needs to be done when writing objects to a stream is to apply a type conversion to the object to be output. Just an ordinary type conversion. Since the functions of the I/O interface deal with all this, the type conversion is never seen by users of "computational type" R.