Live data from Hacker News

C Is Not Reasonable

osr.com

31–40 of 71 posts

Re: C Is Not Reasonable

#31
post #4

Earlier quoted context omitted.

As someone who only has a passing knowledge of C, why is that wrong? Is it because it should be "uint_64" instead?

> When in doubt, stick a (double) in front of it If casting from an integer type, this loses precision. Why would this make tests pass? Are there any secondary effects? The author apparently made no effort to find out.

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...

Re: C Is Not Reasonable

#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 yet another lesson I learned to avoid working weekends.

... his example is saying (a×b)+(c×d)+e->f. I understand it being a learning curve to memorize that bit-shifts have higher precedence over bitwise operators, but ... you learn that multiplication happens before addition in elementary school! It's a pre-requisite to learning pre-Algebra in middle school. This isn't even some arcane programming thing you have to learn.

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 don't say this to be mean, but I really don't think programming is the right profession for this guy.

Re: C Is Not Reasonable

#33
post #29

C is a minimal abstraction over asm and I wouldn't be surprised if this behavior can be configured in some C compiler, even though it would be odd to do so. What I find surprising is when people say C is a simple and small language that's nice to build portable programs in. So much of C is undefined behavior or implementation specific that many professional users pin a certain compiler toolchain version for a project…

C portability is not portability in the Java or Python sense. It's portability across architectures, and undefined (and implementation-defined) behavior is a powerful tool for that.

Re: C Is Not Reasonable

#34
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.

> Python does that

So do Ruby or Erlang. The problem, of course, is that it has a cost: trivial arithmetic operations have to be checked and may need to allocate.

And operational coverage can be spotty outside of the trivial range e.g. when you give a bignum to an "integer" operation going through FPN, bad things can happen as said FPN are generally machine doubles (fp64)

Re: C Is Not Reasonable

#35
post #18

Earlier quoted context omitted.

It would be nice if languages allowed us to overload function names with the exact same parameters but different return types. The compiler or runtime environment should be able to select the correct implementation automatically based on type inference, or allow the programmer to specify which one should be used with an annotation. This would make some code a little cleaner instead of having to give all of those func…

> It would be nice if languages allowed us to overload function names with the exact same parameters but different return types. Haskell's typeclasses kind-of do that. `read` has type `Read a => String -> a`, so the result's type `a` (which can be inferred) drives which "Read" instance will be used: Prelude> read "1" :: Int 1 Prelude> read "1" :: Float 1.0

> Haskell's typeclasses kind-of do that.

You're over-hedging. As your example shows, Haskell's typeclasses exactly do that.

Re: C Is Not Reasonable

#36

"This is wrong, and there's a way to fix it, but shut up I don't want to learn." ok...

Indeed. The post begins with a question and asserts that the reader doesn't know the answer. I knew the correct answer instinctively and I haven't written any C in anger in years. Expecting a C compiler to promote expression operands prior to assignment because the output location is a larger size... that's just not the mentality C programmers develop; what if the output is smaller? Should all the expression operands be demoted automatically, producing radically different results as large numbers get truncated prior to evaluation? No. Obviously not. That sort of thing is self-evident to a competent C programmer.

Re: C Is Not Reasonable

#37

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…

Looks like a use-case for typeclasses, e.g. those in Haskell. A typeclass is like a Java interface, except the method lookup can use the return type as well.

For example, we could make "plus" depend on the return type:

    -- "plus" takes two instances of "Number" and returns an "a"
    class Additive a where
      plus :: (Number b) => b -> b -> a

    -- Take two Numbers and return an Int
    instance Additive Int where
      plus x y = intPlus (toInt x) (toInt y)

    -- Take two Numbers and return a Float
    instance Additive Float where
      plus x y = floatPlus (toFloat x) (toFloat y)
We can even abuse this to do ugly hacks, like making "plus x y" return a list of "[x + y]" when the return type requires a list:

    -- Take two Numbers and return a list containing their sum
    instance (Additive a) => Additive (List a) where
      plus x y = [plus x y]
Alternatively, we could have returned "[plus x 0, plus y 0]" to make things even uglier ;)

Re: C Is Not Reasonable

#38

Earlier quoted context omitted.

> It would be nice if languages allowed us to overload function names with the exact same parameters but different return types. Haskell's typeclasses kind-of do that. `read` has type `Read a => String -> a`, so the result's type `a` (which can be inferred) drives which "Read" instance will be used: Prelude> read "1" :: Int 1 Prelude> read "1" :: Float 1.0

> Haskell's typeclasses kind-of do that. You're over-hedging. As your example shows, Haskell's typeclasses exactly do that.

I'm mostly hedging on the "overloading" part as Haskell doesn't support arbitrary ad-hoc polymorphism in the sense of C++/Java/C# (IIRC the foundational paper on typeclasses is about making ad-hoc polymorphism less ad-hoc). Depending how far into the overloading field nradov is, typeclasses may not match their definition of or requirements for overloading.

It's probably more noticeable in Rust than in Haskell.

Re: C Is Not Reasonable

#39
post #20
post #4

Earlier quoted context omitted.

As someone who only has a passing knowledge of C, why is that wrong? Is it because it should be "uint_64" instead?

Well, uint64_t ;) - but ULONGLONG is uint64_t, so it's the same thing. The real "problem" here is presumably that ULONGLONG is a Windows-specific type, probably. (I say probably, because you can always make your own type called ULONGLONG - there's no rule to stop you.) People do like to mock people who program for Windows.

ULONGLONG is in fact a Windows Drivers Kit specific type. WDK has its own specialised set of weird and uncomfortable type conventions in the MS style [0] and although the author's point about C arithmetic type promotion is generic, his context is WDK device drivers, so ULONGLONG is absolutely correct, if possibly somewhat archaic (there's a ULONG64 lately).

[0] https://www.osr.com/blog/2015/05/27/newbie-corner-theres-typ...

Re: C Is Not Reasonable

#40
post #29

C is a minimal abstraction over asm and I wouldn't be surprised if this behavior can be configured in some C compiler, even though it would be odd to do so. What I find surprising is when people say C is a simple and small language that's nice to build portable programs in. So much of C is undefined behavior or implementation specific that many professional users pin a certain compiler toolchain version for a project…

C portability is not portability in the Java or Python sense. It's portability across architectures, and undefined (and implementation-defined) behavior is a powerful tool for that.

Of course, but shifting the burden onto developers, where most of them aren't professional libc or kernel engineers, leads to avoidable issues.

Rust seems familiar enough to many developers, and forces them to think about resource management before running the code by not allowing incorrect code, so I hope it will lead to more libraries and applications that would have otherwise been easily plagued with issues due to choosing C. Granted, I'm not a fan of how Rust's surface has turned out, but it's a sensible compromise to attract masses of developers into writing less buggy code that operates on the same level as that written in C. So I use it as a C replacement, and for that use case I like it because there's momentum behind it.

Post reply on HN