Endianness is critical, yet C has no standard facility to find out what endianness the host uses, nor to convert values to and from a specific endianness. Due to other problems, these are not trivial to handle yourself either!
The whole “binary input and output” section seems like nonsense to me. There are also a lot of complaints about C not guaranteeing specific kinds of integer, but C only doesn’t guarantee them so that it can be ported to platforms which don’t have them. The fixed-width types do always exist if you restrict yourself to targets that can run Javascript.
The stuff about overflow and out-of-bounds array access is fair enough, although I personally think Javascript does about the worst thing a memory-safe language could possibly do in both cases (yield a value instead of indicating an error).
There are also a lot of complaints about C not guaranteeing specific kinds of integer, but C only doesn’t guarantee them so that it can be ported to platforms which don’t have them.
Which is ridiculous! How many users want to be able to rely on fixed-size integers vs how many users want to target a platform that doesn’t hav 8/16/32 bit integers? (How many have even seen one?)
I obviously hid this fact better than I meant to in my last comment: The people who don’t want to target those weird old platforms can rely on fixed-width integers, and have been able to for decades. The weird concessions C made to support weird old architectures sometimes affect programmers who don’t care about those architectures, but this is not one of those times. Nothing in the C standard requires you to write code that will work with 9-bit bytes.
I really like the way that Smalltalk handles integers, which (I believe) is adopted from Lisp. Integers are stored with a tag in the low bit (or bits on 64-bit platforms). If they overflow, they are promoted to big integer objects on the heap. If you do arithmetic that overflows the fast path in Smalltalk, then your program gets slower. This doesn’t mean that it can’t lead to security vulnerabilities, but they’re a less serious kind (an attacker can force you to allocate a huge amount of memory, they can’t access arrays out of bounds). It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
This is not possible in C because C has to work in situations where heap allocation is impossible. If you write a+b in a signal handler, you may deadlock if the thread that received a signal in the middle of malloc, if addition is allowed to allocate memory to create big integer objects. If you’re using C in a situation where memory allocation is always fine, you’re probably using the wrong language.
I’m pretty sure all Python objects are really pointers with their own object headers. “small” integers (-5 to 256, inclusive) are statically allocated and most ways of getting these values will share them. Most, but not all:
>>> 7 is 6+1
True
>>> 7 is int('7')
True
>>> 7 is int.from_bytes(b'\x07', 'big')
False
but in any case they’re still real objects which reside at real locations in memory. Python does use long arithmetic instead of its base-2**30 big integers when it can, but it doesn’t have any other tricks to avoid allocation, as far as I know.
Accurate, but the parent comment is mainly around underlying implementation rather than the fact that Python does object interning for the sake of efficiency. The interning Python (and some other languages) does has unintended consequences though: I recall spending a whole hour convincing a developer I used to work with that == and is are not interchangeable. I literally had to show you them the C source to show exactly where the interning of small integers was happening before they’d believe me.
Yeah, I went through all that, and that’s what was so frustrating about it. 1 << 10 gets interned because it evaluates to a constant, as you noted. Constants are interned in addition to small numbers, hence why I ended up having to point all this out in the Python source code before I was believed.
It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
Wasn’t JS famously developed during a weekend or something … snark aside, it is a bit sad that so many people just accept the limitations of C instead of looking at other solutions.
A basic Scheme interpreter is really easy to implement over a couple of days, especially when you’ve a full runtime to lean on for a bunch of the awkward bits. Converting the original LiveScript over to a C-like syntax probably took longer than the original interpreter.
“An ancient memory-safe language is more memory-safe than a language that isn’t memory safe” is hardly surprising.
(And in case someone’s not aware: yes, undefined behaviour from integer overflow is a memory-safety issue. Undefined behaviour is always a memory safety issue).
Edit: I probably just should’ve let this go. I’m just so tired of people complaining about integer overflow in C. How hard is it to add -fwrapv to a command line?
Tell me you know nothing about C programming without telling me you know nothing about C programming…
The whole “binary input and output” section seems like nonsense to me. There are also a lot of complaints about C not guaranteeing specific kinds of integer, but C only doesn’t guarantee them so that it can be ported to platforms which don’t have them. The fixed-width types do always exist if you restrict yourself to targets that can run Javascript.
The stuff about overflow and out-of-bounds array access is fair enough, although I personally think Javascript does about the worst thing a memory-safe language could possibly do in both cases (yield a value instead of indicating an error).
Which is ridiculous! How many users want to be able to rely on fixed-size integers vs how many users want to target a platform that doesn’t hav 8/16/32 bit integers? (How many have even seen one?)
I obviously hid this fact better than I meant to in my last comment: The people who don’t want to target those weird old platforms can rely on fixed-width integers, and have been able to for decades. The weird concessions C made to support weird old architectures sometimes affect programmers who don’t care about those architectures, but this is not one of those times. Nothing in the C standard requires you to write code that will work with 9-bit bytes.
I really like the way that Smalltalk handles integers, which (I believe) is adopted from Lisp. Integers are stored with a tag in the low bit (or bits on 64-bit platforms). If they overflow, they are promoted to big integer objects on the heap. If you do arithmetic that overflows the fast path in Smalltalk, then your program gets slower. This doesn’t mean that it can’t lead to security vulnerabilities, but they’re a less serious kind (an attacker can force you to allocate a huge amount of memory, they can’t access arrays out of bounds). It makes me sad that JavaScript, coming over twenty years after the techniques that made this fast were invented, just used doubles.
This is not possible in C because C has to work in situations where heap allocation is impossible. If you write
a+b
in a signal handler, you may deadlock if the thread that received a signal in the middle ofmalloc
, if addition is allowed to allocate memory to create big integer objects. If you’re using C in a situation where memory allocation is always fine, you’re probably using the wrong language.This is how Python also works.
There was a proposal to add it to Go, but it never went anywhere because it would break existing code. https://github.com/golang/go/issues/19623
I’m pretty sure all Python objects are really pointers with their own object headers. “small” integers (-5 to 256, inclusive) are statically allocated and most ways of getting these values will share them. Most, but not all:
but in any case they’re still real objects which reside at real locations in memory. Python does use long arithmetic instead of its base-2**30 big integers when it can, but it doesn’t have any other tricks to avoid allocation, as far as I know.
Accurate, but the parent comment is mainly around underlying implementation rather than the fact that Python does object interning for the sake of efficiency. The interning Python (and some other languages) does has unintended consequences though: I recall spending a whole hour convincing a developer I used to work with that
==
andis
are not interchangeable. I literally had to show you them the C source to show exactly where the interning of small integers was happening before they’d believe me.Tricky: I thought using a big enough number would make this obvious:
but this one comes out True…
Ok, so I’ll try even bigger numbers, but I’ll factor out N first:
wat (:
Apparently it’s constant folding, and then sharing the constant:
Yeah, I went through all that, and that’s what was so frustrating about it.
1 << 10
gets interned because it evaluates to a constant, as you noted. Constants are interned in addition to small numbers, hence why I ended up having to point all this out in the Python source code before I was believed.Wasn’t JS famously developed during a weekend or something … snark aside, it is a bit sad that so many people just accept the limitations of C instead of looking at other solutions.
From my vague recollections, it was originally meant to be Scheme with Java syntax, so not knowing how Lisp did numbers was a bit surprising.
A basic Scheme interpreter is really easy to implement over a couple of days, especially when you’ve a full runtime to lean on for a bunch of the awkward bits. Converting the original LiveScript over to a C-like syntax probably took longer than the original interpreter.
You can also use
(a + b) >>> 0
, which I’d expect to be more efficient.“An ancient memory-safe language is more memory-safe than a language that isn’t memory safe” is hardly surprising.
(And in case someone’s not aware: yes, undefined behaviour from integer overflow is a memory-safety issue. Undefined behaviour is always a memory safety issue).
Edit: I probably just should’ve let this go. I’m just so tired of people complaining about integer overflow in C. How hard is it to add
-fwrapv
to a command line?…doesn’t work for multiplication, though.
Fortunately, if you are able to use circa 2013 javascript there’s Math.imul()
WAT?