EEVblog Electronics Community Forum

Products => Computers => Programming => Topic started by: SiliconWizard on April 19, 2023, 04:11:45 am

Title: Oh, C3!
Post by: SiliconWizard on April 19, 2023, 04:11:45 am
https://c3-lang.org/
Title: Re: Oh, C3!
Post by: Whales on April 19, 2023, 05:19:50 am
Quote
Member access using . even for pointers

Convenient.

Quote
Removal of multiple declaration syntax

Only a single declaration is allowed per statement in C3:

int i, j; // ERROR
int a;    // Fine

In conditionals, a special form of multiple declarations are allowed but each must then provide its type:

for (int i = 0, int j = 1; i < 10; i++, j++) { ... }

Why?

Quote
Goto removed

goto is removed and replaced with labelled break and continue together with the nextcase statement that allows you to jump between cases in a switch statement.

Rationale: It is very difficult to make goto work well with defer and implicit unwrapping of optional results. It is not just making the compiler harder to write, but the code is harder to understand as well. The replacements together with defer cover many if not all usages of goto in regular code.

Thankyou to the authors for providing the rationale.  I'm not involved in your group or the languages you are probably using as context, without this I'm clueless as to why you are doing many of your things.

I like C as a low-level language, ie closer to assembly.  Goto is natural for that.  I'm worried that it sounds like you are placing compiler author desires ahead of users; what are these desires?  Higher optimisation levels?  That's a difficult sell to many C users, it's not an absolute problem, there are lots of shades of grey.

I want to look more at this 'defer' feature, but I can't find much docs about it.  Best I can do is this example (https://c3-lang.org/primer/#goto-removed) but it doesn't explain things like order of defer executions (stack or queue?), what happens to variable scope, whether I can defer an entire block of code (instead of just one line), etc.

EDIT: removed my extra ideas, split into another post below.
Title: Re: Oh, C3!
Post by: Ed.Kloonk on April 19, 2023, 05:21:44 am
 ::)   :-\

Always the same. Based on C.

Quote
Stay close to C - only change where there is a significant need.

Or when you're too lazy to write code that cleans up after itself.

 :--
Title: Re: Oh, C3!
Post by: Whales on April 19, 2023, 05:28:31 am
I disagree with both you Kloonk AND the statements of the C3 authors :P  I hope that doesn't count as a double negative.

There is lots to C I like.  Definitely lots I don't like either.  I'm not sure if C3 really floats my boat. 

I wonder what C3's use case and mindshare is?  Narrowly in-operating-system programming mainly?  Or broad inc micros?  I can't find anything about that on the c3-lang.org site.

The C2 site (http://www.c2lang.org/) mentions kernels & bootloaders.
Title: Re: Oh, C3!
Post by: Whales on April 19, 2023, 05:36:39 am
Split from my earlier post, these are not comments about C3 but just interesting to compare with the lang changes they have made.

Some things I've imagined up over the years whilst using C that I wish I had:

(Whales1) Make the struct keyword unnecessary when using structs. 

Both options are annoying: having to write "struct" before every defintion (inc in function args) OR having to typedef every struct.

This change would be backwards compatible with 99% of code (only breaking those that use struct names as names for something else too).  If you want to keep using "struct" keyword everywhere you still could, no wakkas.

(Whales2) Clamp down on a lot of the silliness you read being discussed about undefined behaviour. 

Do what the programmer would expect to happen on a standard 2's complement machine with type sizes a multiple of 8 bits.  Use the rule of "least astonishment".  C is supposed to be easier than assembly, don't make it harder.

(Whales3) Require that ALL new arches/platforms adopt the same fixed definitions for the sizes of int, char, long, etc. 

I already use uint32_t and co from <stdint.h> but standard funcs like printf("%d") then require much uglier writing to be platform portable. 

eg printf("I have %"PRIu32" doges with %"PRIs64" coolness factor\n", dogcount, coolsum) is just a pain, even worse when you have many consecutive fields and less string inbetween.

(Whales4) Syntactic sugar: namespaces.

Implement just as an auto-prepending of function (and var?) names with the characters "namespacename::" and do nothing more.  Also allow someone to strip these characters off again (ie skip the namespacename:: prefix when using the funcs) if they so desire.

Completely optional, breaks nothing.  Worth trying just to see if it makes things easier or harder to deal with.  Many people already prefix their lib's function names with "LibName_" anyway, it might be better or worse to make an option of a standard method, not sure.

(Whales5) Syntactic sugar: allow defining functions in a class-like syntax.

ALL it does is automatically modify them to add a "self" argument to their arg list.  No new/delete/constructor/deconstructor/public-private-protecgted stuff, leave that to Cpp, just a bit of sugar to make things a little neater and happier.

Code: [Select]
struct something
{
  f32 posx, posy;
  char *name;
  void *aux;
};

something::new(u32 id);
something::destroy();
something::recolour(u8 r, u8 g, u8 b);

Unlike C++ you wouldn't even need to expose all of the struct internals inside the header files, so editing the struct contents won't cause header files to change (which then won't trigger a recompile of absolutely everything).  Eg this would be OK too:

Code: [Select]
struct something;
something::new(u32 id);
something::destroy();
something::recolour(u8 r, u8 g, u8 b);

(On the technical side: this is doable because then things don't need to know sizeof(struct) any more)
Title: Re: Oh, C3!
Post by: Ed.Kloonk on April 19, 2023, 05:36:51 am
I disagree with both you Kloonk AND the statements of the C3 authors :P  I hope that doesn't count as a double negative.

There is lots to C I like.  Definitely lots I don't like either.  I'm not sure if C3 really floats my boat. 

I wonder what C3's use case and mindshare is?  Narrowly in-operating-system programming mainly?  Or broad inc micros?  I can't find anything about that on the c3-lang.org site.

The C2 site (http://www.c2lang.org/) mentions kernels & bootloaders.

I wonder if the adoption of these mutations sometimes comes from a project leader with certain pet-hates. But I see your point, a solution looking for a problem.
Title: Re: Oh, C3!
Post by: Whales on April 19, 2023, 05:41:15 am
Probably a few different pet hates combined, the site lists 3 authors. 

Of course my pet hates are far superior 8)

C (for better and for worse) has been shaped by the desires of many diverse groups, so it's hard and dangerous to claim you have improved it without taking into account a lot of diverse people's opinions OR intentionally stating that your modified version is for a narrower use case than the original.
Title: Re: Oh, C3!
Post by: DiTBho on April 19, 2023, 09:16:03 am
C (for better and for worse) has been shaped by the desires of many diverse groups, so it's hard and dangerous to claim you have improved it without taking into account a lot of diverse people's opinions OR intentionally stating that your modified version is for a narrower use case than the original.

yup, in my case I can publicly declare I my modified version is for my narrower use case than the original, that's why it's called "my-c" ;D


I think c/89 and c/99 cannot be modified/improved too much if they have to serve diverse people's needs  :-//
Title: Re: Oh, C3!
Post by: newbrain on April 20, 2023, 12:18:01 pm
https://c3-lang.org/
https://strlen.com/lobster/
See for yourself: https://ziglang.org/

You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!
Title: Re: Oh, C3!
Post by: Whales on April 20, 2023, 12:42:35 pm
You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!

There are constant newlang discussions elsewhere.  Checkout https://lobste.rs and https://news.ycombinator.com/

I don't like newlangs (https://halestrom.net/darksleep/blog/036_timesafety/) because I want to give my programs the best chance of still compiling and running in 10 or more years time.  C is not perfect, stuff still breaks, but it's better than most.
Title: Re: Oh, C3!
Post by: Ed.Kloonk on April 20, 2023, 02:24:35 pm
You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!

There are constant newlang discussions elsewhere.  Checkout https://lobste.rs and https://news.ycombinator.com/

I don't like newlangs (https://halestrom.net/darksleep/blog/036_timesafety/) because I want to give my programs the best chance of still compiling and running in 10 or more years time.  It's not perfect, stuff still breaks, but it's better than most.

Absolutely.

It's hard enough to re-acquaint the libs and deps, and then you've got some Martian language to deal with.

It's a mid-level language that everyone eventually wishes it were high level.
Title: Re: Oh, C3!
Post by: DiTBho on April 20, 2023, 02:37:23 pm
You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!

was/is it interesting?  :o :o :o
Title: Re: Oh, C3!
Post by: DiTBho on April 20, 2023, 02:59:40 pm
I don't like newlangs because I want to give my programs the best chance of still compiling and running in 10 or more years time.

LOL, like "Fire-fLOP" (aka firefox) ? In 2005 I was able to compile it on my PowerBook G4.
Now not only it's C++11 (requires modern gcc version) & Rust (requires llvm/clang) but building it eats more than 2GByte of ram  :o :o :o

my old laptop has 512Mbyte of ram, was able to compile the early versions of FireFox but .. today I only compile Dillo instead, ssh-tunneling to a proxy that makes it access to HTTPs web 2.0.

Or, like the old Gentoo portage, that was python v1 && EAPI={1 , 2}?
Now it's Python >=3.*, EAPI={ 5 , 6 , 7 , 8}, no more compatible with previous ABI.
Code: [Select]
case ${EAPI} in
        5) ;;
        6) ;;
        7) ;;
        8) ;;
        *) die "EAPI=${EAPI} is not supported" ;;
esac
----> forget your old Overlays, forget ***every*** single old portage: old stuff won't work on modern stuff.

And I have no solution, except an ugly hybrid merge-up(1) for my old router (2008); while for the new one router (2020) ... I am all with 2023 stuff, and expect (hope?) it will work for the next 5-8 years.

Or, like Perl, autodoc (Latex?), and other scripts used in Linux Kernel?
can you still compile kernel 2.0? no -> need to be fixed, but you'd best use an old rootfs
can you still compile kernel 2.2? no -> need to be fixed, but you'd best use an old rootfs
can you still compile kernel 2.4? no -> need to be fixed, but you'd best use an old rootfs
Can you still compile kernel 2.6? no  -> need to be fixed, but you'd best use an old rootfs
Can you still compile kernel 3.*? somehow yes, but ... it's full of pain, and you'd best use an old rootfs

So, I am afraid that it's not only the language but rather everything from the kernel up!




(1) basically it's still a 2008 stage4, integrated with a forced multi-library or static-linked (I know, it's wrong by design, and consumes more space ... but at least it works) to have some modern stuff on it, like modern OpenSSL, modern OpenSSH, modern curl, and modern wget, all able to work on "https" and SSL stuff.
Title: Re: Oh, C3!
Post by: SiliconWizard on April 20, 2023, 07:22:25 pm
https://c3-lang.org/
https://strlen.com/lobster/
See for yourself: https://ziglang.org/

You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!

I have posted quite a few of these. These new programming languages make an almost endless list! :popcorn:
Most of the corresponding threads, the "yet another one" series I have started are more for a quick fun than anything else.

Many are sort of "funny", some are interesting. As I said previously, I think Zig would fit in the interesting category. Another one would be Odin.
The guy behind Odin, which is nicknamed gingerBill, has interesting stuff to say, and he's very humble.

That doesn't mean you should actually use any of these languages, but still can be interesting to look at.
Generally speaking, looking at stuff that you're not constantly being told to look at is not a bad move.
Title: Re: Oh, C3!
Post by: newbrain on April 20, 2023, 08:33:49 pm
You guys are throwing me back to when I was (happily) subscribed to "Computer Language (https://archive.org/details/computerlanguage)" magazine!
Thank you!

was/is it interesting?  :o :o :o
For a young EE studying nerd? Quite a lot!
Read the number with the interviews to Knuth and Wirth (https://archive.org/details/Computer_Language_Issue_09_1985-05_CL_Publications_US).
But TBH, my original subscription was for Micro Cornucopia (https://archive.org/search?query=micro+cornucopia), a treasure trove of hardware and software information, which unfortunately folded shortly after I paid my second year.
They offered to transfer the subscription to a small number of magazines - remember those?
I selected CL as I was buying it already from time to time.
Title: Re: Oh, C3!
Post by: Siwastaja on April 21, 2023, 06:43:24 pm
I find it hilarious they absolutely had to remove goto, but then creep in a feature of adding a new kind of goto which can arbitrarily jump around inside switch-case: something no one ever asked, switch-cases being quite confusing already as they are.
Title: Re: Oh, C3!
Post by: SiliconWizard on April 21, 2023, 08:08:33 pm
I find it hilarious they absolutely had to remove goto, but then creep in a feature of adding a new kind of goto which can arbitrarily jump around inside switch-case: something no one ever asked, switch-cases being quite confusing already as they are.

As I've seen, they removed the need for 'break' inside switch's, making them behave as the Pascal/Ada 'case' constructs by default. But then added the 'nextcase' statement to allow falling through.
'nextcase' doesn't allow to jump around freely but only to the next 'case', as I've got it at least.
In order words, they inverted the default behavior in switch-case, which is not a completely stupid idea.

You're wrong in saying "no one asked for that". Fallthrough is the only way of combining multiple cases. People use that all the time. And so, once you decide to remove the fallthrough behavior as default, this 'nextcase' statement is the logical step. You need it, unless you give up on having multiple cases leading to the execution of the same code.

The problem is that it's a half-baked solution: outside of cryptic constructs like the Duff's device, using fallthrough in switch-case in C was mostly meant to emulate the possibility of having cases for multiple values instead of just one. That was much better addressed even in Pascal (if I remember it right) using ranges.

But obviously a 'nextcase' statement is much easier to implement.
Title: Re: Oh, C3!
Post by: Siwastaja on April 22, 2023, 05:39:34 am
'nextcase' doesn't allow to jump around freely but only to the next 'case', as I've got it at least.

No, look closer - clearly that was their original idea, but they feature creeped their "fallthrough" to take an argument, allowing you to jump to any other cases, in any order. I'm ridiculing this feature.

I agree with the inversion from implicit fallthrough to making it explicit. Not only it saves from typing boilerplate (break is the usual case), it reduces human error.
Title: Re: Oh, C3!
Post by: Karel on April 22, 2023, 06:25:52 am
Here we go again. Is there somebody who really believes C is going to be replaced?
I don't for various reasons. C has been here for a long time and it will stay here for even a longer time.

I agree though, it's fun to watch the attempts and it can be interesting to analyze them.

 :popcorn:
Title: Re: Oh, C3!
Post by: newbrain on April 22, 2023, 06:29:28 am
I'm ridiculing this feature.
But why?
It's so beautiful!
Now you don't need if, while, do and for.
Every structured flow control can be achieved with a suitable switch statement!

/s, in case it's needed.

I don't find the nextcase feature (even the basic one) especially compelling.
In a way, it's already there in C as compilers warn when falling through cases.
Break is still there, (and the possibility of leaving named scopes is indeed nice) this just removes one of its uses.
Title: Re: Oh, C3!
Post by: DiTBho on April 22, 2023, 10:53:54 am
Here we go again. Is there somebody who really believes C is going to be replaced?
I don't for various reasons. C has been here for a long time and it will stay here for even a longer time.

there are only to kinds of people: those who are spending time wondering *** if *** { C/89 , C/99 } could be replaced ... (and with what?) and those who have actually already replaced (improved? just modified? just made it weirder? ... mumble, dunno what's the correct verb here) C and re-written a small uKernel as well as a b+tree filesystem, and are very happy that it took just 1/4 of the effort was taken with C/89  :o :o :o


Title: Re: Oh, C3!
Post by: Karel on April 22, 2023, 11:51:32 am
Here we go again. Is there somebody who really believes C is going to be replaced?
I don't for various reasons. C has been here for a long time and it will stay here for even a longer time.

there are only to kinds of people: those who are spending time wondering *** if *** { C/89 , C/99 } could be replaced ... (and with what?) and those who have actually already replaced (improved? just modified? just made it weirder? ... mumble, dunno what's the correct verb here) C and re-written a small uKernel as well as a b+tree filesystem, and are very happy that it took just 1/4 of the effort was taken with C/89  :o :o :o

I always use gcc with option -std=gnu11. No problems here, programming has never been easier using GNU/Linux, make and GCC.
Not saying here that everybody should do like me. Just telling what works best for me.
Title: Re: Oh, C3!
Post by: DiTBho on April 22, 2023, 01:16:34 pm
No problems here, programming has never been easier using GNU/Linux, make and GCC.
Not saying here that everybody should do like me. Just telling what works best for me.

frankly I feel really frustrated by answer like this.
Title: Re: Oh, C3!
Post by: Karel on April 22, 2023, 01:30:07 pm
No problems here, programming has never been easier using GNU/Linux, make and GCC.
Not saying here that everybody should do like me. Just telling what works best for me.

frankly I feel really frustrated by answer like this.

Please don't, it's not worth it. Use what works best for you.
Title: Re: Oh, C3!
Post by: JPortici on April 22, 2023, 05:01:30 pm
IMHO the only thing that C ever needed is a .length attribute for arrays.
I'm sick and tired of bugs introduced by using sizeof() on an array when you should have used sizeof(a)/sizeof(a[0]). Looking at you, handsome guy in the mirror pointing at me.
Title: Re: Oh, C3!
Post by: SiliconWizard on April 23, 2023, 08:54:50 pm
'nextcase' doesn't allow to jump around freely but only to the next 'case', as I've got it at least.

No, look closer - clearly that was their original idea, but they feature creeped their "fallthrough" to take an argument, allowing you to jump to any other cases, in any order. I'm ridiculing this feature.

Oh, you're right. You had a closer look than I did. ;D

There's this infamous "labelled nextcase". https://c3-lang.org/statements/#nextcase-and-labelled-nextcase

It's not even merely a "label", it's an expression that can be evaluated at run-time and this acts as though the code flow was looping back to the switch select with a value given by the "label" (which again isn't a label.)

That doesn't look good. :-DD Oh, and incidentally, with this construct, if the expression given to nextcase evaluates to a value that is not handled by any 'case', then it becomes an infinite loop. Nice!! :-DD
Or does the switch just exit in this case? Who knows, not sure I saw that clearly.

That said, the guy maybe had the typical state machine construct in mind. For which I would favor setting a variable with the next state, rather than directly controlling the flow anyway.
His approach avoids having to put the switch inside a loop, but then it makes a potentially implicit loop, which is horrific.

The benefit of using a variable holding the state is that it's much easier to trace. If you control the flow directly in many places, it makes tracing much more tedious.
Title: Re: Oh, C3!
Post by: PlainName on April 25, 2023, 06:45:31 pm
Quote
I'm sick and tired of bugs introduced by using sizeof() on an array when you should have used sizeof(a)/sizeof(a[0])

All my project have:
Code: [Select]
#define	ARRAY_SIZE(x)	(sizeof(x) / sizeof((x)[0]))
Title: Re: Oh, C3!
Post by: Nominal Animal on April 25, 2023, 07:19:46 pm
Ever since the last C-related programming language discussion, I've now and then examined the typical cases where human programmers make most errors in C.

I'm pretty darned convinced that the only fundamental change (in addition to various syntax etc. additions we have discussed here in other threads previously), would be to replace pointers with arrays as the base memory reference type.  (There are details wrt. read-only strings I'm not sure about, though.)  That would let the compiler do compile-time memory access validation, helping kill buffer-related bugs.  All other changes could be done incrementally, by replacing the C standard library.

Whenever I do such experiments –– i.e., how would code look like and what would it compile to, if I tweaked the compiler and libraries just so –– I always discover that the end result I desire is obtainable by a smaller 'real' change (but large paradigm/approach/theory-wise change) than one would initially assume or believe.  Furthermore, the things most developers get stuck on –– myself included, unless I monitor myself to explicitly avoid this ––, end up not affecting the actual language use much; only how it looks like on the surface, and how it can be described to other people.  Unimportant fluff, in other words.

To repeat from those other threads, I would like additional features that provide an unordered (data-parallel) for loop constructs, as well as a way to tell the computer that two independent code sections can be interleaved (that their relative order is unimportant, perhaps at block level).  But these are optimization, things that are somewhat difficult for compilers to optimize using current C rules; and I have not verified what kind of constructs would be needed and what kind of changes needed to the C standard abstract machine model to address these.  The all-pointers-are-actually-arrays change, however, would be suprisingly straightforward.
Title: Re: Oh, C3!
Post by: PlainName on April 25, 2023, 08:36:25 pm
Quote
replace pointers with arrays as the base memory reference type

Why would that be better?
Title: Re: Oh, C3!
Post by: DiTBho on April 25, 2023, 09:43:49 pm
Quote
replace pointers with arrays as the base memory reference type

Why would that be better?

because they can transport borders and size { begin, end, size }
Title: Re: Oh, C3!
Post by: Nominal Animal on April 25, 2023, 09:53:48 pm
Quote
replace pointers with arrays as the base memory reference type
Why would that be better?
It makes it possible for the compiler (with current gcc and clang static analysis/warning capabilities) to verify buffer accesses are valid.  (That is, the compiler knows at compile time if each access is "valid" (safe, within the buffer), "invalid" (overrun/underrun), or "undetermined"; with the last one only affecting code that uses pointers or tricky indexing math whose limits are unknown at compile time.)

To explore this yourself, write some test code using the pattern
    type1 somefunc(size_t len, type2 buffer[len], ...)
i.e. instead of pointers, you pass an array; and to avoid having the array auto-decay to a pointer, you need to specify its size too.
If you introduce a typical buffer overrun bug in such a function, no matter how deep in a call chain, the compiler will tell you if you enable the relevant warnings.  There are no added run-time checks at all; look at the generated machine code too.

This alone does not do anything for existing code, say for example strlen().  The idea is to use the change to rewrite the standard library in a form where pointers are replaced with array references.  Currently it is a bit cumbersome, for example strlen() would best be written as
    ssize_t strlen(size_t len, const char s[len]);
so at minimum we'd need the compiler to allow the size of a parameter array to be defined later in the explicit parameter list (with ssize_t from stolen from POSIX; C currently uses int for it, which is problematic on LP64 architectures).

The necessary changes, as I said, are surprisingly small.  The effects, however, to how easily statically analyzable it makes efficient code, are surprising.  You really do need to experiment with it to see the possibilities.  As I also said, read-only/immutable strings have peculiarities I'm not sure yet how best to deal with, but basically the rest of POSIX C -like functionality (i.e., with different API/function signatures, but same or very similar functionality) is quite straightforward.  Oh, and functions allocating or reallocating memory, returning an array reference, may need syntactic sugar (as currently they really need to return a struct containing the start address of the allocated memory, and length in bytes).

(What I am not sure about yet, is whether we need a new non-scalar base "type" with two properties, start address and length.  Currently, we can do that and slicing (three properties: start address, step size, and count), just fine using structures.  But there might be additional compiler optimization/compile time static analysis opportunities, if it was a base type to begin with.)
Title: Re: Oh, C3!
Post by: PlainName on April 25, 2023, 10:02:12 pm
Quote
replace pointers with arrays as the base memory reference type
Why would that be better?
It makes it possible for the compiler (with current gcc and clang static analysis/warning capabilities) to verify buffer accesses are valid.  (That is, the compiler knows at compile time if each access is "valid" (safe, within the buffer), "invalid" (overrun/underrun), or "undetermined"; with the last one only affecting code that uses pointers or tricky indexing math whose limits are unknown at compile time.)

Ah! Of course, I was stuck in pointer mode thinking the array would be passed as a pointer and just look like an array to the programmer. But I see now that's not the idea :)
Title: Re: Oh, C3!
Post by: SiliconWizard on April 25, 2023, 11:11:07 pm
That's more or less akin to always using the base pointer to an allocated block (rather than accessing it through a pointer that could point arbitrarily inside, or even outside of it) and some index for accessing its content. You also need to store the size.

After which it does look like a full-fledged array indeed.

That's something you can always do in pure C though, even if that means a bit more programming overhead and possibly a bit less opportunity for optimization (even though that would remain to be seen in practice.)

I have written a header file years ago, that I still use to this day (with some minor evolutions), that exposes a few macros to encapsulate dynamic memory management, including "dynamic arrays", which are accessed via indices only (either with, or without bounds checking depending on the use case.) I haven't directly called any malloc/realloc/free ever since. The runtime overhead is either zero or extremely small.

Sure having that built-in would be nice, but point is, this approach can still be - at least in essence - used without designing a new language. I for one wouldn't use C without this small "library" I wrote more than a decade ago, at least for anything requiring dynamic allocations. For pure static allocation stuff, part of it can still be used.

The basic idea is to create a type for your 'arrays', something like this:

Code: [Select]
typedef struct
{
    BaseType *Block;    // pointer to your memory block, from static or dynamic allocation
    size_t n;    // current number of items of type 'BaseType' in the memory block
    size_t nMax;    // max number of items of type 'BaseType' in the memory block
}   Array_t;

That can be initialized from a statically-allocated array just like so:
Code: [Select]
BaseType Array[xxx];

Array_t MyArray = { .Block = Array, .n = 0, .nMax = ARRAY_SIZE(Array) };

The variant for dynamically-allocated arrays is also easy. With this simple construct, one can see that handling dynamic arrays becomes 'straightforward'.

Accessing it is just:
Code: [Select]
MyArray.Block[index] // no bounds-checking, can be used with zero overhead when guarantees about 'index' are sufficient
MyArray.Block[index < MyArray.n? index : MyArray.n - 1] // bounds-checking, default to "saturating" the index

// You can add variants of bounds-checking that will execute some code in case of an out-of-bounds condition if needed.

With a few macros, that can be declared, and manipulated for just any base type very easily.
Some will find that clunky, especially if they don't like macros, as doing this without macros will be even clunkier.
Others will do this kind of stuff with macros and move on.

In any case, you'll indeed realize that directly playing with pointers is rarely necessary, and can be left to the very occasional and very low-level stuff.

The benefits of keeping all your pointers only pointing to *objects*, rather than potentially pointing arbitrarily *inside* an object are multiple.
Title: Re: Oh, C3!
Post by: PlainName on April 25, 2023, 11:43:22 pm
I do a similar thing but use functions rather than macros. There's an overhead in the function call, but more scope to mess around when debugging without affecting anything else. Also doesn't rely on the programmer remembering to use the safe access when appropriate :)
Title: Re: Oh, C3!
Post by: Nominal Animal on April 26, 2023, 12:12:52 am
It is very interesting (but unclear) to me exactly why most C programmers – myself included – prefer
    rettype funcname(elemtype *ptr, size_t len);
over
    rettype funcname(size_t len, elemtype buf[len]);
even though the only difference in machine code is the order of parameters; but the latter API pattern allowing much better buffer access checking at compile time, even through deep call chains (each call limiting to a smaller sub-array), helping catch buffer underrun/overrun errors.

The easy answer is inertia (or habit or familiarity or because everyone else does it that way too), but I'm not sure it is the whole answer.
Isn't it interesting how rarely anything like this (arrays-not-pointers) is suggested for "the next C", even though memory or buffer over/underrun bugs are the most common issues in C code?

Quote
replace pointers with arrays as the base memory reference type
Why would that be better?
It makes it possible for the compiler (with current gcc and clang static analysis/warning capabilities) to verify buffer accesses are valid.  (That is, the compiler knows at compile time if each access is "valid" (safe, within the buffer), "invalid" (overrun/underrun), or "undetermined"; with the last one only affecting code that uses pointers or tricky indexing math whose limits are unknown at compile time.)
Ah! Of course, I was stuck in pointer mode thinking the array would be passed as a pointer and just look like an array to the programmer. But I see now that's not the idea :)
Yep.  It's more like a cultural change than a technical one, even though its purpose is purely technical: help with compile-time static analysis wrt. buffer accesses.

That's more or less akin to always using the base pointer to an allocated block (rather than accessing it through a pointer that could point arbitrarily inside, or even outside of it) and some index for accessing its content. You also need to store the size.
Actually, what I want is for the compiler to be aware of the size whenever it is known at compile time.

If you consider the two funcname() definitions at the beginning of this post, you can clearly see the difference between the pointer and the array approach.  This difference is the critical one; it is not about adding explicit size information to interfaces that currently use a pointer only.  (Except for memory allocation functions: these should return both the allocated size and the base address, instead of just the base address.  This would actually be desirable in many grow-as-needed use cases, considered completely separately.  Oh, and possibly the string functions, which deserve to be redesigned anyway.)

That's something you can always do in pure C though, even if that means a bit more programming overhead and possibly a bit less opportunity for optimization (even though that would remain to be seen in practice.)
Note that the change would not cause any change to runtime code, no inherent additional runtime memory or CPU overhead at all.

Many string functions would actually add an explicit size parameter (ABI-wise), but I consider that a plus (and a deficiency in current standard C library string functions).  I've discussed the related issues especially in embedded environments before; let's just say that string handling can be done much better (faster, more reliably) even in current C than what the standard C library provides.

Passing an array forwards is trivial even in current C (since C99), although the size of the array must be before the array in the parameter list, but receiving an array from a function call is not supported.  Thus far, in my experiments I've simply assumed syntax "elemtype arrayname[sizetype count] = ...;" (declaring two variables at once, initialized by a single function call returning both the base pointer and the size, with the size divided by the element size to obtain the count "automagically"), but I'm sure better syntax can be devised.

The basic idea is to create a type for your 'arrays', something like this:
Code: [Select]
typedef struct
{
    BaseType *Block;    // pointer to your memory block, from static or dynamic allocation
    size_t n;    // current number of items of type 'BaseType' in the memory block
    size_t nMax;    // max number of items of type 'BaseType' in the memory block
}   Array_t;
Yes, I use this pattern extensively.  For some reason, I use 'used' for the current number of items, and 'size' for the maximum number of items, and 'item' for the pointer or C99 flexible array member.  It is very common to see a variant of
    typedef struct {
        size_t   size;
        size_t   used;
        elemtype item[];
    } elem_array;
in my code.

Indeed, whenever this information is already available, why don't we tell the C compiler about it, so it can help check the array boundaries for us at run time?

This is the core of this suggestion.  Not to add size and/or used to everywhere (except functions that in my opinion should have had the size from the beginning even in the standard C library), but to help the compiler understand better exactly what us humans intend, and help catch our thinkos at compile time.
Title: Re: Oh, C3!
Post by: DiTBho on April 26, 2023, 08:54:36 am
It is very interesting (but unclear) to me exactly why most C programmers – myself included – prefer
    rettype funcname(elemtype *ptr, size_t len);
over
    rettype funcname(size_t len, elemtype buf[len]);

actually I do prefer

    ans_t funcname(buffer_t buffer)

 :D
Title: Re: Oh, C3!
Post by: DiTBho on April 26, 2023, 09:08:11 am
whenever this information is already available, why don't we tell the C compiler about it, so it can help check the array boundaries for us at run time?

even better, why don't we tell the ICE about it? so it can help automatic test-cases and autonomously check boundaries for us at run time?

even better++, why don't we facilitate AI-assisted ICEs? So they can also use that information to identify common patterns in pieces of code that have a high probability of containing bugs.
Title: Re: Oh, C3!
Post by: JPortici on April 26, 2023, 10:20:59 am
Quote
I'm sick and tired of bugs introduced by using sizeof() on an array when you should have used sizeof(a)/sizeof(a[0])

All my project have:
Code: [Select]
#define	ARRAY_SIZE(x)	(sizeof(x) / sizeof((x)[0]))

of course, and i should do that.
However a lengthof(x) operator that can only take arrays as an input would have been better than a macro (ISTR lengthof as an extension in some compilers)
Title: Re: Oh, C3!
Post by: SiliconWizard on April 26, 2023, 08:40:00 pm
I do a similar thing but use functions rather than macros. There's an overhead in the function call, but more scope to mess around when debugging without affecting anything else. Also doesn't rely on the programmer remembering to use the safe access when appropriate :)

Sure, problem is that you can't avoid macros to generate the type definitions themselves (such as the Array_t example I gave, for any given base type.)
You can kind of work around it by using a void * pointer for the allocated block and add an additional member for the 'element size', but then you lose any basic static check, and you suddenly get an even better way of shooting yourself in the foot than directly messing with pointers. :popcorn:

Or you hand-write every 'array' type definition, which is horrible. Macros are for avoiding to retype the same text over and over again, and that's what I use them for.
Want to add a member to your 'generic' type? Just modify the macro. Macros need some care to avoid the usual pitfalls, but when used with some care, they are infinitely preferable to duplicating code.
Title: Re: Oh, C3!
Post by: Siwastaja on April 27, 2023, 09:06:56 am
Or you hand-write every 'array' type definition, which is horrible. Macros are for avoiding to retype the same text over and over again, and that's what I use them for.
Want to add a member to your 'generic' type? Just modify the macro. Macros need some care to avoid the usual pitfalls, but when used with some care, they are infinitely preferable to duplicating code.

And I truly believe the C preprocessor is one of its strongest points and reason why C became so popular. People who invent "C replacements" tend to miss this fact. The first thing they do is they remove the preprocessor because it's so inelegant and dangerous; yet fail to come up with something with at least the same capabilities.

C programmers have this love-hate relationship with the preprocessor. It's horrible, but it's surprisingly powerful and makes it possible to do generic programming in C.
Title: Re: Oh, C3!
Post by: DiTBho on April 27, 2023, 11:23:51 am
Or you hand-write every 'array' type definition, which is horrible. Macros are for avoiding to retype the same text over and over again, and that's what I use them for.
Want to add a member to your 'generic' type? Just modify the macro. Macros need some care to avoid the usual pitfalls, but when used with some care, they are infinitely preferable to duplicating code.

And I truly believe the C preprocessor is one of its strongest points and reason why C became so popular. People who invent "C replacements" tend to miss this fact. The first thing they do is they remove the preprocessor because it's so inelegant and dangerous; yet fail to come up with something with at least the same capabilities.

C programmers have this love-hate relationship with the preprocessor. It's horrible, but it's surprisingly powerful and makes it possible to do generic programming in C.

sure! why not? in fact cpp was the first thing being banned and removed entirely in my-c

It can be done, and my-c doesn't miss anything, just it solves problems differently and makes life easier :D

Whereas C/89/99 ... well, the last bug i fought in the Linux kernel was a typo with "#define something SPACE MISTAKE etc" which got through the build Gcc-v12 steps but caused a silent but catastrophic and sneaky bug, and I wasted three weeks on it  :o :o :o
Title: Re: Oh, C3!
Post by: DiTBho on April 27, 2023, 11:31:56 am
C programmers have this love-hate relationship with the preprocessor

Also, include those who write analysis software and develop ICE tools.
For all of us cpp is more than terrible.
Title: Re: Oh, C3!
Post by: Siwastaja on April 27, 2023, 01:55:14 pm
CPP = C Plus Plus
Title: Re: Oh, C3!
Post by: DiTBho on April 27, 2023, 02:08:10 pm
CPP = C Pre Processor

belongs to
sys-devel/gcc ---> /usr/$arch-$computer-linux-gnu/gcc-bin/$gcc_version/cpp
dev-lang/gcc_gnat ---> /usr/$arch-$computer-linux-gnu/gnat-bin/$gcc_version/cpp

(gcc_gnat is ... gcc + gnat_ada_core, recompiled as gcc with languages={C, Ada} )

c++ = C plus plus
g++ = GNU C plus plus
Title: Re: Oh, C3!
Post by: DiTBho on April 27, 2023, 02:18:08 pm
cpp also belongs to
overlay@idp: sys-devel/my-c~MIPS5++ ---> /usr/idp/my-c-bin/$my-c_version/cpp


what?  :o :o :o

didn't you say that cpp was banned?

Yup!

So why is cpp there in the my-c tree?

to cure your inertia at being tempted to invoke it with ... random punishments in form of
- console blocked for 5 minutes (like with the "SL" ncurses program)
- you cannot do nothing but get your random insults, ncurses full screen

(so at the end of the day you would like to DELETE it, and you cannot because you don't have root permissions)
Title: Re: Oh, C3!
Post by: SiliconWizard on April 27, 2023, 07:41:13 pm
C programmers have this love-hate relationship with the preprocessor. It's horrible, but it's surprisingly powerful and makes it possible to do generic programming in C.

I personally don't hate the preprocessor at all - I find it very useful.

Yep, every attempt at replacing the preprocessor to achieve the same level of generic programming have either led to something much less flexible/powerful, or true untamable and unverifiable monsters.

What many people seem to miss - and that Wirth has kept saying over and over again - is that simplicity should be a goal.
C is simple, the C preprocessor is simple.

C++ templates are monsters.
Title: Re: Oh, C3!
Post by: DiTBho on April 28, 2023, 10:14:54 am
every attempt at replacing the preprocessor to achieve the same level of generic programming have either led to something much less flexible/powerful, or true untamable and unverifiable monsters.

every attempt? except my-c, so it's some but not all  :o :o :o

Title: Re: Oh, C3!
Post by: DiTBho on April 28, 2023, 10:20:45 am
even replacing  #define macro() in cpp with a true compiler built-in macro() mechanism is better

everything that doesn't pre-process the source is better because it doesn't hide information
Title: Re: Oh, C3!
Post by: PlainName on April 28, 2023, 10:39:41 am
Quote
everything that doesn't pre-process the source is better because it doesn't hide information

But isn't that one of the main features of functions? They hide lots of nitty gritty detail behind a simple name (and, of course, let you reuse code without repeating it, which is also what macros can do).
Title: Re: Oh, C3!
Post by: DiTBho on April 28, 2023, 03:26:26 pm
macros (by cpp) vs functions:
- functions are not pre-processed but compiled
- macro does not check any Compile-Time Errors, Function checks Compile-Time Errors

the second is what I meant: you lose information during pre-processing.
Title: Re: Oh, C3!
Post by: Siwastaja on April 28, 2023, 03:45:24 pm
Quote
everything that doesn't pre-process the source is better because it doesn't hide information

But isn't that one of the main features of functions? They hide lots of nitty gritty detail behind a simple name (and, of course, let you reuse code without repeating it, which is also what macros can do).

DiTBho means it hides information otherwise accessible to his own automated analysis tool. The options are obvious, either go through the hassle of making that analysis tool understand macros (thus nothing would be hidden), or ban the use of macros. DiTBho has clearly chosen the latter and it's understandable as it's less work for him.

For example, modern C compilers have "understood" preprocessor (I think by producing metadata from the preprocessing step and forwarding it to the compiler) and not just blindly do text replacement as a separate preprocessing step; they can produce good error messages. The same idea could be followed in DiTBho's "ICE".
Title: Re: Oh, C3!
Post by: DiTBho on April 28, 2023, 04:08:45 pm
Specifically, there are three kinds of code repetition:

Which brings to what experienced C/{ 89, 99} programmers feel as "tagged patterns of code repetition".
Which brings the question: to avoid it, can pure C benefit from meta-programming?
Which brings the final question: since there is no other mechanism in C/{ 89, 99}, can the C pre-processor-macro be *the right tool* for some decent meta-programming?

The answer is: NO.
Technically it can be done, but it's practically too error prone.

What you want here is a replacement of the pre-processor, something built-in the language that allows you to eliminate code repetition by using macro iteration and with the complete support for algebraic data types and interfaces.

Your goal is also to reduce boilerplate and the risk of a failure.

And about that, I want to make myself clear: you need it strictly this way and nothing more. C++ does more than is required, making it a dangerous template meta-programming monster.
Title: Re: Oh, C3!
Post by: Siwastaja on April 28, 2023, 04:32:38 pm
The right balance between "stupidly simple and thus dangerous" and "too elegant and thus dangerous" is very difficult to achieve. What sounds nice on a CS department coffee room easily gets out of hands.

One-man project is likely to go less catastrophically wrong than something designed for years by a committee, so I'm sure your-C has better generic programming ideology than C++  ::)
Title: Re: Oh, C3!
Post by: PlainName on April 28, 2023, 06:32:42 pm
Quote
- functions are not pre-processed but compiled

That's a backroom issue though. Kind of like driving a car and saying this one is trash because the engine is petrol rather than diesel. On a technical level it can make a difference, but if you're having to deal with that regularly I think something is wrong.

Quote
- macro does not check any Compile-Time Errors, Function checks Compile-Time Errors

Not sure I get what you're saying there: doesn't a macro error result in a compiler error?
Title: Re: Oh, C3!
Post by: PlainName on April 28, 2023, 06:34:53 pm
Quote
DiTBho means it hides information otherwise accessible to his own automated analysis tool. The options are obvious, either go through the hassle of making that analysis tool understand macros (thus nothing would be hidden), or ban the use of macros. DiTBho has clearly chosen the latter and it's understandable as it's less work for him.

Sure, nowt wrong with that. I would do the same if I was making the stuff he was. But I don't think it's legitimate to say something is bad everywhere with no redeeming features because of some personal thing no-one else will encounter. And it's the general that I thought we were talking about here.
Title: Re: Oh, C3!
Post by: SiliconWizard on April 28, 2023, 06:58:09 pm
Quote
DiTBho means it hides information otherwise accessible to his own automated analysis tool. The options are obvious, either go through the hassle of making that analysis tool understand macros (thus nothing would be hidden), or ban the use of macros. DiTBho has clearly chosen the latter and it's understandable as it's less work for him.

Sure, nowt wrong with that. I would do the same if I was making the stuff he was. But I don't think it's legitimate to say something is bad everywhere with no redeeming features because of some personal thing no-one else will encounter. And it's the general that I thought we were talking about here.

Agreed, but to be fair, that tends to be the attitude of *most* people having designed programming languages, with only a very few exceptions.

Title: Re: Oh, C3!
Post by: SiliconWizard on April 28, 2023, 07:14:05 pm
Quote
everything that doesn't pre-process the source is better because it doesn't hide information

But isn't that one of the main features of functions? They hide lots of nitty gritty detail behind a simple name (and, of course, let you reuse code without repeating it, which is also what macros can do).

DiTBho means it hides information otherwise accessible to his own automated analysis tool. The options are obvious, either go through the hassle of making that analysis tool understand macros (thus nothing would be hidden), or ban the use of macros. DiTBho has clearly chosen the latter and it's understandable as it's less work for him.

What it hides to what (or whom) is the question here.

To the programmer, macros "abstract" pieces of code, so in that regard they "hide" code, but in a similar way other language abstractions do, as PlainName suggested.

Now the reverse happens for static analysis tools and compilers (usually): the code they analyse is the preprocessed code, and in that regard, macros hide no code to these tools. It's the converse: in that context, macros hide... the macros themselves, not the code they generate, as it's preprocessed.

Sure some more elaborate tools can "understand" macros (instead of merely preprocessing them before analysing the code) so the analysis can link to the original macros, which can be handy to... "debug" macros. Otherwise, it may not be that useful, you usually have line numbers to look at the original source code in case.

I think the main concern people have with macros is that they find it hard to prove the correctness of the code generated by macros - in other words, the correctness of macros themselves.
I've personally never introduced bugs due to macros I've written, that I can remember of, but I may be an alien, who knows.

Now if you still want/need to validate your macros as the rest of your code, you'd do just as you do for the rest of your code. Write "unit tests" for your macros. It's not rocket science.

Title: Re: Oh, C3!
Post by: PlainName on April 28, 2023, 08:24:25 pm
Quote
I think the main concern people have with macros is ...

They can turn into a write-only language. Especially with heavy use of ##.
Title: Re: Oh, C3!
Post by: Siwastaja on April 29, 2023, 05:33:20 am
Quote
I think the main concern people have with macros is ...

They can turn into a write-only language. Especially with heavy use of ##.

Ignoring DRY and copypasting is way way way worse than a difficult-to-read macro.

Copypaste / search-and-replace bugs happen and they happen a lot. Also difficult to notice for a human reader; in 9 places out of 10, correct type/variable is used, but in one spot... Compared to that, a hard-to-understand macro is much better. Maybe it's hard to read, but you need to read and understand that only once, and then it produces perfect automated copy-paste each time used.

# and ## magic is pretty essential in many types of projects (for example, many different message types in a message processor), because the only other options would be getting rid of most typechecking and writing everything around void* pointers and generic buffers; or copypasting and manually modifying code gazillion of times. Both much worse.
Title: Re: Oh, C3!
Post by: PlainName on April 29, 2023, 07:46:00 am
I guess it depends. From a user perspective, this kind of thing can be tricky:

Code: [Select]
return _lv_obj_get_style##style_type (obj, part, LV_STYLE_##prop_name);

It defeats editor/IDE lookup tools to figure out what it means, so while it no doubt helps the original author (and a user not trying to debug it) it's a drag for anyone else. This is one of the decent uses - I've seen much, much more user-hostile stuff.
Title: Re: Oh, C3!
Post by: Siwastaja on April 29, 2023, 07:56:21 am
Doesn't look too nice, but isn't the alternative copy-pasting and search/replace the whole function? Possibly tens of times? That's just disastrous. Generic programming is needed. In C, that's using preprocessor. In C++, either preprocessor or template system. Generic programming never looks as simple as non-generic, no matter how well designed the language is. It's still super useful.

Title: Re: Oh, C3!
Post by: PlainName on April 29, 2023, 08:06:15 am
Quote
but isn't the alternative copy-pasting and search/replace the whole function?

No idea - I gave up trying to figure out what it all means :)
Title: Re: Oh, C3!
Post by: SiliconWizard on April 29, 2023, 07:46:23 pm
"Obvious" tips to help with macros.

First, document your macros as soon as they are non-trivial. Funnily enough, I've seen A LOT of code in which the C code itself was heavily commented, but macros, almost NEVER.

Then, as I suggested earlier, if you want to be sure of your macros (or someone else's) and you have doubts, just TEST them.

Just because they are macros doesn't mean they are out of scope for testing.

Testing is not difficult.
Write test files that include the macros you want to test (ideally your macros sit in header files so just include the corresponding header files), and a bunch of test cases. It doesn't have to be C code at all. Just a series of macro invocations. Write the expected output in separate files.

Run the preprocessor on these test files and compare the outputs with your expected outputs with diff. All this can be fully automated.
Title: Re: Oh, C3!
Post by: PlainName on April 29, 2023, 09:54:27 pm
I think the issue with stuff like ## is the levels of redirection. We can keep in mind up to 7 levels (if we're good - most people aren't) and a #define is already one level. So you can sit and work it out and even write test cases and know what it does, but then trying to apply that in realtime to what you're looking at is like speaking Spanish while reading Mandarin. And, as I note, the usual tools that let you find, say, a function definition and its associated comments, don't work with this type of macro so you can't easily find any comment either.
Title: Re: Oh, C3!
Post by: cfbsoftware on May 09, 2023, 12:31:15 am
The problem is that it's a half-baked solution: outside of cryptic constructs like the Duff's device, using fallthrough in switch-case in C was mostly meant to emulate the possibility of having cases for multiple values instead of just one. That was much better addressed even in Pascal (if I remember it right) using ranges.
FTR, Standard Pascal has case label lists e.g.

case ch of
  'a', 'e', 'i', 'o', 'u': chtype := vowel;
...
...

This was extended in Modula-2 to include case label lists and subranges e.g.

CASE ch OF
  'a', 'e', 'i', 'o', 'u': type := vowel |
  '0'..'9': type := digit |
...
...