Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
jahboater wrote: ↑Sat Apr 03, 2021 6:17 pm
I fear a quest to find something actually better than C is doomed to failure.
I think we should be wary of using words like "better". At least not without qualifying what we are comparing. Else we end up comparing very different things that are not really comparable.
For example, can we say C is better than assembler? Maybe, for a given job. Certainly not for all. Still one can write assembler that the C language has no idea about. Thing is C and assembler are at different levels of abstraction. They both suit their intended abstraction level very well.
One could compare things at the same abstraction level. Debating this assembler syntax vs that assembler syntax. Or, at a higher level of abstraction, comparing C to Pascal or PL/M. Higher still we can debate the merits of Python vs Javascript vs Julia or whatever.
Yes exactly.
Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
So, in my view, it's not about finding something better than C. It's about finding a new, different, thing at a higher level of abstraction. Preferably without losing performance or bloating code size along the way, for most of the jobs we want that new thing for.
I saw this text somewhere on the net about abstraction:
Each level of abstraction you apply over and above assembler means added
complexity and more generic functionality to encompass all the possible use
cases. That means each thing you want to do will take more time and more
resource per call. C is (so far) the lightest practical abstraction of
assembler that we have, hence its one of the fastest high level languages.
Expanded:
All computers execute assembly. How that assembly gets written is very
important. If you write it by hand, you are only performing the operations that
you require. But assembler is really really hard to write so some smart people
started abstracting it.
C was not the first abstraction language, but C is a very fast language because
it closely maps to the groups of assembly instructions you need to perform
simple tasks. Moreover, C gives you direct access to memory and resources,
meaning you can manipulate these things yourself (thus increasing performance
by optimizing how you use the memory/resources).
As has been pointed out, while C is fast, its not very safe. So some more smart
people decided that they would abstract from C to make it easier (and safer) to
write good code. As computers have been getting exponentially faster for most
of computing history, this approach made sense. However, every layer of
abstraction (read language) over and above C more or less boils down to a C
call, or groups of C calls. *This is the really important point*. There are
very few language compilers and VMs that convert from a language directly to
assembly - they typically convert to C libraries that are then converted to
assembly (those that do compile to assembly instead of C are screaming fast
such as the LuaJIT which has hand written assembler). Some VMs have an
intermediary abstraction layer (C#, Java), but in the end, Languages very
rarely boil down to straight assembler calls. The .Net VM for instance uses
Intermediate Language which is JIT compiled to its own VM internal
instructions, which in turn execute assembler.
In order to make the C calls that you abstract safe, there needs to be checks
made to ensure proper functioning, as well as abstractions that allow for
larger groupings of common scenarios. Each safety check, each generalized
function, and every extra resource that is used during the abstraction adds
time and resources to your total execution path.
As an example in practical terms, if you can write 10 lines of C to perform a
task (and you know its safe because of the code is custom written for that
functionality) a higher level language would need say 50 lines of C (an example
only) to check if there are resource violations or to abstract something to a
level to be useful across more use cases.
So in our example, our other language would need 5 times the number of calls to
perform the same action. That wouldnt be bad if language abstraction was
simple, but its not. So if you had a function that needed to call your custom C
code 100 times, you would be executing 1000 C instructions. But because we
wrote it in other language we abstracted it to work in more cases and be safer,
we now need to execute 5000 C instructions.
But what if we abstracted our abstraction (Im looking at you Python) and made
it really generic? What if that new abstraction was done at the cost of say two
calls to our original library, plus some other stuff? Now we are looking at
some serious performance penalties. instead of 5000 lines of C, we are now at
10,000+ lines of C. Which is could be very noticeable, depending on how often
that abstraction-abstraction is called.
This is a super simplified view of the problem, but you get the point:
Abstractions can cause non-linear and even exponential increases in resources
to simplify coding for the programmers. The same thing is easily applicable to
all computer resources including memory, disk access, networking, etc.
Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
I really would like a C like language with:
1) A proper type system.
Yes, the C typedef isn't much more than an alias! Useful in places.
Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
2) A text string type.
You noted once before that there was little mention of "strings" in the C standard. Which is true.
But then there is a reason, for that. They are very simple, there is nothing much to say about them. The clear relationship between C strings and array's of any other type is a good thing in my book. Vast amounts of complex text handling code has been written over the years with these simple strings.
They are simply arrays of chars, with a handy literal notation, a NUL terminator, and a few simple library functions to manipulate them.
Most importantly, their access is extremely efficient, there is only one byte of space overhead, and they are conceptually simple for beginners.
Once you start messing with things like this:
typedef struct { size_t length; char text[]; } string;
it all goes horribly wrong when you think about the practicalities of it.
Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
3) Like a high level language like C relieves the programmer of a lot of book keeping busy work, like constructing loops, function calls and so on he had to do in assembler, I'd like a language that takes care of the busy work of taking care of memory allocation/deallocation.
Smart pointers I suppose? TBH, I've never found memory allocation/deallocation to be a huge issue. Its just programming. I very rarely have bugs here. Its all very simple. But then I have been programming in C for such a long time that the care needed to avoid bugs in this area is second nature. Same with array bound checks and similar stuff. My bugs tend to be elsewhere!
Heater wrote: ↑Sat Apr 03, 2021 8:16 pm
Not asking much, am I?
Well this sort of list is personal and would differ from user to user.
Not sure what my list would look like.
I don't use all the features of C now, such as the C11 generics and the async stuff!
I'm a big fan of static error checking and I am pleased that modern C compilers do as good a job as any other language at advanced error detection and diagnostics. Run time checking, where object values cannot be determined by data-flow analysis or any other method, must involve run-time overhead which is a no-no in my book (I can add checks myself in sensitive places).