Author Topic: Design a better "C"  (Read 69378 times)

0 Members and 9 Guests are viewing this topic.

Offline SiliconWizardTopic starter

  • Super Contributor
  • ***
  • Posts: 17810
  • Country: fr
Re: Design a better "C"
« Reply #200 on: August 06, 2021, 08:03:28 pm »
The above was elegantly solved in Pascal with the "WITH" statement. Much clearer and a lot less cumbersome. Your piece of code, using a C-like "with", would look like:
Code: [Select]
with (p_app->context.slice.app)
    ans = do_mount(device, mntpnt, fstype, prolix);

Some other languages have incorporated this feature. Not many.
It's elegant, but the downside is that it can be slightly confusing to read in some cases. It could shadow variables with the same name within scope, which is often considered bad coding style. So, pick your poison.

 

Offline free_electron

  • Super Contributor
  • ***
  • Posts: 9053
  • Country: us
    • SiliconValleyGarage
Re: Design a better "C"
« Reply #201 on: August 06, 2021, 08:26:33 pm »
Quote
There is no requirement to have ; there is an end of line character in the file from when you pressed the return key.

I think it's getting too close to function following form. Like Python. As programmers we know that coupling is bad, and yet having the way an editor may format the code determine what that code does is what you're proposing. The way the code is written or formatted should be irrelevant. Even forth figured that out in the end.

[edit: added context quote due to slow posting]

Quite the contrary. Now i have to help the compiler understanding when a statement is completed. ( that is what the semicolon does. it tells the compiler: end of statement ) semicolon is implied on closing brackets. )
it is pure lazyness on the coders of the first compiler. Same thing for = and ==.  Parsers for languages much older than C can handle both these things without issues. The problem is that C was designed on a crummy clunker of a computer and they were restricted to the memory available . So they took shortcuts. Because it saved memory. Anno 2021 we are still living with it.
Most statements are single line and i have to give the ;
Realistically speaking there are fewer multiline statements than there are singleline statements so a continuation character is more logical than a termination character.
Professional Electron Wrangler.
Any comments, or points of view expressed, are my own and not endorsed , induced or compensated by my employer(s).
 

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8853
  • Country: 00
Re: Design a better "C"
« Reply #202 on: August 06, 2021, 10:01:21 pm »
Quote
Now i have to help the compiler understanding when a statement is completed.

Sure (although, pedantically, you are telling, not helping). But then that's what you do when you write code. You're not suggesting anything to the compiler, you are explicitly saying what you want to occur.

Quote
Same thing for = and ==.  Parsers for languages much older than C can handle both these things without issues.

How do those other languages handle Siwastaja's earlier example of:

Code: [Select]
if( (retval = do_thing()) == -1)
 

Offline bd139

  • Super Contributor
  • ***
  • Posts: 23102
  • Country: gb
Re: Design a better "C"
« Reply #203 on: August 06, 2021, 10:21:54 pm »
So in the last few days I was ignoring this thread, has anyone designed a better C yet?  :-DD
 
The following users thanked this post: newbrain

Offline tggzzz

  • Super Contributor
  • ***
  • Posts: 23122
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: Design a better "C"
« Reply #204 on: August 06, 2021, 10:36:31 pm »
Yes; several in fact :)
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 
The following users thanked this post: bd139

Offline free_electron

  • Super Contributor
  • ***
  • Posts: 9053
  • Country: us
    • SiliconValleyGarage
Re: Design a better "C"
« Reply #205 on: August 06, 2021, 10:47:57 pm »
How do those other languages handle Siwastaja's earlier example of:
Code: [Select]
if( (retval = do_thing()) == -1)

simple: they don't allow for such vomit ! that is un-understandable. no wonder we have annual most obfuscated c code contests. this is extremely difficult to understand. syntax should be clear.

what is wrong with reformatting that to something readable ?

retval = dothing();  //statement begins with a variable so it is clearly an assignment.
if retval = -1 ... // statement begins with an if statement so it is a comparison.
there is no ambiguity when = means 'assign' or when it means 'compare'  depending on the keyword , the parser descends one logic branch or another. if there is an 'if' keyword : descend down the compare branch , if there is a variable : descend down the assignment branch

that is simple and understandable.

Even then the point is still moot. Even with that convoluted source there is still no ambiguity : compiler knows we are evaluating an if statement hence a compairson that yields a boolean value ( if 1 then this, else that. ) an if statement is a pure boolean operation. It is a switch statement with only two possible paths.

So , the parser begins.
'if'  |->  descend down comparison branch
 '(' |-> recursive instantiate a new parser branch as we begin a new block
    'retval'  |-> variable this will be our first value
    '='   |-> first statement was variable so = means assign descend down assign tree
    'dothing()' // execute statement and collect return value
')' closing bracket. recursive instance terminates and passes 'retval' outward
outward parser now has 'retval' , which is a value

the parser now basically sees if(retval == -1) it has minimized away the retval = donothing() block to a variable. that bracketed block is done.

so , we are back into evaluating an if clause
left hand is 'retval'
= is a comparison clause (we are in an if block)
-1 is a constant


Look, the parser can figure out things much more complex than this ! Like that retval is a variable but dothing is a function call. You don't need to write things like :
if ((variable retval getsassignedresultof functioncall dothing(withnothingpassed) ) compareto constant -1) . Based on the syntax convention it knows what things are. So, based on the knowledge what things are it can also know when = means assign and when compare. like you cannot assign a value to a functioncall.
if (dothing() = -1) is the same as if(-1 = dothing())


like i said , many other languages , much older than C have no problems with this.

my gripe with it is that, as an infrequent coder , i often find that i make mistakes against this. and they can be very hard to find. You are inside an if clause, it is illogical to perform assignments in there )

if ((fruit= pick_a_fruit()) = apple)
why do you need that intermediate there ?
if (pick_a_fruit() = apple)

and, in case you really need to retain what was picked :
fruit = pick_a_fruit
if (fruit = apple)

i simply hate cryptical stuff. The simpler something is written the simpler it is to spot mistakes. And simpler does not mean 'less characters'. simpler means 'babytalk'. ditch complexity.

Hardcore c coders will state that this assign and compare contraction is 'elegant'. Which i read as : "if you don't understand it then you don't belong in our 'elite' club" snobbery

i've seen code where they do this kind of crap in for loops.... it takes you half an hour to figure out what the fuck they are doing. 'but it is elegant'. no it isn't . (and then on top of that they modify the loopcounter inside the block as well. that ought also be prohibited. use an exit clause to cleanly terminate the loop prematurely. it;s all about readability and maintainability)

Splitting it in multiple lines produces just as compact machine code. The end result is the same. it's just easier for humans to understand. and that is the part i like.

« Last Edit: August 06, 2021, 11:26:51 pm by free_electron »
Professional Electron Wrangler.
Any comments, or points of view expressed, are my own and not endorsed , induced or compensated by my employer(s).
 
The following users thanked this post: DC1MC, DiTBho

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8853
  • Country: 00
Re: Design a better "C"
« Reply #206 on: August 06, 2021, 11:13:26 pm »
OK
 

Offline free_electron

  • Super Contributor
  • ***
  • Posts: 9053
  • Country: us
    • SiliconValleyGarage
Re: Design a better "C"
« Reply #207 on: August 06, 2021, 11:41:49 pm »
OK

when you think about it the syntax of '=' is

<lefthand> = <righthand>

type of lefthand is
function : = since you cannot assign a value to a function call , the function returns something to you, it is clearly a comparison.
constant : = constants are immutable, you cant assign something to the, so comparison
variable : = tis is mutable so it means 'assign' ,unless we are in an IF clause. then it means compare
block of code between brackets : this can only return a variable. , but since this block is left hand it needs to be treated as a constant. you cannot assign a value to the outcome of a block of code. that is illogical . the block of code returns something to you. so the only logical choice is : comparison. you cannot execute dothing() =9; that throws an error.

righthand :
function : take return value
constant : take constant value
variable : take variable value
block of code between brackets : take return value

so if you now drop this one level up ( in an IF statement ) the only modifer is the fact that this is part of an IF clause. so we just need to modify the lefthand 'variable' and treat it as constant , so it becomes acompare and not an assign. simple matter of checking a flag.

I've made simple languages that ran on semicustom cores. i never had problems with figuring out when = means assign and when compare.
Professional Electron Wrangler.
Any comments, or points of view expressed, are my own and not endorsed , induced or compensated by my employer(s).
 
The following users thanked this post: DiTBho

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: Design a better "C"
« Reply #208 on: August 07, 2021, 12:08:32 am »
Back to Dylan, apart from Bruce who has worked on it quite a bit, can anyone else in here comment on it?

This would be quite surprising :-(

The language that is currently the most similar to Dylan combined with most popular seems to be Julia. I need to take a closer look at it myself.
 

Offline brucehoult

  • Super Contributor
  • ***
  • Posts: 6464
  • Country: nz
Re: Design a better "C"
« Reply #209 on: August 07, 2021, 12:22:53 am »
The above was elegantly solved in Pascal with the "WITH" statement. Much clearer and a lot less cumbersome. Your piece of code, using a C-like "with", would look like:
Code: [Select]
with (p_app->context.slice.app)
    ans = do_mount(device, mntpnt, fstype, prolix);

Some other languages have incorporated this feature. Not many.
It's elegant, but the downside is that it can be slightly confusing to read in some cases. It could shadow variables with the same name within scope, which is often considered bad coding style. So, pick your poison.

C++11 comes close, and the amount it misses by is exactly that required to not have shadowing problems:

Code: [Select]
  {
    auto &x = p_app->context.slice.app;
    ans = do_mount(x.device, x.mntpnt, x.fstype, x.prolix);
  }

Plain C can do almost the same (the same generated machine code) with a pointer and x-> instead of x. except that you have to figure out (and type) what the type of x is yourself.
 
The following users thanked this post: DiTBho

Offline SiliconWizardTopic starter

  • Super Contributor
  • ***
  • Posts: 17810
  • Country: fr
Re: Design a better "C"
« Reply #210 on: August 07, 2021, 12:34:54 am »
The above was elegantly solved in Pascal with the "WITH" statement. Much clearer and a lot less cumbersome. Your piece of code, using a C-like "with", would look like:
Code: [Select]
with (p_app->context.slice.app)
    ans = do_mount(device, mntpnt, fstype, prolix);

Some other languages have incorporated this feature. Not many.
It's elegant, but the downside is that it can be slightly confusing to read in some cases. It could shadow variables with the same name within scope, which is often considered bad coding style. So, pick your poison.

C++11 comes close, and the amount it misses by is exactly that required to not have shadowing problems:

Code: [Select]
  {
    auto &x = p_app->context.slice.app;
    ans = do_mount(x.device, x.mntpnt, x.fstype, x.prolix);
  }

Plain C can do almost the same (the same generated machine code) with a pointer and x-> instead of x. except that you have to figure out (and type) what the type of x is yourself.

Oh yes, of course, and that's something I've done on many occasions.
The "with" statement would really be just sugar coating with little added value, for any language that supports getting a reference or a pointer to some object.

 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2499
  • Country: us
  • Yes, I do this for a living
Re: Design a better "C"
« Reply #211 on: August 07, 2021, 05:11:48 am »
Back to Dylan, apart from Bruce who has worked on it quite a bit, can anyone else in here comment on it?

I remember when Bruce Springsteen was the new Bob Dylan!
 

Offline JPortici

  • Super Contributor
  • ***
  • Posts: 3914
  • Country: it
Re: Design a better "C"
« Reply #212 on: August 07, 2021, 06:04:03 am »
I am reusing an old project, another feature I found useful in the Japanese C-like compiler is "alias"

Code: [Select]
{
    alias device = p_app->context.slice.app.device;
    alias mntpnt = p_app->context.slice.app.mntpnt;
    alias fstype = p_app->context.slice.app.fstype;
    alias prolix = p_app->context.slice.app.prolix;

    ans = do_mount(device, mntpnt, fstype, prolix);
    return ans;
}

This piece of code is a custom bootloader; "alias" works similar to #define, but it only works inside a block {}, it's not global.

this is like defiing a pointer to the type of device and initializing it at p_app->context.slice.app.device, which i do and for which my compiler doesn't even allocate a pointer and optimizes it away (unless the pointer is of a volatile type of course)
 
The following users thanked this post: DiTBho

Offline DC1MC

  • Super Contributor
  • ***
  • Posts: 1925
  • Country: de
Re: Design a better "C"
« Reply #213 on: August 07, 2021, 06:31:06 am »
How come that nobody mentioned NIM https://nim-lang.org/, it seem to have a lot of suggested improvements and the only "bad" thing I've heard about it was "...I will never learn or support nim, they don't have a Code of Conduct...", which in my book is a big plus.

Cheers,
DC1MC
 
 
The following users thanked this post: DiTBho

Offline DiTBho

  • Super Contributor
  • ***
  • Posts: 5098
  • Country: gb
Re: Design a better "C"
« Reply #214 on: August 07, 2021, 10:27:02 am »
my compiler doesn't even allocate a pointer and optimizes it away (unless the pointer is of a volatile type of course)

yes, they said they did this trick because their compiler usually allocated a variable to point to the field and they didn't want it.

I'm reusing a part of their project code; yesterday I replaced "alias" with a pointer to allow Gcc to compile the code, which does a good job with the optimizer, but frankly I find "alias" really useful, kind of functionality I would like to have.

There a couple of reasons why I like it, mainly because it makes life easier with ICEs since alias are simple symbol label so the ICE doesn't need to query the host to know which reference it's on.

Ok, this is a specific personal need and it's no secret I am ICE-addicted, but I like it because you could also for instance use "alias" to locally define the size of strings.

Code: [Select]
void adjust_filename(...) /* original code */
{
    alias name_size = 40; <---------- local
    char_t source_name[name_size];
    char_t target_name[name_size];
    char_t local_name[name_size];
     ...
}

Another thing of their code I had to adapt to Gcc. I replaced "alias" with "#define", which is unfortunately global, so ... this is what I did
Code: [Select]
void adjust_filename(...) /* code adapted to Gcc */
{
    #define adjust_filename_name_size 40 <---------- global
    char_t source_name[adjust_filename_name_size];
    char_t target_name[adjust_filename_name_size];
    char_t local_name[adjust_filename_name_size];
     ...
}

The code works the same, Gcc is happy, and the code is working  ;D

Code: [Select]
xboot v3 (2021-08-07)
waiting for "/dev/sda2" ... success
/usb/app/kernel/5.4.128@/dev/sda3:ext2
"experimental-kernel with mesh support"
ram: [###############.........................] 9541 / 24964 Kb
checking available ram ... success
loading kernel ... success
Starting new kernel ...

So you could say ... "no reason to introduce alias". Yup, human tastes  ;D
The opposite of courage is not cowardice, it is conformity. Even a dead fish can go with the flow
 

Offline emece67

  • Frequent Contributor
  • **
  • !
  • Posts: 614
  • Country: 00
Re: Design a better "C"
« Reply #215 on: August 07, 2021, 11:32:33 am »
.
« Last Edit: August 19, 2022, 04:37:13 pm by emece67 »
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 11286
  • Country: fi
Re: Design a better "C"
« Reply #216 on: August 07, 2021, 11:48:38 am »
In such approach, what means x = y = z (all being variables)?

Quite obviously - that would be forbidden too. And inside if - that was already answered: forbidden.

What free_electron suggests is a very simple language with very limited "power". What he calls "obfuscation" is what I call competent programmers being efficient. Patterns like being able to "do things" inside a condition, and short-circuiting logical operations, enable code with least repetition which is not only the problem of writing the code taking longer, it also slows down reading, and worst, makes maintenance riskier.

C allows some pretty nasty obfuscation mechanisms though, and total minimization of LoC is not a good target, but the opposite, requiring gazillion of maintained lines of basically copy-paste code to do anything is not any better. As usual, the golden middle way works best. Use some widely used and understood patterns to reduce excess work but don't try to outsmart everyone.

C just requires some expertise and total beginners cannot instantly understand C code made by experienced professionals. It's still much easier than C++ or even a 25% subset thereof.

Brain surgery is difficult, too, yet we want to have that available, and we don't want to dumb it down enough so that anyone can do it after a 2-hour crash course.

Python is good for beginners because you can get good results quickly by scripting together professionally developed C modules and mix some "traditional" programming inbetween when you need it. Being able to leverage work already done minimizes the amount of your "own" code and related risk of bugs due to stupid choices Python makes (discussed above). For the same reason, Python is useless to actually implement any non-trivial piece of software (say, tens of thousands of LoC) and almost no one does that.
« Last Edit: August 07, 2021, 11:55:29 am by Siwastaja »
 
The following users thanked this post: newbrain

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8853
  • Country: 00
Re: Design a better "C"
« Reply #217 on: August 07, 2021, 12:05:25 pm »
Quote
I replaced "alias" with "#define", which is unfortunately global,

Could you not use #undef to make it local:

Code: [Select]
void adjust_filename(...) /* code adapted to Gcc */
{
    #define adjust_filename_name_size 40 <---------- global(ish)
    char_t source_name[adjust_filename_name_size];
    char_t target_name[adjust_filename_name_size];
    char_t local_name[adjust_filename_name_size];
     ...
    #undef adjust_filename_name_size <----------- now local
}
 
The following users thanked this post: DiTBho

Online gf

  • Super Contributor
  • ***
  • Posts: 1832
  • Country: de
Re: Design a better "C"
« Reply #218 on: August 07, 2021, 12:35:38 pm »
Quote
I replaced "alias" with "#define", which is unfortunately global,

Could you not use #undef to make it local:

Code: [Select]
void adjust_filename(...) /* code adapted to Gcc */
{
    #define adjust_filename_name_size 40 <---------- global(ish)
    char_t source_name[adjust_filename_name_size];
    char_t target_name[adjust_filename_name_size];
    char_t local_name[adjust_filename_name_size];
     ...
    #undef adjust_filename_name_size <----------- now local
}

Some compilers also support pragmas for saving/restoring (push/pop) macro definitions.
https://gcc.gnu.org/onlinedocs/gcc/Push_002fPop-Macro-Pragmas.html
But I think this is not standard.
 
The following users thanked this post: DiTBho

Offline SiliconWizardTopic starter

  • Super Contributor
  • ***
  • Posts: 17810
  • Country: fr
Re: Design a better "C"
« Reply #219 on: August 07, 2021, 03:41:09 pm »
Regarding this assignment vs. equality thing, IMHO, trying to harmonize both is just wrong conceptually, and a complete waste of time if the net result is just having to type one fewer character.

Assignment and equality testing are DIFFERENT things. They should not look the same. There is no good rationale for this except laziness or possibly a questionable command of programming concepts.

Now, I for one prefer the Wirthian syntax: '=' for equality, and ':=' for assignment. It's simple, it doesn't mess with the equal sign we're all used to.
I don't know why they chose '=' for assignment and '==' for equality in C. Maybe this was for the silly reason of setting itself apart from Pascal and all related languages.

Some languages, willing to set themselves apart further from either approaches, are using the '=' character for both, but with the additional 'let' keyword for assignments. It probably looks a bit more like real maths, but it's unnecessary verbose IMHO. What's wrong with ':=' really? One point is that an assignment in a programming language does not quite map to a math notation IMO, so trying to make it look like math is not necessarily a good idea.

Now I agree the related fact that an assignment is an expression in C (so has a value) is a questionable choice, so in itself it wouldn't be a good rationale for choosing the way to express an assignment.
 
The following users thanked this post: Siwastaja

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8853
  • Country: 00
Re: Design a better "C"
« Reply #220 on: August 07, 2021, 04:00:13 pm »
Quote
why they chose '=' for assignment and '==' for equality in C

Perhaps because then you can go '!=' and '>-', etc. Bit hard to do that with '=' :)
 

Offline SiliconWizardTopic starter

  • Super Contributor
  • ***
  • Posts: 17810
  • Country: fr
Re: Design a better "C"
« Reply #221 on: August 07, 2021, 04:06:17 pm »
Quote
why they chose '=' for assignment and '==' for equality in C

Perhaps because then you can go '!=' and '>-', etc. Bit hard to do that with '=' :)

What does it have anything to do with it?
 

Offline PlainName

  • Super Contributor
  • ***
  • Posts: 8853
  • Country: 00
Re: Design a better "C"
« Reply #222 on: August 07, 2021, 04:34:27 pm »
Huh? If you use '=' for testing then you end up with one or two character tests. OTOH, use '==' and it's consistently two characters. And '==' is visually similar to, and differs in the right way, from '>='. Or '!=', etc.
 

Offline madires

  • Super Contributor
  • ***
  • Posts: 9211
  • Country: de
  • A qualified hobbyist ;)
Re: Design a better "C"
« Reply #223 on: August 07, 2021, 06:31:59 pm »
Rust: CVE-2021-29922 (https://sick.codes/sick-2021-015)
Go: CVE-2021-29923 (https://sick.codes/sick-2021-016)

You can screw up security in any language. ;)
 

Offline SiliconWizardTopic starter

  • Super Contributor
  • ***
  • Posts: 17810
  • Country: fr
Re: Design a better "C"
« Reply #224 on: August 07, 2021, 06:34:44 pm »
Rust: CVE-2021-29922 (https://sick.codes/sick-2021-015)
Go: CVE-2021-29923 (https://sick.codes/sick-2021-016)

You can screw up security in any language. ;)

Of course!

I'll take the above reports as an opportunity to emphasize the importance of parameter checking/validation, something I already talked about a few times. Failing to do this properly is a major source of bugs and security or safety issues, from simple apps to safety-critical firmware. To the point that I would add to the list of features for a new language, making the validation of function parameters mandatory (checked at compile time.) A qualifier could be added so that the developer could selectively indicate that some parameter doesn't have to be validated, but the default would be validation required.

Let's illustrate with simple examples what it could be like:

Code: [Select]
double sqrt1(double x)
{
   return sqrt(x + 1.0);
}

would yield a warning (or even error): "parameter 'x' not checked".

Code: [Select]
double plus1(unchecked double x)
{
   return x + 1.0;
}

In this case, no warning or error would occur. The developer would use the 'unchecked' qualifier if they determined that said parameter doesn't need to be checked.
Compilers could output the exhaustive list of functions that have 'unchecked' parameters, so that those could be scheduled for code reviews.

Chances are, most developers would hate this.
« Last Edit: August 07, 2021, 07:18:42 pm by SiliconWizard »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf

 

-->