Live data from Hacker News

C Is Not Reasonable

osr.com

51–60 of 71 posts

Re: C Is Not Reasonable

#51
What harsh comments about a person that is just asking for a warning. Tell me, do you really think such a warning wouldn't be reasonable?

I do agree with the author that it would be better if C coerced the operators into the result type before the calculation instead of after. I would really like a warning when there's an implicit coercion at the end of a calculation.

Re: C Is Not Reasonable

#52
post #32

Programming practically requires a willingness to continue learning. But his statements are deeply troubling: > I’m not annoyed by the way statements are formed, or even by the precedence order (which I readily admit to not knowing or understanding or even caring much about) > And don’t complain about how I parenthesize my arithmetic statements. I already mentioned precedence order. All those parens are the result of…

Whilst the delivery could be better, I agree with the sentiment that operator precedence is a waste of time. It's exactly the kind of mundane, error-prone work that machines should be doing for us, whether it's via a sophisticated structured editor, or a simple hack like Emacs's various paredit-like modes.

> Sure, you can pepper all your code in parentheses, but sooner or later you're going to come across code that doesn't. And a person like that working on such a codebase is a huge danger.

I can certainly imagine someone who doesn't care about precedence using an editor which disambiguates such things automatically; either by adding parentheses, colouring the background, etc. I can also imagine such a person spotting precedence bugs introduced by a colleague who considered themselves to be above such tooling.

Lisp, Forth and friends do perfectly well without having to consult precedence tables, and whilst I appreciate that some would prefer more syntax than those provide, I think precedence rules should still stick to the meta-level, parser-directing stuff like block delimiters, statement separators ("x ; y"), and maybe syntax sugar like "," ".", "=", etc. If it can be written as a library (which certainly includes things like numeric procedures) then it shouldn't have any precedence.

Even this minimal amount of precedence should be avoidable if desired, e.g. to avoid ambiguities like "a = b xor c". In PHP this parses to "(a = b) xor c", which is a perfectly valid PHP expression and caused the most egregious waste of my time to date.

Whilst it's true that learning and applying "BODMAS" is simple enough to do in high school arithmetic, the context of high school arithmetic is vastly impoverished compared to computer programming.

For example, which has the higher precedence: integer multiplication or list append? What about floating-point division compared to image convolution? Tree construction or matrix subtraction?

I think such questions are silly, yet they're a legitimate concern in languages with heavy use of infix notation (e.g. Haskell). Languages which define a fixed set of infix operators to avoid such problems (e.g. C) cause an unnecessary asymmetry between operators and every other procedure (e.g. think about the number of times "function(x, y) { return x + y; }" has been written by Javascript programmers!), and are impoverishing their domain of discourse much like high school arithmetic (e.g. compare introductory C material to something like https://code.world/doc.html?help/codeworld.md or http://www.bootstrapworld.org/materials/spring2016/tutorial )

Re: C Is Not Reasonable

#53

It is strange to pick on C for this, as I cannot think of a single language that works the way the author seems to want. The only exception I can think of is Perl, which has the "wantarray" function that lets a function vary its behavior based on what its return is being assigned to: http://perldoc.perl.org/functions/wantarray.html With that exception, it's pretty much always assumed that an expression is evaluated i…

> It is strange to pick on C for this, as I cannot think of a single language that works the way the author seems to want. Agreed, though recent crop of languages with less implicit conversion will reject the entire thing rather than silently expand the value at the end, e.g. in Rust error[E0308]: mismatched types --> :7:19 | 7 | tableOffset = (l1Index * L1_TABLE_GRANULARITY) + | ^ expected u64, found u32 error: abor…

So far I found this mandatory explicit conversion to only get in the way. Caused me a bug even (in Go), because it made it too noisy and very unclear where the value was unnecessarily trimmed.

Re: C Is Not Reasonable

#54

It is strange to pick on C for this, as I cannot think of a single language that works the way the author seems to want. The only exception I can think of is Perl, which has the "wantarray" function that lets a function vary its behavior based on what its return is being assigned to: http://perldoc.perl.org/functions/wantarray.html With that exception, it's pretty much always assumed that an expression is evaluated i…

The surprise would be if you wanted to, say, add 100 to a uint8 and have it wrap, but were assigning the result to a uint64. Then your arithmetic wouldn't wrap, unless you explicitly told it to, i.e. "x = (y + 100) & 0xff;"

Either way leads to surprises if your intuition tells you the other thing should happen.

Strictly, in C the behaviour is undefined when a signed integer overflows. Although it wouldn't help in the author's case, since he's using unsigned integers, it is valid for a compiler to internally promote the operands of signed arithmetic.

Re: C Is Not Reasonable

#55

Earlier quoted context omitted.

To be fair, though, this entire comment thread echoes the main point of the article: in what world is it reasonable to have to keep track of such things?

Drivers, for one. Any world where performance is so critical that you want to ensure you're fitting as much information as you reasonably can into the L1 and L2 caches for the computations you must do. There's even still a role in this world for people to fine tune the assembly code for a specific execution environment to make their HPC models execute faster.

Respectfully, this misses my point (which, granted, was poorly explained).

The necessary evil here is using low-level languages. The unnecessary evil is using a language like C with arbitrary and highly variant conventions.

Better alternatives exist for writing drivers (e.g. Rust). To be clear, historical baggage sometimes dictates that we must use C, but that doesn't change the fact that much of the C world is a footgun, leading to eye-gouging frustration and threads such as this one about the myriad pitfalls associated with the language.

The author might not be a good C programmer, but this thread nevertheless supports his point. The necessity of writing C in practice is neither here nor there.

Re: C Is Not Reasonable

#56
post #53

Earlier quoted context omitted.

> It is strange to pick on C for this, as I cannot think of a single language that works the way the author seems to want. Agreed, though recent crop of languages with less implicit conversion will reject the entire thing rather than silently expand the value at the end, e.g. in Rust error[E0308]: mismatched types --> :7:19 | 7 | tableOffset = (l1Index * L1_TABLE_GRANULARITY) + | ^ expected u64, found u32 error: abor…

So far I found this mandatory explicit conversion to only get in the way. Caused me a bug even (in Go), because it made it too noisy and very unclear where the value was unnecessarily trimmed.

Yeah it's a mixed blessing, implicit conversions are sources of bugs but the lack of them can be a real pain in the ass when mixing numerics of different bit width. Maybe it's possible to write a rustc plugin to opt-in auto-expansion of numeric types in the style of unsafe blocks? E.g. `extend!(numexpr)` which would go through the numeric expression and automatically (sign-|zero-)extend values to make it typecheck?

Re: C Is Not Reasonable

#57

Earlier quoted context omitted.

This may lose precision. Depending on architecture & compiler & flags, your mantissa may be big enough to hold your whole int. An 80 bit extended double has 64 bits of significand. https://en.wikipedia.org/wiki/Extended_precision#x86_extende...

This will lose precision, as any floating point operation is only accurate to 1 unit in the last place (ULP). Even simple addition.

This conversion will not lose precision!

With a 64-bit mantissa, ULP(x) is ≤ 1 for x in [-2e64, 2e64]. If you have the time you can count up to 2^64 by repeatedly incrementing a float80(0.0) by 1.

Addition, subtraction and multiplication on float80s are perfectly stable provided the results stays within [-2e64, 2e64].

Re: C Is Not Reasonable

#58

Earlier quoted context omitted.

Drivers, for one. Any world where performance is so critical that you want to ensure you're fitting as much information as you reasonably can into the L1 and L2 caches for the computations you must do. There's even still a role in this world for people to fine tune the assembly code for a specific execution environment to make their HPC models execute faster.

Respectfully, this misses my point (which, granted, was poorly explained). The necessary evil here is using low-level languages. The unnecessary evil is using a language like C with arbitrary and highly variant conventions. Better alternatives exist for writing drivers (e.g. Rust). To be clear, historical baggage sometimes dictates that we must use C, but that doesn't change the fact that much of the C world is a foo…

Rust and its ilk may eventually eat this space, but it doesn't appear ready. For one, it's list of supported architectures is too small. For two, it's poorly optimized, when compared to C. Three, it's still too new - it has only been "stable" for a bit over a year. Four, the static verification tools are not yet there (you still need a way to verify the unsafe portions of code, which will not be trivial in a driver).

Do you know of any existing non-toy (i.e. distributed in support of a device) drivers which have been written in Rust? I'd love to see some in action, and will be happy revise my opinion of Rust's capabilities when those drivers start rolling out.

Let's be frank for a moment. Rust's biggest advantage in this space is its memory safety. But we've had memory safe languages for as long as we've had C, and they still have not eaten C's lunch. If Rust wants to pave the way into C's territory (and not just C++'s territory), it will need to identify why and address that.

Re: C Is Not Reasonable

#59
post #25
post #7

Arithmetic is surprisingly hard to get "right". You might try to generalise from this example that "multiplying two N bit numbers together should give a result 2N" wide, then discover that for simple examples you run out of machine bits. Then there's overflow/saturation handling, which is a mess everywhere: lots of systems have hardware support for saturation arithmetic, but you can't conveniently specify it in C. If…

For modern applications programming, arbitrary-precision is probably the right way to do integer arithmetic. Python does that, and it doesn't seem to cause any trouble. The people who need to do massive amounts of numeric stuff know who they are and can take the time to learn the relevant arcana, but your typical cat pictures app never has to worry about how big any of its integers are.

If Python handled overflow with an exception instead of a bignum, I'd bet it still wouldn't cause trouble either. The actual values generally aren't reaching bignums.

Re: C Is Not Reasonable

#60
post #44
post #30

Earlier quoted context omitted.

Yeah, I recently read on some forum someone who was looking for a quick C++ training for a friend and said "he doesn't need a deep training, just some basic syntax, he's not a programmer, that doesn't interest him, he's just doing scientific calculus". I was like: Oh boy... getting arithmetic calculation right is really tricky and you have to understand many not-obvious details, especially concerning the behaviour of…

The Cambridge (UK) maths undergraduate course used to do exactly this; include a numerical programming section without any training. They effectively just gave people a small volume of API calls and expected them to get on with it. The only reason it worked at all was a small number of undergraduates who could already program running guerilla assistance courses in C for bewildered mathematicians. Programming is becom…

Intel's 80-bit FP issues are only an issue on 32-bit platforms, amd64 stuff uses SSE. (Right?)
Post reply on HN