char defaultOption = "4";
Did you mean "char *defaultOption" or "char defaultOption[]" rather than
"char defaultOptions", or did you mean '4' rather than "4"?
I meant char defaultOption[] = "4";
I would like to be able to specify that with a const prefix, as in this
type of syntax:
char* list[] =
{
"foo1",
const "foo2",
"foo3"
}
In this case, I do not want the second element to be changed, but the
first and third... they can change.
If I were to suggest a new language feature to support that, I'd want an
explicit marker for a string that I *do* want to be able to change.
I realize that. My view, of course, differs.
In your proposed C-like language, what would this snippet print?
for (int i = 0; i < 2; i ++) {
char *s = "hello";
if (i == 0) {
s[0] = 'H';
}
puts(s);
}
Interesting.
FWIW, I don't believe in defining variables in this way in C. I believe an
initialization block should exist so it is being done explicitly, both for
documentation purposes, and clarity in reading the source code (it's very
easy to miss a nested declaration when a group of variables is created of
a similar type.
In my proposed language, it would print "Hello" both times because the
char* s definition would've been pulled out of the loop and defined as a
function variable. If the user wanted independent copies each iteration
he would have to create them and manage them himself, which I think
documents the condition of the code more explicitly, making it far
easier for someone to see what's going on rather than inferring from
language peculiarities which may not be consistent across compiler
versions (they probably are in this case, but I've seen other similar
conditions which vary between Visual C++ and GCC).
I would rewrite your function to look like this (because I believe it
should behave this way):
void foo(void)
{
int i;
char* s; // Note I use the D language syntax of keeping the pointer
// symbol near the type, rather than the variable.
// Initialization
s = "hello";
// Code
for (i = 0; i < 2; i ++)
{
// I introduce predicates, which logically operate more like this:
if (i == 0) s[0] = 'H';
// Displays "Hello" both times
puts(s);
}
}
To mimic your functionality, I would code this way:
const char gcHello[] = "hello";
void foo(void)
{
int i;
char s[7];
// Initialization (a compiler switch would make this automatic)
memset(s, 0, sizeof(s)); // Here it's done manually
// Code
for (i = 0; i < 2; i ++)
{
// Iterative re/initialization
memcpy(s, gcHello, -2); // My memcpy would support a p3 of -1 to
// automatically perform strlen() on p3,
// and -2 would be strlen()+1.
// First pass conversion only
if (i == 0) s[0] = 'H';
// Displays "Hello" then "hello"
puts(s);
}
}
In C as it's currently defined, the string literal "hello" corresponds
to an anonymous array object with static storage duration; attempting to
modify it has undefined behavior. As I understand it, you want to
remove the second part of that. The above code has one occurrence of a
string literal, but it's being used in the initializer for two distinct
objects. On the second iteration, does s point to a string with
contents "hello" or "Hello"?
Either interpretation is problematic.
Exactly. So, you don't code that way.
You make everything a function-level variable and it's done. You make
all code items read/write unless they are explicitly prefixed with a
const or have some macro wrapper like _rw("foo") or _fo("foo") to
explicitly name them.
I fail to see how this argues for modifiable string literals.
Not just string literals, but a separation of the "before" and the "after."
Programming today is, by default, targeted at multiple CPUs. There are
functions which run top-down, but on the whole we are creating
multi-threaded congruent code execution engines running on commensurate
hardware. The time for a new language syntax is at hand.
I propose new extensions to C in general:
in (thread_name) {
// Do some code in this thread
} and in (other_thread_name) {
// Do some code in this thread
}
And a new tjoin keyword to join threads before continuing:
tjoin this, thread_name, other_thread_name
flow name {
flowto name;
always before {
}
always after {
}
function name {
}
subflow name {
}
error name {
}
} // end flow
And I propose the new concept of a cask, a "pill" that is inserted anywhere
in code to do whatever I like, along with explicit cask definitions that do
certain things based upon called functions which can convey branch logic
upon returning.
Casks look like this (|sample|) and they would operate like this:
Traditional code:
if (some_test(1, 2, 3)) {
// Do something
}
In this case:
push 3
push 2
push 1
call some_test
compare result to 0
if not equal, enter the block
The ability to insert a cask does not alter program logic:
if ( (|cask1|) some_test( (|cask2|) 1, 2, (|cask3|) 3) {
// Do something
}
In this case:
push 3
call cask3
push 2
push 1
call cask2
call some_test
call cask1
compare result from some_test to 0
if not equal, enter the block
The casks are called functions which can be inserted at any point without
otherwise affecting program logic (hence their new shape). I wrote it with
spaces above to make it more clear, but it could be coded like this:
if ((|cask1|)some_test((|cask2|)1, 2, (|cask3|)3)
And I have other ideas. You can read about them on this page. This page
specifically relates to extensions to Visual FoxPro, but my intention is
my RDC (Rapid Development Compiler) which is C-like, but relaxes a lot of
stringent errors in C reporting them only as warnings, such as pointer-to-
pointer conversions, allowing for them to be perfectly valid, and many
other changes as well.
http://www.visual-freepro.org/wiki/index.php/VXB++
Each of these add-ons should be language-level first class citizens which are known to the language and allow for modern CPU architectures with various new data types and volatile extensions which operate around explicitly semaphored access at the language level, along with certain optimization constraints and allowances (as per the developer's dictates, even of the kind which can override "safety" on variable use -- meaning that a particular case could violate atomicity and the compiler knows it, but the compiler is a tool and should allow what the developer dictates because the developer is a person and has real authority).
My opinion. My goals.
As a language design issue, I *strongly* disagree with this.
Personally, I like the idea of making everything read-only unless you
explicitly say you want to be able to modify it. (Obviously C isn't
defined this way; equally obviously, this is merely my own opinion.)
I look at computers as being exactly that: computers. They compute. Their
purpose is to take input, process it, and store output. That storage portion
automatically means write abilities, and the input combination means
read-write as it is more common to operate through a chain of processing
where a recently computed and written value is then quickly used thereafter
as input to a follow-on computation.
Everything should be read-write unless explicitly stated as read-only. My
opinion, and my position in any languages I author.
BTW, your _c("text") macro would still have to be defined somehow;
a new kind of string literal would probably make more sense.
I think string literals should all use double-quotes, but it should be a
different double-quote character from ASCII-34, and one for left and one
for right, so they can be nested and mate up as parenthesis. I also
believe variables should be allowed to have spaces, but it should be a
different space character than ASCII-32. In my implementation of RDC,
Visual FreePro, my virtual machine, I will introduce ASCII characters which
explicitly serve these purposes at the developer level, allowing for double-
quoted characters to be used as raw input without first escaping them. I
will also allow other explicit ASCII characters between the new double quote
characters in their raw single-symbol form without escaping.
We're past the days of limited abilities. We have GUIs now that can draw any
icon, any character ... it's time to grow up.
There are a lot of things which were done badly in the early days of
programming. Many rigid constraints which make difficult-to-read-and-understand source code. The concept of a header, for example, is
no longer required when 16GB of memory is $700 or less and will only
get cheaper over time.
It's time to rethink what's been thought, and undo the damage that's been
done, to look to the current and future needs of multi-core, parallel-thread,
object-oriented design, yet with all of it having an explicit base in the raw
compute needs of the machine. C is ideal for that. C++ takes the idea of
object orientation too far.
In C++, foo->function(). The better syntax is foo.function() (for both
pointers to variables, and declared variables), and such is a mild
extension of the existing struct:
struct SFoo
{
void function(void);
int member_variable;
}
SFoo foo1;
SFoo* foo2 = malloc(SFoo); // Compiler is smart enough to know
foo1.function();
foo2.function(); // Same syntax
No default constructor. No default destructor. Each component must be
explicitly coded and executed in code if needed ... thereby documenting it
without obfuscation, and allowing a straight-forward merging of structures
through multiple inheritance. My opinion.
The bottom line is that standard C cannot, and IMHO should not, cater to
every obscure coding practice. A language can have:
1. mutable string literals;
2. immutable string literals; or
3. both, with distinct syntax.
C has chosen option 2, and it has served us well. I would not strongly
object to option 3, but I'm not convinced that it would be worth the
extra complexity. You're welcome to push for option 1, but don't expect
to succeed.
I don't expect to get anywhere trying to change anything in C.
It's why
I'm moving to my own language. I hit the GCC group a while back asking for
the self() extension, which allows recursion to the current function without
it being explicitly named or even explicitly populated with parameters. They
said it was not a good idea. I asked for something else (can't remember what)
and they said the same. So ... it was fuel for me to get started on my own..
Best regards,
Rick C. Hodgin