Non-constant constant strings

R

Rick C. Hodgin

Kaz, I don't know about the history of C. Over time I've learned to use the
language and I have written a lot of code in it. I am currently working on a
large project written entirely in C. I understand most C code when I read it.
Much beyond a pointer to a pointer and my head starts to spin though. :)
I don't purport to be an expert in C standards. Never have been. Never will
be. I have no interest in becoming an expert in that. I came here asking for
something specific and no one had a solution for me, just workarounds. That
was, until this solution was introduced:
char* list[] = { "jjj", (char[]){"kkk"}}.

The following solves the problem, and is highly portable. Moreover, it has
basically the same structure and should compile to the same object code; it
just doesn't have the source-level "syntactic sugar":

char el0[] = "jjj";
char el1[] = "kkk";
char *list[] = { list_elem1, list_elem1 };

That solution was discussed. It is workable, but it is unmanageable because
the element block in question in my particular case is about 100 lines and
will change from time to time.
You do not have an actual "problem" here; you're just looking for how to do
something using the minimal number of keystrokes.

Correct. I have had a working work-around the entire time I've been
discussing this.
Also note that you could just waste a few bytes and do this, which also
works in pretty much any C dialect:
char list[][128] = {
"everything",
"is mutable now"
};

That solution was discussed. It is also workable, but it was undesirable
for me as it's clunky, wasteful, and so on.
(This program isn't targetting tiny embedded systems where every byte
counts, is it? It's a code generation tool that runs on developer machines
and build servers. It runs for a few milliseconds and then terminates,
freeing all of its memory to the OS.)

Yes. It's entirely on principle I rejected it, not mechanics.
The number of keystrokes you've wasted in this newsgroup outweighs
any savings by now from the syntactic sugar.

I found the solution I wanted, and learned many things in the process.
It was positive.
The approach you're taking of mutating global strings is an poor design for
what you're doing, based on a poor choice of programming language.

Kaz, you don't know what I'm doing on this project. You don't know any of
the details of what I'm doing. You don't have any idea of the size, scope,
or any aspect of its design, history, or anything else.

In short: You are not equipped to render a verdict like that.
A high school kid working in, say, Lisp, Python, Ruby or Perl would
have the project done already.

My project is done. I had a solution before I came here. I had a solution
about two weeks before I came here. I originally discussed this subject on
comp.os.ms-windows.programmer.win32 asking specifically for a Visual C++
extension, and after much discussion someone there suggested I try here.

It's purely a mental exercise. Mechanically it was solved the very hour I
first discovered that the char* list[] = { "one", "two", "three" }; were all
read-only. I just wrote a work-around. But, I also wanted to find out a
better way.
Yeah, minor issue: can't actually use the solution in one of the development
environments you use, and have been mentioning from the start.

I didn't say "minor issue" ... I said "totally separate issue". I did find
what I was looking for. It's now a shortcoming in Microsoft's product that
it is not supported, not a shortcoming in C.

Love you, Kaz. Keep on keeping on. :)

Best regards,
Rick C. Hodgin
 
J

James Kuyper

LOL! It's one extra null (beyond the "useful sentinel"), and it has the solid
purpose of not needing the extra comma.

If that's it's purpose, it fails to achieve it. It has one more comma
than the alternative he was describing, not one fewer:

const char *archiveFormats[] = {
#if CPIO_SUPPORTED
"cpio",
#endif
#if TAR_SUPPORTED
"tar",
#endif
#if ZIP_SUPPORTED
"ZIP",
#endif
#if APK_SUPPORTED
"apk",
#endif
null
};

That alternative is still ugly, and IMO, still a fairly convincing
argument for the convenience of allowing a terminal comma on a list.
However, it's also a real, if slight, improvement over your suggestion.
 
K

Kaz Kylheku

Also note that you could just waste a few bytes and do this, which also
works in pretty much any C dialect:
char list[][128] = {
"everything",
"is mutable now"
};

That solution was discussed. It is also workable, but it was undesirable
for me as it's clunky, wasteful, and so on.

That is nonsense. It's wasteful on a Commodore 64 from 1983.
It's wasteful on a PIC16 microcontroller, sure.

It's hardly wasteful in an environment in which every invocation of
your code-generation tool causes the attachment of many megabytes of shared
library material, and detachment thereof a fraction of a second later.
 
R

Rick C. Hodgin

const char *archiveFormats[] = {
#if CPIO_SUPPORTED
"cpio",
#endif
#if TAR_SUPPORTED
"tar",
#endif
#if ZIP_SUPPORTED
"ZIP",
#endif
#if APK_SUPPORTED
"apk",
#endif
null
};

That alternative is still ugly, and IMO, still a fairly convincing
argument for the convenience of allowing a terminal comma on a list.

I think all those #if..#endif blocks are ugly. It clutters the code and
makes it hard for me to read.
However, it's also a real, if slight, improvement over your suggestion.

It seems odd to me that developers would reject the trailing null solution
using existing C abilities, and instead ask that a trailing comma ability
be included to save the 4-bytes a typical 32-bit pointer would consume.
Most modern compilers align data on 2^N boundaries for speed anyway.

FWIW, I think the trailing null is the best current solution. And I like the
term sentinel. :) I would use it for variable code.

In moving forward, I would write some new ability to create the list properly,
giving the compiler a new ability to handle variable items:

char *archiveFormats[] =
{
#elementif CPIO_SUPPORTED "cpio"
#elementif TAR_SUPPORTED "tar"
#elementif ZIP_SUPPORTED "ZIP"
#elementif APK_SUPPORTED "apk"
null // Optional
};

A single-line pre-processor directive which adds an element if the token
is defined, and one that does not require any comma-based syntax. It also
provides the explicit and condensed documentation in source code that
only if those values are defined are they included, saving valuable
screen real-estate (especially on text-only displays). :)

Best regards,
Rick C. Hodgin
 
G

glen herrmannsfeldt

Interesting. To recap, my reasoning relates to the nature of
software and computers in general. They are just that: computers.
They take input, process it, and generate output. That, by
definition, means read-write. The only cases where I would like
to have something be read-only is when I explicitly cast for it,
indicating that this variable should not be modified. In that
way the compiler can help catch errors, as can the runtime
environment.
I believe everything should be read-write unless explicitly cast
otherwise.

There is a favorite related effect that goes back pretty much to
the beginning of Fortran. Unlike C, Fortran does not pass by value,
but (pretty much) either pass by reference or pass by value result.

If you pass a constant to a called subroutine, that subroutine
can (usually accidentaly) change the value of the constant.
That tends to make debugging complicated. The first I knew
that placed constants in read-only pages was VAX/VMS.

Note that C makes it difficult to modify numeric constants, as
the & operator doesn't apply to them, but string constants are
not so hard to modify, intentionally or not.

The early days of C were before paging systems were as popular
as now, and even then not all supplied the ability for user
code to make pages read only. (The OS would, of course, protect
its own code and data.)

Note that systems commonly only keep one copy of constants that
have the same value, so you might find the effect somewhere else
in the program, when 2+2 isn't 4 anymore.

In a large fraction of the cases where one wants to modify a
character value, the new length is different. C does supply a
way to initialize a character array of a specified length,
such that it can be modified. That might waste a little more
memory, but not as much as is wasted with this discussion.

I notice no comment about the %d method that I suggested, which
takes minimal programming work!

-- glen
 
R

Rick C. Hodgin

Also note that you could just waste a few bytes and do this, which also
works in pretty much any C dialect:
char list[][128] = {
"everything",
"is mutable now"
};
That solution was discussed. It is also workable, but it was undesirable
for me as it's clunky, wasteful, and so on.

That is nonsense. It's wasteful on a Commodore 64 from 1983.
It's wasteful on a PIC16 microcontroller, sure.

It's hardly wasteful in an environment in which every invocation of
your code-generation tool causes the attachment of many megabytes of shared
library material, and detachment thereof a fraction of a second later.

The phrase you're looking for there isn't "hardly wasteful," but "relatively
wasteful." Compared to the amount of resources used in common programs, it
is not relatively wasteful. However, it is, by definition, wasteful. It
reserves bytes that will never be used, and only take up space, and are not
needed by the application, and are actually nothing but total digital flotsam.
:) They are wasteful, by definition, and are not needed with the compound
literal ability Joe demonstrated.

Joe's solution is elegant, and exactly what I was looking for. It is not
wasteful, and it addresses the exact need I had, which was to include text
strings at compile time that can be later modified at runtime without any
re-allocation. I simply use what was defined in source code, and go.

That's elegant.

Maybe there's a way for me to link in an object file output from GCC for
this one part into my Visual Studio project. Then it would work in my
current VS/VC++ environment as well.

I appreciate all of your help, Kaz.

Best regards,
Rick C. Hodgin
 
G

glen herrmannsfeldt

(snip)
Understandably. I believe if you want something to be constant, you should
declare it as const, and then it is created at executable load time into an
area of memory which is explicitly marked read-only. It will signal a fault
when an attempt to write to it is made.

Sounds nice, but a large fraction of systems don't supply that
ability, and even when they do, there might be an unexpected overhead
to doing it.

As I said before, there are an infinite number of features that
could be added to a language. One has to narrow it down a little
bit when actually doing it.

-- glen
 
R

Rick C. Hodgin

Note that systems commonly only keep one copy of constants that
have the same value, so you might find the effect somewhere else
in the program, when 2+2 isn't 4 anymore.

It depends on the system. Many assembly instructions allow the encoding
of immediate data. This is typically sign-extended 8-bits, 16-bits, or
32-bits, though sometimes larger. As such, constants used in various C
source code lines may not refer back to memory locations, allocated in
read-only or read-write memory, or otherwise, but rather to a literal
component in the opcode. The compiler will make decisions based on nearby
usage of the same constant as to what's more advantageous. Sometimes
filling a register with the constant and referencing it is faster and
more desirable. Other times not. Throughout a single application the use
of constants will be variable on most modern CPUs. Some will come from
memory, others from direct inclusion in the instruction encoding.
In a large fraction of the cases where one wants to modify a
character value, the new length is different. C does supply a
way to initialize a character array of a specified length,
such that it can be modified. That might waste a little more
memory, but not as much as is wasted with this discussion.

Yes, but that does not cover all cases. In my case I explicitly allocate
a larger number of bytes than is required. My input string is something
like "[9999]" and I currently have only 812 items, so today it will always
only populate up to "[ 812]", but I leave room for expansion into the 1000s.
I notice no comment about the %d method that I suggested, which
takes minimal programming work!

I don't recall this one. I must have missed it. Can you repost?

Best regards,
Rick C. Hodgin
 
R

Rick C. Hodgin

Sounds nice, but a large fraction of systems don't supply that
ability, and even when they do, there might be an unexpected overhead
to doing it.

As I said before, there are an infinite number of features that
could be added to a language. One has to narrow it down a little
bit when actually doing it.

I appreciate your well thought out responses, Glen. I understand and agree.
The platform I would create will be new, meaning new code will be written
for it, or old code will be ported to it, and thereby tested.

My personal targets are also not all systems, but those most used today
for general purpose computing, namely x86 and ARM. I have goals of the new
programming language and developer GUI, along with new operating systems on
those platforms (Exodus for x86, Armodus for ARM). I eventually desire to
create 64-bit versions called Exodus-64 and Armodus-64. We'll see though.
I've been 18 years on these projects and life's whatevers have come at me.
It may well be only a pipe dream by a little man with big dreams and no
ability to complete them. Then again, it may not be.

In my goals, both x86 and ARM offer memory protection abilities.

Best regards,
Rick C. Hodgin
 
G

glen herrmannsfeldt

(snip)
Just because something is possible, doesn't mean it's always a good
idea. One of the most valuable features of any high-level language is
that it makes it easier to AVOID doing some things that lower level
languages allow, because those things shouldn't be done. Identifying
some things as read-only, so that it's a detectable error if an attempt
is made to write to it, is a prime example of this.

It is always a trade-off. I have complained about some cases in
Fortran where features were removed.

For one, Fortran 77 added the ability to use REAL (that is,
floating point) variables in DO loops. If you aren't careful,
you can get surprising rounding errors, but that is true for
floating point in general.

Fortran 90 removed this feature, though compilers might still
support it as an extension. (Note that C has supported float
and double in for loops, always, and I see no hint to remove
that feature.)

I can see why string constant modification was allowed in early
C, but those reasons were gone by ANSI time.

-- glen
 
R

Rick C. Hodgin

I notice no comment about the %d method that I suggested, which
takes minimal programming work!


I went back and looked and I remember it now. I responded to it.

"Still requires that I write some code, and maintain some code, and
have a function that leaves allocated memory blocks hanging around
(inviting leaks unless I code to handle them all properly all of the
time). It's more than "very little work" to do this when, in the
alternative, the very definition of the thing you'd be copying in
your example would be utilized in my example.

"The compiler option removes all issues."

For my workaround I actually used a version similar to yours at one point.
At startup I iterated through the list[] array and replace all elements
with malloc()'d copies of the constant strings. Another version makes a
copy of the read-only version at each use replacing any macro portions
within before returning.

The actual string I use is about 40 characters, so it's more like:
char* list[] = {
...
"if (thisObject.______________placeholder_____________.whatever)\r\n",
...
};

As such, the full "___placeholder__" text is replaced with a value that's
computed above in the program for each iteration.

It typically looks like:
char placeholder[] = "somePrefix_20140121_125802001_21636893620000000";

It's a value computed during runtime execution based on a fixed size prefix
name, along with the date and time, coupled to the CPU tick count stored in
reverse numerical digit order, padded out with zeros unto the required size.

It's overkill to be sure, but there are times the iterative loop can process
dozens of times per second, so the millisecond and CPU tick count portions
are the only parts that sometimes change.

Best regards,
Rick C. Hodgin
 
R

Rick C. Hodgin

It is always a trade-off. I have complained about some cases in
Fortran where features were removed.

For one, Fortran 77 added the ability to use REAL (that is,
floating point) variables in DO loops. If you aren't careful,
you can get surprising rounding errors, but that is true for
floating point in general.
Fortran 90 removed this feature, though compilers might still
support it as an extension. (Note that C has supported float
and double in for loops, always, and I see no hint to remove
that feature.)

I can see why string constant modification was allowed in early
C, but those reasons were gone by ANSI time.


Early versions of Microsoft's C compiler also allowed the 80-bit floating
point form as a long double (or far double??, can't remember). Their
assembly language supported the REAL10 type long after it was dropped from
their C language. I miss that feature as it's still present today in the
x86's FPU hardware -- it's just really slow compared to 32-bit or 64-bit.
But for many applications, that doesn't matter ... the extra 3 to 4
significant digits in base-10 did matter.

I've never used Fortran. Not even one time even try it out.

Best regards,
Rick C. Hodgin
 
J

James Kuyper

const char *archiveFormats[] = {
#if CPIO_SUPPORTED
"cpio",
#endif
#if TAR_SUPPORTED
"tar",
#endif
#if ZIP_SUPPORTED
"ZIP",
#endif
#if APK_SUPPORTED
"apk",
#endif
null
};

That alternative is still ugly, and IMO, still a fairly convincing
argument for the convenience of allowing a terminal comma on a list.

I think all those #if..#endif blocks are ugly. It clutters the code and
makes it hard for me to read.
However, it's also a real, if slight, improvement over your suggestion.

It seems odd to me that developers would reject the trailing null solution
using existing C abilities, and instead ask that a trailing comma ability
be included to save the 4-bytes a typical 32-bit pointer would consume.
Most modern compilers align data on 2^N boundaries for speed anyway.

The "null" creates something that survives to be incorporated into the
final executable, affecting the efficiency of the implementation,
however slightly. The trailing comma does not. That's the key reason.

By the way, you still haven't identified what "null" is, and why you
prefer it to NULL, which is an existing feature of the C standard
library. If that seems like nit-picking, it isn't. C is a case-sensitive
language - if you don't pay close attention to case, you're going to
have a lot of trouble writing C code.
FWIW, I think the trailing null is the best current solution. And I like the
term sentinel. :) I would use it for variable code.

In moving forward, I would write some new ability to create the list properly,
giving the compiler a new ability to handle variable items:

char *archiveFormats[] =
{
#elementif CPIO_SUPPORTED "cpio"

For consistency with the naming of existing preprocessing directives,
that should be #elementifdef. Would you also propose #elementif, which
works like a #if, and #elementifndef, which would work like #ifndef?

Would you also recommend specialized equivalents of #if, #ifdef, and
#ifndef for use in other contexts? If so, in which other contexts? If
not, why not? What's special about array elements that singles them out
for special treatment?

A #if equivalent where the code controlled by it extends only to the end
of the same line would be fairly unpopular. While this particular case
is an exception, the controlled code is often too large to fit on the
same line with the preprocessing directive.

A #ifdef-like preprocessing directive specialized for elements of an
array seems pretty odd; since pre-processing occurs during translation
phase 4; arrays aren't even recognized as such until translation phase
7. If you're talking about a feature that is not evaluated until phase
7, then you'll have to deal with the fact that CPIO_SUPPORTED is a macro
whose definition ceases to be meaningful after the end of translation
phase 4.

You can get around that by #defining CPIO_SUPPORTED to have an actual
value, and testing that value with the equivalent of #if. However,
that's not idiomatic; macros that control whether various features are
implemented are conventionally #defined with an empty value, and tested
with #ifdef rather than #if. This is just a convention, not a strict
rule, but compatibility with existing conventions is an important issue
to be considered when evaluating proposed changes to the language.
 
G

glen herrmannsfeldt


(snip, then I wrote)
I've always though that S/360, et al, were rather painful for
extended precision arithmetic. Sure an Add Logical produces a
carry, but there's no good way to use that carry, except by
conditional branching around an add of a constant 1.

Yes, though it does make the instruction set more consistent,
and that pretty much the only place the condition code is
used is conditional branch instructions. Fortunately not so
many people do extended precision arithmetic.

I have a multiple precision floating point package written
in OS/360 assembler. I know the person who wrote it.
Along the way, he wrote about the problem of doing unsigned
divide. Turns out that with a little extra work, you can do
with the signed divide instruction, but you really need the
ability to divide an unsigned 64 bit value by an unsigned 32
bit value.
Add Logical with Carry is a fairy recent addition to the
ISA (it's part of the 64 bit base ISA, but I think it may
have been on the last generation of 9672s as well).

I thought it was late in the ESA/390 days, but I wasn't
following it all that closely.

All 32 bit systems supporting a 64 bit (long long) data type
that I know of use subroutine calls for mulitply and divide
(at least when all the bits are needed) but most can do add
or subtract inline.

-- glen
 
K

Kaz Kylheku

Interesting. To recap, my reasoning relates to the nature of software and
computers in general. They are just that: computers. They take input,
process it, and generate output. That, by definition, means read-write.

No it doesn't.

Computation can also be defined as a recursive process on mathematically
defined structures, and this idea is practically embodied in functional
programming languages, and functional programming features in multi-paradigm
programming languages.

You can do quite a lot with code that doesn't mutate state.

Where did you flunk computer science?
 
G

glen herrmannsfeldt

BartC said:
I don't understand the need for the prepended comma and the two nulls.
I would just have everything with a trailing comma, then have NULL
as the final element, which also serves as a useful sentinel instead
of trying to figure out the length of the list.

As I understand it, it is often used for structs, where it might
not be so easy to find the null, and it wastes a whole struct,
not just one pointer or int.
And when I generate such list using a proper language (not macros),
then the extra logic to suppress a comma at the end is trivial.
But, perhaps commas used for list elements can just be called element
terminators rather than separators. With the final one being optional.

You mean like the difference between Pascal (semicolon is statement
separator) and PL/I, C, and Java (to name a few) where it is a
statement terminator?

-- glen
 
K

Kaz Kylheku

On Wednesday, January 22, 2014 11:49:09 AM UTC-5, Kaz Kylheku wrote:
Also note that you could just waste a few bytes and do this, which also
works in pretty much any C dialect:
char list[][128] = {
"everything",
"is mutable now"
};
That solution was discussed. It is also workable, but it was undesirable
for me as it's clunky, wasteful, and so on.

That is nonsense. It's wasteful on a Commodore 64 from 1983.
It's wasteful on a PIC16 microcontroller, sure.

It's hardly wasteful in an environment in which every invocation of
your code-generation tool causes the attachment of many megabytes of shared
library material, and detachment thereof a fraction of a second later.

The phrase you're looking for there isn't "hardly wasteful," but "relatively
wasteful." Compared to the amount of resources used in common programs, it
is not relatively wasteful. However, it is, by definition, wasteful.

The whole lifestyle which enables you to write programs is wasteful compared
to living in the wild.

If you don't want to be wasteful, don't drive a car, don't consume anything
that was produced more than 20 miles from where you live, etc.

You're talking about wasting *bytes* on a machine whose RAM is measured in
*gigabytes*. Moreover, those bytes are not permanently wasted; they are only
briefly occupied, and then released and re-used for something else.

This "relative waste" is less, relatively, than the scraps that remain on your
plate at dinner, probably even if you lick the plate "clean".
Joe's solution is elegant, and exactly what I was looking for. It is not
wasteful, and it addresses the exact need I had, which was to include text

Except that it needs a compiler for the C99 dialect, which is larger, written
to a standard which almost tripled the page count compared to C90.
 
G

Geoff

That solution was discussed. It is workable, but it is unmanageable because
the element block in question in my particular case is about 100 lines and
will change from time to time.

In that case, with an alterable "template text" I would have made it a
text file, loaded a copy of hat text into memory and altered the copy
on the fly as needed. This allows replacement of the text without
recompiling all the source. Alternatively, putting the text into a
resource DLL and copying the resource would have solved the problem
without exposing the text to unauthorized alteration.
 
R

Rick C. Hodgin

The "null" creates something that survives to be incorporated into the
final executable, affecting the efficiency of the implementation,
however slightly. The trailing comma does not. That's the key reason.

I can see the need to remove the trailing null. And I can also see the need
to remove the trailing comma.

But in order to use a list that is populated without a trailing null you
must have a count that is known, so that either exists as a populated
constant that must be maintained, or it is another variable stored in
memory computed by the code generation utility ... either way it's (1)
manual work, or (2) 32-bits of storage taken up.

To me it seems six one way, half dozen the other -- especially when a variable
number of parameters is involved.
By the way, you still haven't identified what "null" is, and why you
prefer it to NULL, which is an existing feature of the C standard
library. If that seems like nit-picking, it isn't. C is a case-sensitive
language - if you don't pay close attention to case, you're going to
have a lot of trouble writing C code.

It's the lower-case version of NULL. I don't like upper-case source items,
preferring bool to BOOL, and null to NULL, etc. I typically include a typedef
somewhere in my common.h header block which defines it that way. It's just
become habit for me to use null over time.

FWIW, I would estimate that any reasonably intelligent C developer would be
able to figure out from context that when I use null, I mean NULL. If not...
well then... there we are. :)
FWIW, I think the trailing null is the best current solution. And I
like the term sentinel. :) I would use it for variable code.
In moving forward, I would write some new ability to create the list
properly, giving the compiler a new ability to handle variable items:
char *archiveFormats[] =
{
#elementif CPIO_SUPPORTED "cpio"

For consistency with the naming of existing preprocessing directives,
that should be #elementifdef. Would you also propose #elementif, which
works like a #if, and #elementifndef, which would work like #ifndef?

I would probably change that as well. I think the pound sign prefix is
not so good. I think I would make all code items that are to be affected
at compile time as computations leading to variable code be prefixed with
leading dots, and then use more or less the same syntax as the rest of
the language.

.if SOMETHING
// Condition code goes here
.endif

.elementIf (SOMETHING) "element"
.elementIf (!SOMETHING) "element"

That way I'm using more or less the same type of general syntax for regular
RDC code, as well as the preprocessor directives.
Would you also recommend specialized equivalents of #if, #ifdef, and
#ifndef for use in other contexts? If so, in which other contexts? If
not, why not? What's special about array elements that singles them out
for special treatment?

Sure. And I have no idea. I'd have to look through them. My idea would be
to make things good for human being developers. Tools that generate code
can be created to do anything they need to. My goal is to serve people and
people's needs. There will be a relationship between the GUI and the source
code, thereby removing a lot of what we see as strict syntax in text form,
to be replaced with colors, or icons, or enclosing casks, in the GUI.
A #if equivalent where the code controlled by it extends only to the end
of the same line would be fairly unpopular. While this particular case
is an exception, the controlled code is often too large to fit on the
same line with the preprocessing directive.

I have introduced this concept into my VXB++ language. I would introduce
something similar here to distinguish it from the #if as well:

lif (some_test()) some_code();
lelse some_other_code();

It is the same as this in traditional C:
if (some_test() {
some_code();
} else {
some_other_code();
}

....except that it does it on single lines. I also introduce the ANDAL
instruction in VXB++, which stands for "and also," and it allows
instructions to be concatenated on a single line (something that xbase
languages do not allow), so I could also use this (the andal keyword can
be abbreviated with a series of four dots, as in ....):

lif (some_test()) some_code(); .... some_code2(); .... some_code3();
lelse some_other_code(); .... some_other_code2();

This would be the same as:
if (some_test() {
some_code();
some_code2();
some_code3();
} else {
some_other_code();
some_other_code2();
}

Or however you would like to reformat it using C, which could also be
like this:

if (some_test() { some_code(); some_code2(); some_code3(); }
else { some_other_code(); some_other_code2(); }

Providing something similar today. Still, the purpose of lif..lelse is
to allow a single line if and else in VXB++, though I would also allow it
to be extended to RDC as well.

For the single-line #if I would allow it thusly:
.lif SOME_CONDITION
A #ifdef-like preprocessing directive specialized for elements of an
array seems pretty odd;

So does a trailing comma allowance because it invites the constant question
when looking at source code, "Why is that there? Was something left out?"
It takes something that should otherwise be known, and converts it into an
unknown ... inviting "confusion and delay" as Sir Topham Hat would say.
since pre-processing occurs during translation
phase 4; arrays aren't even recognized as such until translation phase
7. If you're talking about a feature that is not evaluated until phase
7, then you'll have to deal with the fact that CPIO_SUPPORTED is a macro
whose definition ceases to be meaningful after the end of translation
phase 4.

No idea what you're talking about, though I assume it has to do with the
current design of at least one C compiler, possibly GCC.

My compiler operates differently. :)
You can get around that by #defining CPIO_SUPPORTED to have an actual
value, and testing that value with the equivalent of #if. However,
that's not idiomatic; macros that control whether various features are
implemented are conventionally #defined with an empty value, and tested
with #ifdef rather than #if. This is just a convention, not a strict
rule, but compatibility with existing conventions is an important issue
to be considered when evaluating proposed changes to the language.

That's fine. Mine would use .ifdef then.

Best regards,
Rick C. Hodgin
 
R

Rick C. Hodgin

No it doesn't.

It does categorically. Even if it's only computing data into registers,
data is being read into the CPU, processed, and then written back somewhere.
It is impossible to have a computing system that does not do this.
Computation can also be defined as a recursive process on mathematically
defined structures, and this idea is practically embodied in functional
programming languages, and functional programming features in multi-paradigm
programming languages.
You can do quite a lot with code that doesn't mutate state.

I have no idea what you're talking about.

FWIW, recursively processing something means using a stack. The stack pointer
internally is incremented. If it does not use a stack, then the iteration of
the recursion is incremented. If it does not use an iterative count, then the
pointer to the location within the defined structure is incremented as it
moves from location to location.

In all computing there is input, processing, and output.
Where did you flunk computer science?

LOL! :)

Best regards,
Rick C. Hodgin
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,083
Messages
2,570,591
Members
47,212
Latest member
RobynWiley

Latest Threads

Top