[TUHS] Minimum Array Sizes in 16 bit C (was Maximum)

Luther Johnson luther.johnson at makerlisp.com
Sun Sep 29 08:50:10 AEST 2024


Or to your point, we have some of these problems no matter what, so
that's not a completely valid reason not to have some other facility, on
the basis of its cost profile, when other things already in, have
similar orders of costs.

On 09/28/2024 03:45 PM, Luther Johnson wrote:
> G. Branden,
>
> I get it. From your and Doug's responses, even O(n) baked-in costs can
> be a problem.
>
> On 09/28/2024 03:08 PM, Luther Johnson wrote:
>> "Classic C", K&R + void function return type, enumerations, and
>> structure passing/return, maybe a couple other things (some bug
>> fixes/stricter rules on use of members in structs and unions), has
>> this, I use a compiler from 1983 that lines up with an AT&T System V
>> document detailing updates to the language.
>>
>> I view these kinds of changes as incremental usability and
>> reliability fixes, well within the spirit and style, but just closing
>> loopholes or filling in gaps of things that ought to work together,
>> and could, without too much effort. But I agree, structures as
>> full-fledged citizens came late to K & R / Classic C.
>>
>> On 09/28/2024 11:46 AM, G. Branden Robinson wrote:
>>> Hi Luther,
>>>
>>> At 2024-09-28T10:47:44-0700, Luther Johnson wrote:
>>>> I don't know that structure copying breaks any complexity or bounds on
>>>> execution time rules. Many compilers may be different, but in the
>>>> generated code I've seen, when you pass in a structure to a function,
>>>> the receiving function copies it to the stack. In the portable C
>>>> compiler, when you return  a structure as a result, it is first copied
>>>> to a static area, a pointer to that area is returned, then the caller
>>>> copies that out to wherever it's meant to go, either a variable that's
>>>> being assigned (which could be on the stack or elsewhere), or to a
>>>> place on the stack that was reserved for it because that result will
>>>> now be an argument to another function to be called. So there's some
>>>> copying, but that's proportional to the size of the structure, it's
>>>> linear, and there's no dynamic memory allocation going on.
>>> I have no problem with this presentation, but recall the principle--the
>>> tenet--that Doug was upholding:
>>>
>>>>> At 2024-09-28T09:34:14-0400, Douglas McIlroy wrote:
>>>>>> This complaint overlooks one tenet of C: every operation in what
>>>>>> you call "language runtime" takes O(1) time. Dynamic memory
>>>>>> allocation is not such an operation.
>>> Even without dynamic memory allocation, if you did something linear,
>>> something O(n), it was a lose and a violation of the tenet.
>>>
>>> I can easily see the appeal of a language whose every operation really
>>> is O(1).  Once upon a time, a university course, or equivalent
>>> experience, in assembly language (on a CLEAN instruction set, not x86)
>>> is what taught you the virtues and drawbacks of thinking about and
>>> implementing things that way.  But my view is that C hasn't been one of
>>> those languages for a very long time, since before its initial ANSI
>>> standardization at the latest.
>>>
>>> At 2024-09-28T10:52:16-0700, Luther Johnson wrote:
>>>> In the compilers I'm talking about, you pass a structure by passing a
>>>> pointer to it - but the receiving function knows the argument is a
>>>> structure, and not a pointer to a structure, so it knows it needs to
>>>> use the pointer to copy to its own local version.
>>> It's my understanding that the ability to work with structs as
>>> first-class citizens in function calls, as parameters _or_ return
>>> types,
>>> was something fairly late to stabilize in C compilers. Second-hand, I
>>> gather that pre-standard C as told by K&R explicitly did _not_
>>> countenance this.  So a lot of early C code, including that in
>>> libraries, indirected nearly all struct access, even when read-only,
>>> through pointers.
>>>
>>> This is often a win, but not always.  A few minutes ago I shot off my
>>> mouth to this list about how much better the standard library design
>>> could have been if the return of structs by value had been supported
>>> much earlier.
>>>
>>> Our industry has, it seemss, been slow to appreciate the distinction
>>> between what C++ eventually came to explicitly call "copy" semantics
>>> and
>>> "move" semantics.  Rust's paradigmatic dedication to the concept of
>>> data
>>> "ownership" at last seems to be popularizing the practice of thinking
>>> about these things.  (For my part, I will forever hurl calumnies at
>>> computer architects who refer to copy operations as "MOV" or similar.
>>> If the operation doesn't destroy the source, it's not a move--I don't
>>> care how many thousands of pages of manuals Intel writes saying
>>> otherwise.  Even the RISC-V specs screw this up, I assume in a
>>> deliberate but embarrassing attempt to win mindshare among x86
>>> programmers who cling to this myth as they do so many others.)
>>>
>>> For a moment I considered giving credit to a virtuous few '80s C
>>> programmers who recognized that there was indeed no need to copy a
>>> struct upon passing it to a function if you knew the callee wasn't
>>> going
>>> to modify that struct...but we had a way of saying this, "const", and
>>> library writers of that era were infamously indifferent to using
>>> "const"
>>> in their APIs where it would have done good.  So, no, no credit.
>>>
>>> Here's a paragraph from a 1987 text I wish I'd read back then, or at
>>> any
>>> time before being exposed to C.
>>>
>>> "[Language] does not define how parameter passing is implemented.  A
>>> program is erroneous if it depends on a specific implementation method.
>>> The two obvious implementations are by copy and by reference. With an
>>> implementation that copies parameters, an `out` or `in out` actual
>>> parameter will not be updated until (normal) return from the
>>> subprogram.
>>> Therefore if the subprogram propagates an exception, the actual
>>> parameter will be unchanged.  This is clearly not the case when a
>>> reference implementation is used.  The difficulty with this
>>> vagueness in
>>> the definition of [language] is that it is quite awkward to be sure
>>> that
>>> a program is independent of the implementation method.  (You might
>>> wonder why the language does not define the implementation method.  The
>>> reason is that the copy mechanism is very inefficient with large
>>> parameters, whereas the reference mechanism is prohibitively expensive
>>> on distributed systems.)"[1]
>>>
>>> I admire the frankness.  It points the way forward to reasoned
>>> discussion of engineering tradeoffs, as opposed to programming language
>>> boosterism.  (By contrast, the trashing of boosters and their rhetoric
>>> is an obvious service to humanity.  See?  I'm charitable!)
>>>
>>> I concealed the name of the programming language because people have a
>>> tendency to unfairly disregard and denigrate it in spite of (or because
>>> of?) its many excellent properties and suitability for robust and
>>> reliable systems, in contrast to slovenly prototypes that minimize
>>> launch costs and impose negative externalities on users (and on anyone
>>> unlucky enough to be stuck supporting them).  But then again cowboy
>>> programmers and their managers likely don't read my drivel anyway.
>>> They're busy chasing AI money before the bubble bursts.
>>>
>>> Anyway--the language is Ada.
>>>
>>> Regards,
>>> Branden
>>>
>>> [1] Watt, Wichmann, Findlay.  _Ada Language and Methodology_.
>>>      Prentice-Hall, 1987, p. 395.
>>
>



More information about the TUHS mailing list