Live data from Hacker News

Two types of C programmers

utcc.utoronto.ca

211–220 of 225 posts

Re: Two types of C programmers

#211

Earlier quoted context omitted.

To pick the same example from both, I hate both fork() and CreateProcess(). Microsoft wrote "A fork() in the Road" [1] describing the problems with fork(), and they are right: fork() is too simple, it doesn't scale, it is inefficient, and error handling becomes next to impossible. (In my code, I have the child process return exit codes from 255 on down for error handling. It assumes, probably wrongly but right enough…

The irony is that what you describe is pretty much the traditional OO way of doing things. In C#: var process = new Process(); process.StartInfo.FileName = "foo.exe" ... process.Start();

Oh, that's cool! I didn't know that.

Re: Two types of C programmers

#212
post #210

Earlier quoted context omitted.

That is an interesting point. I wonder if it would be feasible to go over every little bit of UB in the Standard and see if it could instead be well-defined in a way that would be compatible with most existing C code out in the wild. How much perf overhead that would actually be? And is there a way to quantify how many exploits that would have prevented?

this was dan bernstein's project with 'boring c' and john regehr's with 'friendly c'; i think the answer is that most of it can be, but definitely not all, and possibly on some platforms it wouldn't be most existing c code https://blog.regehr.org/archives/1287 basically it seems feasible but it's going to be a lot of effort also of course any semantics change will introduce some new exploits, but doing that once seem…

To be clear, I'm thinking specifically from the perspective of making existing legacy code less broken, not about making the language "more friendly" - as you rightly point out, C really ought to be considered legacy by now (and in new languages, where we will also have this discussion, we can at least begin it from a clean slate). Thus there's no need to consider usability. I was also imagining a hard rule: if the only reason why something is UB is perf overhead, it must not be UB (this covers e.g. the memcpy/memmove debate brought up in that article). But, yeah, as the other example with shifts illustrates, even such tight-fisted approach can be problematic.

The real question is how much perf overhead this entails vs how much benefit from mitigating yet-undiscovered issues caused by UB in legacy code.

Re: Two types of C programmers

#213

Earlier quoted context omitted.

> If you don't believe me, ask the Zig team how they plan to solve this problem. Don't ask them if they plan to solve it; ask them how. The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. The counter can be manually set to a higher value but all compilations will eventually fail if your comptime logic is too loopy. In practice…

> The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. Okay, here's a solution. It's already implemented. Nice. Now let me destroy it. You said those compilations "fail"; I presume there's an error that kicks in. In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-compl…

> In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-complete. It's also less powerful; there are going to be things that Zig's type system cannot express.

I think you're a bit too high on all this compsci theory stuff.

All computations in all languages (including ones generally considered to be turing complete) fail when you run out of resources like RAM or patience. Zig introduces an artificial quantity that can be used as a machine-independent way to ensure all compilations eventually end in either success or failure. It's like a timeout, but an actual timeout would be inconsistent across different machines (with different performance characteristics).

The actual state of things is much more boring than what your analysis tries to suggest: comptime is used to do some metaprogramming whose practical value is in good part determined by it not being too crazy, so the fact that you can't make a DisprovesCollatzConjecture type is actually fine.

You have found another feature of Zig that's even more mundane than async where you're trying really hard to misunderstand everything to indulge in... "destroying".

I think your own wording betrays the fact that you care about needlessly debating people more than actually understanding the tools in front of you in order to produce better software.

Re: Two types of C programmers

#214

Earlier quoted context omitted.

> If you don't believe me, ask the Zig team how they plan to solve this problem. Don't ask them if they plan to solve it; ask them how. The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. The counter can be manually set to a higher value but all compilations will eventually fail if your comptime logic is too loopy. In practice…

> The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. Okay, here's a solution. It's already implemented. Nice. Now let me destroy it. You said those compilations "fail"; I presume there's an error that kicks in. In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-compl…

> then some valid Zig programs will be rejected

A program is defined to be invalid when it runs out of counters. Problem solved.

>Also, if you step out to dedicated build steps, then the compiler no longer has complete visibility into that code when analyzing.

You can't really "generate code" in these dedicated build steps. Kristoff is talking about generating data. you could maybe build an object file, but then it's bound in using c abi, statically, which we've already solved in this conversation.

>Also, what do you do if a user needs to pass a function pointer to a C function? I presume they must use a sync function? If so, that seems like a direct application of the function colors definition;

In the long run for zig, calling out to c abi, much less one which takes a function pointer, much less one which you happen to have as async, is going to be a rare enough operation that I think people aren't clamoring to go and use it, which fails one of the criteria for your function coloring list. Besides, you just quickly wrap it in noasync context and you're done (you can't pass a zig callconv function directly to a c abi callconv site without at least a tiny wrapper anyways).

Re: Two types of C programmers

#215

Earlier quoted context omitted.

> If the type system is uncomputable, then the type system will never be able to resolve all uses of function pointers everywhere. Can you elaborate on what you mean here, and the problems this might cause? Do you mean that some function pointers cannot be resolved to concrete functions? Or that the process of evaluating comptime may be infinite? Or some other problem where the compiler can't determine whether a func…

These are great questions. All of the above, actually. Turing-completeness and the uncomputability thereof are widespread, easy to build, hard to keep away, and affects everything that might happen at runtime. A list of things that can happen is infinite, but that list absolutely includes: * Whether a particular function pointer resolves to certain functions, * Whether evaluating the comptime portion of a Zig program…

> Whether a particular function pointer resolves to certain functions

This is only a turing completeness issue if the list of functions is infinite. It is not, in zig.

Re: Two types of C programmers

#216

Earlier quoted context omitted.

> The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. Okay, here's a solution. It's already implemented. Nice. Now let me destroy it. You said those compilations "fail"; I presume there's an error that kicks in. In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-compl…

> In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-complete. It's also less powerful; there are going to be things that Zig's type system cannot express. I think you're a bit too high on all this compsci theory stuff. All computations in all languages (including ones generally considered to be turing complete) fail when you run out of resources like RAM o…

Comptime is too crazy.

Comptime is powerful, but without that counter, it's effectively uncontained.

With that counter, it's contained, but then some comptime stuff needs to be separate, where users lose the benefits of Zig's all-at-once compilation model, a model that is necessary because of the feature of hiding function colors.

If you think I care about "needlessly debating people more than actually understanding the tools in front of me," let me dispel that notion.

I was once a fan of Zig.

Yep. I was. I thought it was great and was even going to rewrite all of my monorepo in it.

And then I started studying it in detail, trying to understand it. It took a while, but I came to realize that Zig appears good and has flashy ideas, but that Andrew just didn't understand the consequences of his design decisions.

In other words, I spent time trying to understand Zig before I ever got these opinions.

To go back to the topic, sure the use of this may appear boring, but if tools have a hard time working with Zig code, so will people. That's my problem with it.

You are absolutely right that this is a "boring" part of Zig, but that doesn't mean it's good. It means that that's where complexity hides.

Once I figured that out, I realized that to make better software, it would be better for me to stick with C.

My wording, by the way, comes from a bit of exasperation because to me, it feels like you, Andrew, and the rest of the Zig team are reluctant to accept criticism or that Zig isn't perfect or even the best.

Re: Two types of C programmers

#217

Earlier quoted context omitted.

> The Zig compiler has a counter that describes the maximum allowed amount of branching that the compiler can do while evaluating comptime code. Okay, here's a solution. It's already implemented. Nice. Now let me destroy it. You said those compilations "fail"; I presume there's an error that kicks in. In that case, then some valid Zig programs will be rejected, but your type system is now not technically Turing-compl…

> then some valid Zig programs will be rejected A program is defined to be invalid when it runs out of counters. Problem solved. >Also, if you step out to dedicated build steps, then the compiler no longer has complete visibility into that code when analyzing. You can't really "generate code" in these dedicated build steps. Kristoff is talking about generating data . you could maybe build an object file, but then it'…

> A program is defined to be invalid when it runs out of counters. Problem solved.

Except that the counter can be adjusted by users.

> You can't really "generate code" in these dedicated build steps. Kristoff is talking about generating data. you could maybe build an object file, but then it's bound in using c abi, statically, which we've already solved in this conversation.

So any code generated outside has to be sync? That's exactly what I thought.

But even if Zig only allowed people to generate only data, this is a pretty big limitation.

This may not be a problem now, but it does mean that as Zig programs grow, people will run into this problem. I suspect that this means that Zig will struggle more than C to scale, maybe even more than C++ or Rust.

> In the long run for zig, calling out to c abi, much less one which takes a function pointer, much less one which you happen to have as async, is going to be a rare enough operation that I think people aren't clamoring to go and use it

This assumes that people won't want to interface with software that isn't in Zig. This is another way that Zig will struggle to scale.

> Besides, you just quickly wrap it in noasync context and you're done

This sounds exactly like a special calling technique mentioned in the function colors post.

> (you can't pass a zig callconv function directly to a c abi callconv site without at least a tiny wrapper anyways).

And this also sounds exactly like a special calling technique.

Re: Two types of C programmers

#218

Earlier quoted context omitted.

These are great questions. All of the above, actually. Turing-completeness and the uncomputability thereof are widespread, easy to build, hard to keep away, and affects everything that might happen at runtime. A list of things that can happen is infinite, but that list absolutely includes: * Whether a particular function pointer resolves to certain functions, * Whether evaluating the comptime portion of a Zig program…

> Whether a particular function pointer resolves to certain functions This is only a turing completeness issue if the list of functions is infinite. It is not, in zig.

You don't need an infinite list of functions to run into the problems with Turing-completeness. You only need effectively infinite behavior, which means all you need is effectively infinite possible inputs.

Re: Two types of C programmers

#219

Earlier quoted context omitted.

> then some valid Zig programs will be rejected A program is defined to be invalid when it runs out of counters. Problem solved. >Also, if you step out to dedicated build steps, then the compiler no longer has complete visibility into that code when analyzing. You can't really "generate code" in these dedicated build steps. Kristoff is talking about generating data . you could maybe build an object file, but then it'…

> A program is defined to be invalid when it runs out of counters. Problem solved. Except that the counter can be adjusted by users. > You can't really "generate code" in these dedicated build steps. Kristoff is talking about generating data. you could maybe build an object file, but then it's bound in using c abi, statically, which we've already solved in this conversation. So any code generated outside has to be sy…

> Except that the counter can be adjusted by users.

So? You've changed the program, and now it's valid. (as my handle suggests) I was a math major: arbitrarily large but finite is a different category than infinite, and that makes all the difference in the world.

> his sounds exactly like a special calling technique mentioned in the function colors post.

No, but the seam between async and sync in most other implementations requires writing an entire event loop. In this case it's often a single keyword, six characters. At worst, you write an extra function header to wrap it.

It's not the extraness that matters, it's the pain of doing so. Hell, even go requires you write "go" in front of your function to run it asynchronously, and I don't think that this counts as "colored functions".

Re: Two types of C programmers

#220

Earlier quoted context omitted.

> Whether a particular function pointer resolves to certain functions This is only a turing completeness issue if the list of functions is infinite. It is not, in zig.

You don't need an infinite list of functions to run into the problems with Turing-completeness. You only need effectively infinite behavior , which means all you need is effectively infinite possible inputs.

this is simply untrue. I'm sorry. I recommend studying math a bit more rigorously before making claims in the future.
Post reply on HN