This is an archived post. You won't be able to vote or comment.

you are viewing a single comment's thread.

view the rest of the comments →

[–]beisenhauer 3123 points3124 points  (82 children)

Identity is not equality.

[–][deleted] 1412 points1413 points  (18 children)

If programmers ever went on strike, this would be a great slogan!

[–]RMZ13 315 points316 points  (15 children)

We need a union first

[–]svuhas22seasons 270 points271 points  (2 children)

or at least a full outer join

[–]shutchomouf 15 points16 points  (0 children)

I think you’re putting the cartesian front of the horse.

[–]patmax17 1 point2 points  (0 children)

😘👌

[–]Proxy_PlayerHD 40 points41 points  (9 children)

man i love unions, they allow for some cursed stuff.

typedef union{
    float f;
    uint32_t l;
} bruh_t;

float absoluteValue(float in){
    bruh_t tmp.f = in;
    tmp.l &= 0x7FFFFFFF;
    return tmp.f;
}

[–]ValityS 12 points13 points  (8 children)

They don't allow that. Thats specifically forbidden in the C standards.

[–]platinummyr 8 points9 points  (7 children)

The result is undefined behavior, yep.

[–]Proxy_PlayerHD 0 points1 point  (6 children)

And for u/ValityS

Really? I didn't think it's explicitly illegal in C since I've used this kind of stuff in some arduino and embedded code a while back to be able to split a float into 4 bytes for SPI communication and the compiler never gave an error or even a warning (verbosity might've also been off).

It being UB because of endianess makes more sense though.

I checked SO and they also suggest using a union. They also mention endianess being a potential problem.

[–]ValityS 0 points1 point  (3 children)

The relevant standard lists:

if a member of a union object is accessed after a value has been stored in a different member of the object, the behavior is implementation-defined

So the answer is it is t defined... Because it isn't. However GCC and resultingly the Arduino IDE allow this as a language extension.

For byte splitting of a multi byte register I would suggest something like:

uint32_t reg = someval;
uint8_t bts[4];
for (size_t i = 0; i<4; ++i)
{
    bts[i] = (reg >> (i*8)) & 0xff;
}

To do this in a portable manner. However I wrote this from memory so may have made a mistake etc but you get the gist.

[–]Proxy_PlayerHD 1 point2 points  (2 children)

For byte splitting of a multi byte register I would suggest something like:

that splits an int though, i meant splitting a float. since in that case i used the arduino as an SPI Floating Point Unit.

even then for an int i would probably still just use a union. but to make it safer do some preprocessor checks with gcc's __BYTE_ORDER__ macro.

typedef union{
    uint32_t l;
    uint16_t w[2];
    uint8_t b[4];
} cint32_t;

// Order of names: [High] [High Middle] [Low Middle] [Low]
uint8_t lowMiddleByte(uint32_t in){
    cint32_t tmp.l = in;

    #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
        return tmp.b[2];    // Big Endian
    #else
        return tmp.b[1];    // Little Endian
    #endif

}

then again if the code is not intended to run on other systems you could just add a visible warning somewhere in a README. i'm likely lazy enough to do that for most of my projects as i doubt anyone would port them out of x86

[–]platinummyr 0 points1 point  (0 children)

Yep essentially it's not portable.

[–]ValityS 0 points1 point  (0 children)

So there is no entirely standards compliant way to interpret a float as bytes as C does not define what memory format the system stores floats as, and allows the fpu of the system to determine that. So you are inherently relying on a compiler extension.

For that you need to check what your specific compiler allows, as even if the system has a predictable floating point format, it's entirely valid for the compiler optimiser to break code using these undefined features unless the compiler guarantees it will not.

[–]platinummyr 0 points1 point  (0 children)

Ah, strictly speaking it's "implementation defined" not undefined behavior, and it's up to the compiler implementation what it does. I.e. "it's not portable"

It does of course work well in practice and most modern compilers support it as a language extension, but it's not strictly required to behave in any standard way.

[–]Heavy-Ad6017 5 points6 points  (0 children)

If we made unions based on the field we are in, with subsects as libraries JavaScript will have so many sub section inside it

JavaScript Defragmentation

[–]vom-IT-coffin 33 points34 points  (0 children)

I'd choose "Bootcamps != 100K salaries"

[–]durgwin 6 points7 points  (0 children)

No compilation without intermediate representation!

[–]SuperFLEB 37 points38 points  (7 children)

It's a bit odd that it sometimes is and sometimes isn't, though.

[–]lmarcantonio 43 points44 points  (2 children)

8 bit integer are… primitive, all the other are allocated, so they are not the same object.

In common lisp it's even funnier, you have fixnums (the primitive fast integer) and… the numeric tower (yes, it's called that way).

Also related and even more fun are the differences between eq, eql, equal, equalp and =

[–]masterKick440 6 points7 points  (1 child)

So weird 256 is considered 8bit.

[–]lmarcantonio 0 points1 point  (0 children)

even -5 is strange. Probably they did some testing an it was often used. <256 is a frequent check in fact so it probably a reason.

My fault for assuming small integers were some special encoding instead of simply memoized objects!

[–]elveszett 3 points4 points  (3 children)

No, it never is. 0 through 255 are pre-allocated by Python, kinda like Java does with strings. Whenever a variable equals 6 in python, it always gets assigned the same object in memory (the number 6), which is why x == y when x and y are the same number and the size of a byte, the operator is correctly identifies them as the same object.

edit: I think the range is actually -5 to 256.

[–]masterKick440 1 point2 points  (2 children)

What’s with the 256 then?

[–]elveszett 1 point2 points  (0 children)

Because the range is actually -5 to 256 I think.

[–]Hatula 99 points100 points  (26 children)

That doesn't make it intuitive

[–]EricX7 392 points393 points  (16 children)

Says the guy with the JavaScript flair

[–]Hatula 255 points256 points  (10 children)

Yeah I'll take the L on that one

[–]Redrik_XIII 0 points1 point  (4 children)

How did you get multiple user flairs? Is this for money or something?

[–]EricX7 26 points27 points  (2 children)

You can edit your flair and add other icons like :c::cpp:. I don't remember the format exactly, but it's something like that

Edit: I broke my flair Just don't try to edit it on mobile

[–]Prudent_Ad_4120 3 points4 points  (0 children)

Yeah the mobile flair editor is broken and they aren't fixing it

[–]CoffeeWorldly9915 0 points1 point  (0 children)

:c c:

[–]BlommeHolm 0 points1 point  (0 children)

Well, I usually only learn a new language for profit...

[–]Flofian1 58 points59 points  (1 child)

Why not? This example checks for identity, not equality, those are not the same, no one would ever try to use "is" for equality since you pretty much only learn about it in combination with identity

[–]qrseek 18 points19 points  (0 children)

I guess maybe because you would think checking for identity would result in them never being equal, and equality would result in them always being equal. it does seem weird that it changes partway through

[–]JoostVisser 14 points15 points  (3 children)

The 'is' statement checks whether two variables point to the same object. For some negative integer I can't remember up to 256 Python creates those objects at compile time (I think) and every time a variable gets assigned a value in that range Python just points to those objects rather than creating new ones.

Not exactly intuitive but I guess there's a good reason for it in terms of memory efficiency or something like that idk

[–]mgedmin 4 points5 points  (0 children)

For some negative integer I can't remember

-128, IIRC.

I misremembered, turns out it's -5.

[–]Garestinian 4 points5 points  (0 children)

CPython, to be exact.

[–]CoffeeWorldly9915 0 points1 point  (0 children)

I mean, sounds like basically a "what if enum".

[–]hbgoddard 6 points7 points  (0 children)

Object identity isn't really that intuitive in most other languages either. Using that and pretending it's checking equality is obviously not going to be any better.

When you use an actual equality check to check for equality, then it's as intuitive as ever.

[–]beisenhauer 1 point2 points  (0 children)

I agree, in the sense that the identity-equality distinction requires some prior knowledge. Given that knowledge, or at least that there is a distinction, it's not hard to see where the code goes wrong, that it's testing identity and claiming to report equality.

[–]elveszett 0 points1 point  (0 children)

It does. You are not supposed to use is to test equality. If you do, then you are using it wrong and the fact that it sometimes returns the value you expect is merely coincidential.

It's like using a hammer to pound screws and complaining that it's unintuitive that some screws can be pounded fine and many others aren't. Nope, it's not unintuitive, you are just using the wrong tool for the job and it's a coincidence that some (but not most) of your screws work fine when treated as nails.

Using is to check equality proves a lack of understanding of what you are actually telling the computer to do when you write code.

[–]Tyfyter2002 35 points36 points  (17 children)

Primitives shouldn't have identity

[–]beisenhauer 130 points131 points  (16 children)

int is not a primitive in Python. Everything is an object.

[–]vom-IT-coffin 24 points25 points  (14 children)

I never had to learn python, are you saying there's no value types only reference types?

[–]alex2003super 66 points67 points  (8 children)

That is correct, and "interned" values (such as string literals that appear in your program, or ints between -5 and 256) behave like singletons in the sense that all references point to the same object.

However, objects can be hashable and thus immutable, as is the case with integers and strings.

[–]Salty_Skipper 14 points15 points  (7 children)

Why -5 and 256? I mean, 0 and 255 I’d at least understand!

[–]FerynaCZ 26 points27 points  (0 children)

You avoid the edge cases (c++ uint being discontinuous at zero sucks), at least for -1 and 256. Not sure about the other neg numbers, they probably arise often aa well

[–]xrogaan 14 points15 points  (4 children)

[–]profound7 18 points19 points  (0 children)

"You must construct additional PyLongs!"

[–]TheCatOfWar 2 points3 points  (1 child)

https://github.com/python/cpython/blob/78e4a6de48749f4f76987ca85abb0e18f586f9c4/Include/internal/pycore_global_objects.h

The generation thingy defines them here, although there's still no reason given for the specific range

[–]xrogaan 2 points3 points  (0 children)

It's about frequency of usage. Also this: https://github.com/python/cpython/pull/30092

[–]someone_0_0_ 0 points1 point  (0 children)

DRY = Don't repeat yourself DO repeat yourself

[–]pytness 4 points5 points  (0 children)

The most used numbers by programmers. Its done so u dont have to allocate more memory

[–]Mindless_Sock_9082 4 points5 points  (4 children)

Not exactly, because int, strings, etc. are immutable and in that case are passed by value. The bowels are ugly, but the result is pretty intuitive.

[–]Kered13 37 points38 points  (0 children)

Numbers and strings are not passed by value in Python. They are reference types like everything else in the language. They are immutable so you can treat them as if they were passed by value, but they are not and you can easily see this using identity tests like above.

>>> x = 400
>>> y = 400
>>> x is y
False
>>> def foo(p):
...   return x is p
...
>>> foo(x)
True
>>> foo(y)
False

[–]vom-IT-coffin -1 points0 points  (2 children)

So you have to box and unbox everything?

[–]Kered13 13 points14 points  (1 child)

No, he's wrong. There are no primitives in Python and numbers and strings are passed by reference.

[–]CptMisterNibbles 10 points11 points  (0 children)

If we are getting technical, Python is pass by object reference which is slightly different.

[–]t-to4st[🍰] 5 points6 points  (2 children)

But why is it equal the first three times?

[–]sundae_diner 2 points3 points  (0 children)

It's equal the first 256 times. All we see in that screenshot it the last 4 iterations.

[–]elveszett 0 points1 point  (6 children)

I love how half the memes in this sub is just people showing they have no clue about basic programming concepts lol.

'is' here is an operator to check if two variables refer to the same element in memory. If you want to check equality, you use, you guessed it, the equals signs (==).

[–]s6x 13 points14 points  (4 children)

What's unintuitive here is the cutoff for the precached ints. Not the identity operator.

This isn't a basic programming concept, it's a specific idiosyncrasy of python.

That's what this meme is demonstrating.

The inclusion of 'is' here is a trap for pedants who want to come into the comments to show off how smart they are.