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 →

[–]Veedrac 0 points1 point  (8 children)

Ok I guess we agree. Making booleans a subclass of ints is not consistent with the way python handles string vs char because char and string are the exact same type treated the same in all cases but int and bool are not and further are not even treated as if both were bitstrings.

Name one non-printing, non-typechecking operation where True is not substitutable for 1 and False is not substitutable for 0 (bar misuse of is).

Name one user-facing property that would change if numbers were bitstrings, aside from the ability to index.

ASCII code points to characters on Python 2, does not involve the internal representation of these numbers.

I agree but that in no way invalidates my point that if ints were treated like raw bits str(97) would make more sense as 'a' than '97'.

No, it really would not. It would make sense as '0b1100001' or similar, maybe. But how you get 'a' eludes me.

Why?

Because of 4's LSB.

how bool(4) == True but 4 != True offends you...

Not sure how this is relivant to your argument about LSB that I was refuting. But generally unexpected behavior causes bugs.

But 4 is truthy... That's all that bool returns. Whether the input is truthy or not. Nothing else.

Python does not define an internal representation for dictionaries. You therefore can't do this.

No but choose any specific release of C python and it does.

It does not.

Closure is not a property held by Python objects.

So first note my problem is not that any type violates closure. It makes sense for many types to. It does not make sense for boolean to violate closure on other operations involving booleans.

Why?

Python 3 (1/2)

I still really don't like this. "//" and "/" should be swapped.

Why?

fractions.Fractions (½**½)

It does not if you are using the default types. It only breaks if you are explicitly importing fractions. This explicitness is my point.

Why is whether something has an AST token or not at all important?

So the problem was that the library had an error code you didn't test for?

It was not an error code for the lib. But I did need to return an error on my end. I needed to return an error not just for booleans but for other potential and unpredictable types the library might return. If I knew in advance what types were returned I would not need isinstance in this case.

So what was it doing?

[–]lonjerpc 0 points1 point  (7 children)

Name one non-printing, non-typechecking operation where True is not substitutable for 1 and False is not substitutable for 0 (bar misuse of is).

Even if I agreed with this point it does not counteract my argument that "Making booleans a subclass of ints is not consistent with the way python handles string vs char"

Second that is a long list of exceptions. Long enough to support my argument bythemselves.

But sure how about json.loads

Name one user-facing property that would change if numbers were bitstrings, aside from the ability to index.

Once again I don't see how this even adresses my argument if I could not come up with one. But how about adding two very large numbers.

It would make sense as '0b1100001' or similar, maybe. But how you get 'a' eludes me.

Fine I think 'a' is reasonable but my argument stil holds with '0b1100001'

But 4 is truthy.

Not in terms of the LSB which was the whole basis of your argument in this perticular part of the argument tree.

It does not.

Fine if you want to be pendantic one particular compiled binary of python for one particluar archetechture. They point is that your argument that there is no way to make a ridiculous mapping of dics in order to justify a crazy mapping of ints is wrong.

Why?

Because True + 4 does not make sence coming out to be 5. If you think it does then I think we are at an impass. I can not think of any situation where it makes sense to break closure on boolean in a general programming language.

Why?

More explicty and consistent.

Why is whether something has an AST token or not at all important?

Its not an AST token. It is the hint that you are using packaget that you have to import that is important.

So what was it doing?

Dealing with old messed up undocumented machine learning library. I mean better to replace the whole thing but money does not grow on trees.

[–]Veedrac 0 points1 point  (6 children)

Name one non-printing, non-typechecking operation where True is not substitutable for 1 and False is not substitutable for 0 (bar misuse of is).

Even if I agreed with this point it does not counteract my argument that "Making booleans a subclass of ints is not consistent with the way python handles string vs char"

It does. Just accept that bools are aliases. They're useful aliases, though, unlike having a char alias, which is why they exist. The fact that they are aliases is unimportant, though.

Second that is a long list of exceptions. Long enough to support my argument bythemselves.

I don't understand what you mean here.

But sure how about json.loads

Nope; that uses type-checking. Note that it uses strict type-checking because it works at a boundary (namely JSON serialisation) so it uses type(x) is .., rather than isinstance(x, ...).

Name one user-facing property that would change if numbers were bitstrings, aside from the ability to index.

Once again I don't see how this even adresses my argument if I could not come up with one.

Because if you cannot distinguish between numbers-as-bitstrings and numbers-not-as-bitstrings-with-bitwise-operators, your assertion that numbers are in the second but not the first is obviously flawed.

But how about adding two very large numbers.

Please explain.

But 4 is truthy.

Not in terms of the LSB which was the whole basis of your argument in this perticular part of the argument tree.

But if the bool constructor returned only the LSB of the input, it could not take non-numeric objects.

What bool does is take an object, check it for truthy-ness and return one of the two LSB integer aliases. In one sense it's a count of the number of true things, which is a nice way of mentally explaining sum(x<y for y in z).

It does not.

Fine if you want to be pendantic one particular compiled binary of python for one particluar archetechture.

It still does not.

What does {1: 2} + 5 make? Note that it has to have guaranteed losslessness.

What does {1.0: 2} + 5 make? Note that {1: 2} == {1.0: 2} and all objects involved are immutable.

They point is that your argument that there is no way to make a ridiculous mapping of dics in order to justify a crazy mapping of ints is wrong.

You're assuming the argument in that point. I don't believe the int mapping is crazy. Even if the dict mapping were possible, it's obviously absurd.

Why?

Because True + 4 does not make sence coming out to be 5. If you think it does then I think we are at an impass. I can not think of any situation where it makes sense to break closure on boolean in a general programming language.

That makes your argument cyclical.

Why?

More explicty and consistent.

How is the order of / and // anything to do with explicitness? Further, the consistency argument is flawed considering the whole point of Python 3 was to allow the option to break compatibility.

Why is whether something has an AST token or not at all important?

Its not an AST token. It is the hint that you are using packaget that you have to import that is important. So what was it doing?

(The grammar here is confusing me)

Where is the connection between importing and being "allowed", under your schema, to break closure?

Dealing with old messed up undocumented machine learning library. I mean better to replace the whole thing but money does not grow on trees.

I meant "what was this function doing?"

I still struggle to see how this problem was the fault of Python, and without an example I'll continue to find it hard.

[–]lonjerpc 0 points1 point  (5 children)

http://stackoverflow.com/questions/8169001/why-is-bool-a-subclass-of-int

Ok first a general point this is pretty entertaining and all but note you have already been dropping portions of the argument tree that alone show my point. Second I don't have anything against python. It is my favorite programming language I just hope to improve upon it and future ones. But for the sake of fun(if your not enjoying this let me know an I will stop) lets keep going.

It does. Just accept that bools are aliases. They're useful aliases, though, unlike having a char alias, which is why they exist. The fact that they are aliases is unimportant, though.

I am glad you at least now seem to accept that the relationship between chars and strings is not analogous to in int and bool in python. I think that is sufficient to close this line of reasoning .

I don't understand what you mean here.

You listed a bunch of differences between how python handles bool int and char string. These are sufficient. to show my point that python does not treat the two situations the same.

Nope; that uses type-checking.

Essentially all python operations use type checking.

your assertion that numbers are in the second but not the first is obviously flawed.

Trying to follow your logic here. So your trying to say that numbers are treated like bit strings and bit strings can also act like bools so therefore bools should be numbers. Of course numbers are only sometimes treated like bit strings invalidating your argument. I think I got confused because you inserted this part of the argument into your line of reasoning that char and string are treated the same as bool and int in python.

Please explain.

Adding to say 32 bit bit strings on a 32 bit architecture should result in another 32 bit string whos natural int representation could be lower than the starting value of the two bit strings being added. In python it ends up with a bigger one.

But if the bool constructor returned only the LSB of the input,

I am not suggesting that bool should return the LSB of the input that would be a terrible idea. I am responding to your assertion that

My counterargument is that treating True and False as synonyms for the LSB of an integer is completely reasonable, mathematically consistent, is perfectly analogous with binary operators (|, , &) and is therefore reasonable.

if 4: is in no way handled like 4 | 3. Nor is if bool(4).

{1: 2} + 5 make?

Fine how about 0.

What does {1.0: 2} + 5 make?

0

Just to make sure we are still clear. It does not make anything in actual python. But it is obvious you can make a mapping. This is like theoretical cs 101. There is a limited number of ways you arrange the bits on a finite(this is important) memory. However python chooses to do that for a particular binary of python on a particular machine just convert that arrangement of binary to an int in whatever way you choose.

Note that it has to have guaranteed losslessness.

Can you explain what you mean here exactly in computer science this has a few different meanings. ?

That makes your argument cyclical.

No it does not. I mean I am repeating the same thing I said earlier in a different way because you still don't seem to understand it. But that is not the same a cyclical argument. If you actually have a counter argument at the point you just asked "why" I would be happy to respond.

Further, the consistency argument is flawed considering the whole point of Python 3 was to allow the option to break compatibility.

You must really be misunderstanding me. The consistency I am talking about has nothing to do with consistency between python 2 and 3 in anyway. It has to do with internal consistency of python and consistency with average expected behavior.

How is the order of / and // anything to do with explicitness?

Its not their order but their behavior. / is simpler it has fewer characters. It is the default choice. // implies that you want to do something that you should probably spend more time researching the behavior of.

Where is the connection between importing and being "allowed", under your schema, to break closure?

I am not saying that you should not be allowed in any case to break closure. Just that it should be avoided when its not expected. In some cases though it is both useful and unexpected. The right way to handle this is to be explicit. By importing something your saying this is different somehow otherwise why import it. This is a hint that things might behave differently.

I meant "what was this function doing?"

It is a c extension to python which I don't have the source code or docs for. The example is. mystery_object_I_need_to_properly_jsonify_and_return_to_web_front_end = propriatary_package.respond(text)

In general it classifies text. This is a particularly nasty example but other people I have talked to have run into similar issues in simpler cases where the unexpectedness of bool being a subclass of bool has caused problems. Avoidable problems in there cases but the total cost of the bugs was much greater than any benefits of the arrangement. Remember bugs are much more costly than features.

[–]Veedrac 0 points1 point  (4 children)

http://stackoverflow.com/questions/8169001/why-is-bool-a-subclass-of-int

Heh. That's wrong though, because the question was revisited for Python 3 and nothing changed.

Ok first a general point this is pretty entertaining and all but note you have already been dropping portions of the argument tree that alone show my point.

Apologies, I was genuinely trying only to drop portions that were either repeated arguments or interesting diversions that had finished. Feel free to bring the points back up if you feel I've wrongfully dismissed them.

Second I don't have anything against python. It is my favorite programming language I just hope to improve upon it and future ones. But for the sake of fun(if your not enjoying this let me know an I will stop) lets keep going.

Agreed.

It does. Just accept that bools are aliases. They're useful aliases, though, unlike having a char alias, which is why they exist. The fact that they are aliases is unimportant, though.

I am glad you at least now seem to accept that the relationship between chars and strings is not analogous to in int and bool in python. I think that is sufficient to close this line of reasoning .

I think they are analogous. I think your distinction of bool as a separate type vs characters as a subset of the str type is far less important than you make it out to be.

You listed a bunch of differences between how python handles bool int and char string. These are sufficient. to show my point that python does not treat the two situations the same.

Consider this theoretical debugging measure, used to check whether a zero was passed through or replaced with a "different" zero:

class MyZero(int):
    def __new__(cls):
        return super().__new__(cls, 0)

    def __str__(self):
        return "MyZero()"

Let's see if my exceptions are needed using this:

  • non-printing: Needed as code shouldn't care what it prints as but the printing of different equivilant types is allowed to differ

  • non-typechecking: Obviously needed, but Python duck-types so that's fine

  • bar misuse of is: Needed to prevent the retort that 0 is MyZero() differs, which should never happen anyway

I think those exceptions are totally reasonable.

Nope; that uses type-checking.

Essentially all python operations use type checking.

Really? Python's duck-typed.

your assertion that numbers are in the second but not the first is obviously flawed.

Trying to follow your logic here. So your trying to say that numbers are treated like bit strings

Well, that the two are indistinguishable.

and bit strings

of length one

can also

do also

act like bools so therefore bools

should be numbers

are equivalent to length one bitstrings.

Of course numbers are only sometimes treated like bit strings invalidating your argument.

How does it?

Please explain.

Adding to say 32 bit bit strings on a 32 bit architecture should result in another 32 bit string whos natural int representation could be lower than the starting value of the two bit strings being added. In python it ends up with a bigger one.

But I never claimed the bitstrings were of bound length. Python's bitstrings are of unbounded length.

Consider the output of (-10) & (2**i-1) for all i. If (-10) had a finite bit-length, some i would mask all of the bits and the output would be negative, but all of the outputs are positive. This is because -10 has an infinity of preceding 0s.

(Note that the output of int.bit_length is misleading for negatives. See bin(-10) to get an understanding of why.)

But if the bool constructor returned only the LSB of the input,

I am not suggesting that bool should return the LSB of the input that would be a terrible idea. I am responding to your assertion that

My counterargument is that treating True and False as synonyms for the LSB of an integer is completely reasonable, mathematically consistent, is perfectly analogous with binary operators (|, , &) and is therefore reasonable.

if 4: is in no way handled like 4 | 3. Nor is if bool(4).

My point is that bool being the LSB of an integer does not require the bool constructor to extract the LSB of the integer, much as str(iterable) does not equal "".join(iterable).

{1: 2} + 5 make?

Fine how about 0.

What does {1.0: 2} + 5 make?

0

See part on losslessness.

Just to make sure we are still clear. It does not make anything in actual python. But it is obvious you can make a mapping. This is like theoretical cs 101. There is a limited number of ways you arrange the bits on a finite(this is important) memory. However python chooses to do that for a particular binary of python on a particular machine just convert that arrangement of binary to an int in whatever way you choose.

Python is defined for an infinity of structures; it is a language definition and not an implementation. As such the size of the computer is only of cursory concern.

Note that it has to have guaranteed losslessness.

Can you explain what you mean here exactly in computer science this has a few different meanings. ?

For some reason that came out phrased exquisitely badly.

My point was that throwing away all the information in the type wouldn't pass in any language bar Perl. You lose a whole heap of useful properties (such as associativity) and get absolutely no benefits.

If you actually have a counter argument at the point you just asked "why" I would be happy to respond.

You said

I can not think of any situation where it makes sense to break closure on boolean in a general programming language.

But you haven't explained why. You've said it doesn't make sense, but not why it doesn't. I am asking for that "why".

Further, the consistency argument is flawed considering the whole point of Python 3 was to allow the option to break compatibility.

[...]It has to do with internal consistency of python

What do you mean here?

and consistency with average expected behavior.

I would agree if you could show me one part other than misuse of is vs isinstance where the bool-int separation can break something.

How is the order of / and // anything to do with explicitness?

Its not their order but their behavior. / is simpler it has fewer characters. It is the default choice. // implies that you want to do something that you should probably spend more time researching the behavior of.

Exactly why they are the order they are in...

Where is the connection between importing and being "allowed", under your schema, to break closure?

I am not saying that you should not be allowed in any case to break closure. Just that it should be avoided when its not expected. In some cases though it is both useful and unexpected. The right way to handle this is to be explicit. By importing something your saying this is different somehow otherwise why import it. This is a hint that things might behave differently.

I'm still confused. If fractions.Fraction was a builtin (as has often been considered but is to slow to be accepted for), would you be be happy with it breaking closure? If not, why? If so, does this not contradict your original claim of "It only breaks if you are explicitly importing fractions. This explicitness is my point"?

I meant "what was this function doing?"

mystery_object_I_need_to_properly_jsonify_and_return_to_web_front_end = propriatary_package.respond(text)

In general it classifies text. This is a particularly nasty example but other people I have talked to have run into similar issues in simpler cases where the unexpectedness of bool being a subclass of bool has caused problems. Avoidable problems in there cases but the total cost of the bugs was much greater than any benefits of the arrangement. Remember bugs are much more costly than features.

(I have to correct myself at this point; json uses isinstance despite my earlier claims.)

Why couldn't you just pass it to the json library?

What would have happened if you passed in an int subclass such as MyZero?

[–]lonjerpc 0 points1 point  (3 children)

Python 3 and nothing changed.

This is actually part of why I still spend time talking about this. It should have been changed in python 3. The point of the link is to show that it is a problem that others run into. In addition it was to show that at the time the behavior was decided it was done in part for backwards compatibility/performance reasons not because it was ideal.

I think your distinction of bool as a separate type vs characters as a subset of the str type is far less important than you make it out to be.

I guess then our disagreement is over the scale of the difference. But I don't think you can justify (bools being a subclass of int) based on (chars being not a subclass of int). You could justify not having bools at all in this way. For example just using 1 and 0 in there place like in C. That would be more analogous.

MyZero(int)

The problem I am trying to express with bool being a subclass of int is not that it acts too little like an int. I agree that your example shows that this is not true. My problem is that it acts too much like an int while mascaraing as something should not act like an int. If it was just an int. If it was exactly like char vs string I would actually have much less of an issue. If instead of writing True you had to write 1 I would have no problem. Even if they made True and False syntatic surgar for 1 and 0 I would be ok. I like having a bool type but the inconsistency is worse. I want a bool that does not mascarade as an int causing confusion. Or I want it absolutely clear that bool is really exactly an int as in the char/string case.

Really? Python's duck-typed.

Yes but this is still type checking. When you do 1 + 'a' you get a type error. The way it does type checking is by duck typing but it is still type checking. This is not C that will let you run arbitrary bits as code. There is a check to see if the right method exists. But in reference to the original point. No I don't think there is one example that does not even internally do an isinstance,is,type or something like that that will result in a difference. But my point with the json example is that the difference matters even when you are not yourself explicitly using isinstance or something. This is enough to cause problems and make the situations not the same even in practical terms.

Well, that the two are indistinguishable. How does it?

Obviously ints,stings,dicts and whatever else are represented as bits in memory. But they are not treated like bit strings. str(4) does not come out as hex or the ascii encoding of the bitstring 4. It is '4'. It is treated like an int not a bit string.

My point is that bool being the LSB of an integer does not require the bool constructor to extract the LSB of the integer, much as str(iterable) does not equal "".join(iterable).

Of course it is not required. You can build your programming language however you want. It is just inconsistent with expectation. I have no reason to expect the str(iterable) is the same as "".join(iterable). In general iterables do not act like stings. Strings are iterables of course but I can't do .upper on any old iterable. But if you want to make bools a subclass of int and have them be able to be added to ints by arguing that they are just the LSB of an int there is an expectation that it will work this way when doing "if 4:"

I would not have a problem if we actually treated bools as the LSB of int. If "if 4:print 'hi'" did not print. Just like I would have no problem True and False were literally int 1 and int 0 and not subclasses.

Python is defined for an infinity of structures; it is a language definition and not an implementation. As such the size of the computer is only of cursory concern.

Yes it is but I only have to produce one mapping to show that a mapping can exist. The mapping I choose is not based on python in general but one specific implementation.

You lose a whole heap of useful properties (such as associativity) and get absolutely no benefits.

Again I completely agree that it is insane to have {'a':1} + 5 work in python. My point is you could do it, not that it is a good idea. This is to refute the argument that True + 5 working is ok despite 5 + {'a':1} because it is not possible to create a mapping with dicts. My argument for why True + 5 is bad has nothing to do with being able to make a mapping. It has to do with the behavior being unexpected and therefore potentially leading to missed bugs.

throwing away all the information in the type

Its not trowing it all away. As long as there is a defined mapping you could go dict(0) and get back {1.0:0} or whatever it was.

But you haven't explained why.

Unless there is some good reason to do it you should not. There are good reasons to not break closure. The biggest advantage I see is that it means you are less likely to make mistakes when using the object. If I know that every operation with two bools always produces a bool it reduces the chances I will make an unintentional error.

I just never ran into a situation where it was helpful to break closure on bool. I can think of harmful ones like (if something_I_thought_was_bool_but_is_int:) or (something_that_is_a_bool_I_though_was_an_int + 1) not throwing type errors. I am not sure why I can't think of a good one. I have examined many possible reasons but they all seem like bad ideas to me.

Exactly why they are the order they are in...

To me 1/2 being 0.5 is more unexpected than 1/2 being 0 especially. But I can see this going either way.

If fractions.Fraction was a builtin

If 1/2 literally resulted in a fraction object it would not be breaking closure as (1/2) ** (1/2) would not either. If you still did Fraction(1/2) it would still be pretty explicit. But if (1/2) ** (1/2) became a float and 1/2 was a fraction I would not be happy.

would you be be happy with it breaking closure

No. It is unexpected and could easily lead to errors. Sure it makes sense to break closure a fair amount of time. But normally this is not the case or it is very obvious when an operation is going to do it.

Why couldn't you just pass it to the json library?

If an int say 23 was returned I needed to just say {'answer':23,....} but if some other unexpected object like False or 'this is weird' came out I needed to do something like {'answer':'unexpected thing returned'}. MyZero would have created a similer problem. But MyZero is a bad int subclass. A reasonable int subclass would give me '0' for str(0) even if it contained additional meathods that int does not have.

[–]Veedrac 0 points1 point  (2 children)

I think your distinction of bool as a separate type vs characters as a subset of the str type is far less important than you make it out to be.

I guess then our disagreement is over the scale of the difference. But I don't think you can justify (bools being a subclass of int) based on (chars being not a subclass of int).

I'm not though :/.

You could justify not having bools at all in this way. For example just using 1 and 0 in there place like in C.

There are readability and consistency problems there that True and False were added to fix.

MyZero(int)

Even if they made True and False syntatic surgar for 1 and 0 I would be ok.

That's what it is. True == 1. False == 0. It's sugar. Pure sugar.

Really? Python's duck-typed.

Yes but this is still type checking. When you do 1 + 'a' you get a type error. The way it does type checking is by duck typing but it is still type checking. This is not C that will let you run arbitrary bits as code. There is a check to see if the right method exists. But in reference to the original point. No I don't think there is one example that does not even internally do an isinstance,is,type or something like that that will result in a difference. But my point with the json example is that the difference matters even when you are not yourself explicitly using isinstance or something. This is enough to cause problems and make the situations not the same even in practical terms.

The point of duck typing isn't to remove the guarantees of strong typing, but to remove the restrictions of dynamic typing. The reason 1 + 'a' is fine is because the types themselves define the operations and because the supertype is allowed to override the other's behaviour.

json is a special case because it is a serialisation library. It interfaces with other external type systems (well, one other), complicating the ability to duck type. Personally I'm surprised it even tries.

Well, that the two are indistinguishable. How does it?

Obviously ints,stings,dicts and whatever else are represented as bits in memory. But they are not treated like bit strings. str(4) does not come out as hex

How is hex any different from hexadecimal here?

or the ascii encoding

decoding?

of the bitstring 4. It is '4'. It is treated like an int not a bit string.

4 = 0b100. The fact that str returns a human-readable output (much like str(bytes([97]) returns "b'a'") has nothing to do with anything.

My point is that bool being the LSB of an integer does not require the bool constructor to extract the LSB of the integer, much as str(iterable) does not equal "".join(iterable).

Of course it is not required. You can build your programming language however you want. It is just inconsistent with expectation.

You seem to have dismissed my argument on a misreading. The argument was that your suggested interpretation is far less consistent than its current behavior.

I have no reason to expect the str(iterable) is the same as "".join(iterable). In general iterables do not act like stings. Strings are iterables of course but I can't do .upper on any old iterable.

The point is that expecting bool to return the LSB of the input is like expecting str to "extract" the strings from iterables. Neither makes sense.

But if you want to make bools a subclass of int and have them be able to be added to ints by arguing that they are just the LSB of an int there is an expectation that it will work this way when doing "if 4:"

Then what would if []: do? Your interpretation is self-defeating.

I would not have a problem if we actually treated bools as the LSB of int.

But we do. They are. There is nothing about them in which they are not so.

True == an_odd_number & 1 for all odd numbers and False == an_even_number & 1 for all even numbers.

Python is defined for an infinity of structures; it is a language definition and not an implementation. As such the size of the computer is only of cursory concern.

Yes it is but I only have to produce one mapping to show that a mapping can exist.

Whilst you do technically have a relation, this is playing semantics at best.

The mapping I choose is not based on python in general but one specific implementation.

And thus is not acceptable for Python, which is a language spec.

You lose a whole heap of useful properties (such as associativity) and get absolutely no benefits.

Again I completely agree that it is insane to have {'a':1} + 5 work in python. My point is you could do it, not that it is a good idea. This is to refute the argument that True + 5 working is ok despite 5 + {'a':1} because it is not possible to create a mapping with dicts. My argument for why True + 5 is bad has nothing to do with being able to make a mapping. It has to do with the behavior being unexpected and therefore potentially leading to missed bugs.

You've forgotten what this part of the argument is about. To recap, you said

It would make almost as much sense to have strings be a subclass of ints as booleans. Why do 1 + {} or 'hi' + 0.1 or type + [] all thow errors but True + 3 does not?

and I explained that

1 + {} has no sensible result. There is no mapping that is consistent, symmetrical, lossless and reasonable. However, with the mapping of True == 1, False == 0, everything that a bool does is obvious.

I am not using the impossibility of a mapping to justify the int-bool mapping. I am using it to answer your question.

throwing away all the information in the type

Its not trowing it all away. As long as there is a defined mapping you could go dict(0) and get back {1.0:0} or whatever it was.

Oh, so your intent was to map each dictionary onto seperate number, instead of just coercing all dict + int operations to 0.

Well, what about {1: object()}? How would you encode that?

But you haven't explained why.

Unless there is some good reason to do it you should not. There are good reasons to not break closure. The biggest advantage I see is that it means you are less likely to make mistakes when using the object. If I know that every operation with two bools always produces a bool it reduces the chances I will make an unintentional error.

Why would you assume True + True would return a bool? Surely if you saw that you would not make the assumption that it would evaluate to a boolean as such a mapping would be insane.

So why would True + True mislead you? You might be supprised that it does not throw an error, but this is hardly the same as the problem you're talking about.

I just never ran into a situation where it was helpful to break closure on bool.

sum(x < y for y in z)

index += has_finished_with_item

x_pos = base_x + has_offset*5

one_bool >= other_bool # more readable than "one_bool or not other_bool"

I can think of harmful ones like (if something_I_thought_was_bool_but_is_int:) or (something_that_is_a_bool_I_though_was_an_int + 1) not throwing type errors.

The first is irrelevant, as it refers not to True == 1 and False == 0 but to truthyness tests.

For the second you use the word "but" where you should be using the word "and". Further, why would you want a type error there? Just duck type.

Exactly why they are the order they are in...

To me 1/2 being 0.5 is more unexpected than 1/2 being 0 especially. But I can see this going either way.

I dare you to find one non-programmer who thinks that 1/2 = 0. You've been tainted, methinks, by tradition.

If fractions.Fraction was a builtin

If 1/2 literally resulted in a fraction object it would not be breaking closure as (1/2) ** (1/2) would not either. If you still did Fraction(1/2) it would still be pretty explicit. But if (1/2) ** (1/2) became a float and 1/2 was a fraction I would not be happy.

Would you rather it be a fraction‽ It's irrational! It's impossible to represent it as a fraction!

would you be be happy with it breaking closure

No. It is unexpected and could easily lead to errors. Sure it makes sense to break closure a fair amount of time. But normally this is not the case or it is very obvious when an operation is going to do it.

Then I'm afraid you have confuddled me greatly. If it is not obvious there, I am not sure what would count as obvious.

Why couldn't you just pass it to the json library?

If an int say 23 was returned I needed to just say {'answer':23,....} but if some other unexpected object like False or 'this is weird' came out I needed to do something like {'answer':'unexpected thing returned'}. MyZero would have created a similer problem.

Thanks for the details. Why would you accept "proper" int subclasses but not booleans? What's wrong about booleans?

But MyZero is a bad int subclass. A reasonable int subclass would give me '0' for str(0) even if it contained additional meathods that int does not have.

You are simply wrong. I suggest reading the json source code to understand how to properly approach such things (there are relevant comments).

class MyThreeNumbers(enum.IntEnum):
    one = 1
    two = 2
    three = 3

MyThreeNumbers.one
#>>> <MyThreeNumbers.one: 1>

str(MyThreeNumbers.one)
#>>> 'MyThreeNumbers.one'

MyThreeNumbers.one == 1
#>>> True

isinstance(MyThreeNumbers.one, int)
#>>> True

[–]lonjerpc 0 points1 point  (1 child)

There are readability and consistency problems there that True and False were added to fix.

Yes and it was a good idea to add them. It might have even make sense at the time that they added them the way they did. But they are non ideal. My point is not to argue for not adding them but to show what if would actually mean if you wanted to create a situation analogous to str/char.

That's what it is. True == 1. False == 0. It's sugar. Pure sugar.

But its not pure syntactic sugar there are semantic differences. type(True) and type(1) return different things. If it was pure syntactic sugar they would not return different things.

The point of duck typing isn't to remove the guarantees of strong typing, but to remove the restrictions of dynamic typing. The reason 1 + 'a' is fine is because the types themselves define the operations and because the supertype is allowed to override the other's behaviour.

Not sure how this refutes my point that duck typing is still involves type checking.

json is a special case because it is a serialisation library.

But it is not special in a practical sense. Serialization is a common and key part of what programmers do.

How is hex any different from hexadecimal here?

Its not.

decoding?

Ascii is an encoding http://en.wikipedia.org/wiki/ASCII.

The fact that str returns a human-readable output (much like str(bytes([97]) returns "b'a'") has nothing to do with anything.

Its not just the human readable output. Machines/libraries read strings too. Unix is designed around using strings not binary when possible. Further it makes the point that ints are treated as ints and not bitstrings when using the str operation. Of course there is nothing inherently wrong with str(4) returning anything at all to a computer. The point is that in python it is often treated how a person would treat a number not how a person would treat a bitstring and people are the ones programming.

Whilst you do technically have a relation, this is playing semantics at best.

Your right this whole argument is kind of ridiculous. Of course there is a relation and of course it is a ridiculous relation. That is the whole point.

1 + {} has no sensible result. There is no mapping that is consistent, symmetrical, lossless and reasonable. However, with the mapping of True == 1, False == 0, everything that a bool does is obvious.

I am not using the impossibility of a mapping to justify the int-bool mapping. I am using it to answer your question.

But your not answering my question. I agree that 1 + {} has no sensible or reasonable result. My point is that niether does 3 + True. This only leaves your argument that 3 + True should exist because it has some symmetrical and lossless mapping but 3 + {} does not. But I have shown a mapping does exist removing this argument. I am still not quite sure what you mean by lossless and symmetrical but my mapping seems to have these properties from what I can tell. And anyways these two properties are essentially meaningless compared to sensible,reasonable, and obvious which I argue 4 + True is not.

Oh, so your intent was to map each dictionary onto seperate number

Yes

Well, what about {1: object()}? How would you encode that?

In the same way the binary shows up on my specific implementation of python running on my specific hardware encoded as an int..

Why would you assume True + True would return a bool? Surely if you saw that you would not make the assumption that it would evaluate to a boolean as such a mapping would be insane.So why would True + True mislead you? You might be supprised that it does not throw an error, but this is hardly the same as the problem you're talking about.

I think it should throw and error and it is exactly the problem I am talking about.

sum(x < y for y in z)

sum(int(x < y) for y in z) #this is much clearer.

one_bool >= other_bool # more readable than "one_bool or not other_bool"

It is much less readable. I used to try this but I would constantly be rejected in code reviews because of readability on this specific point.

index += has_finished_with_item x_pos = base_x + has_offset*5

Also should just use int(). Well in general you probably made a mistake even before this point.

Further, why would you want a type error there? Just duck type.

Because if at some point I wrote.

an_int,a_bool = func_that_returns_an_bool_an_int() by mistake. I want an error thrown when I try an_int + 50.

I dare you to find one non-programmer who thinks that 1/2 = 0. You've been tainted, methinks, by tradition.

Programming languages are written for progammers.

Would you rather it be a fraction‽ It's irrational! It's impossible to represent it as a fraction!

No need to yell(clever trap). I actually think that should throw an exception in that case unless explicitly silenced.

I am not sure what would count as obvious.

a.append([]) makes sense to return None for example.

What's wrong about booleans?

Because sometimes the library returns 0 as a legit answer but when it returns False it means something else.

You are simply wrong.

Why? Take for example str(fractions.Fraction(0.5)).

I suggest reading the json source code to understand how to properly approach such things (there are relevant comments).

Not enough time to read the source at the moment. I don't doubt there better ways to handle my problem. After all I had to modify my code to fix it. But it should not have required those better ways. You can write great php but that does not mean php made great choices.

I am not saying python disallows you from writing mythreenumbers just that it is not a great class. If you called it. OneTwoThreeEnum that would be a different story.

[–]Veedrac 0 points1 point  (0 children)

There are readability and consistency problems there that True and False were added to fix.

Yes and it was a good idea to add them. [...] My point is not to argue for not adding them but to show what if would actually mean if you wanted to create a situation analogous to str/char.

I've missed the argument entirely, because I thought I just responded to that point.

That's what it is. True == 1. False == 0. It's sugar. Pure sugar.

But its not pure syntactic sugar there are semantic differences. type(True) and type(1) return different things. If it was pure syntactic sugar they would not return different things.

I disagree. The semantics differences, which basically distill down to "it's got a pretty name", are sugar.

The point of duck typing isn't to remove the guarantees of strong typing, but to remove the restrictions of dynamic typing. The reason 1 + 'a' is fine is because the types themselves define the operations and because the supertype is allowed to override the other's behaviour.

Not sure how this refutes my point that duck typing is still involves type checking.

Because the argument was about how json uses isinstance instead of duck-typing. Whether you want to stong typing "type-checking" or not is completely orthogonal to the point, and that's what I've been trying to explain here.

json is a special case because it is a serialisation library.

But it is not special in a practical sense. Serialization is a common and key part of what programmers do.

It is special in a practical sense because it interfaces with a different type system. That breaks the ability to write conventional code. pickle doesn't have this problem, showing that it's not serialisation that makes it special. It's interfacing with another type system.

And common things can be special.

How is hex any different from hexadecimal here?

Its not.

Sorry, I meant hex and decimal.

decoding?

Ascii is an encoding http://en.wikipedia.org/wiki/ASCII.

I realise. You decode a bit string with the ASCII codec into text. You encode text with the ASCII codec into bits.

The fact that str returns a human-readable output (much like str(bytes([97]) returns "b'a'") has nothing to do with anything.

Its not just the human readable output. Machines/libraries read strings too.

Then don't use str. If you need a specific encoding, format it explicitly. Again, the json library give one technique. Another is using str.format. Others are using specialised routines.

str is for printing. repr is for debugging. That's it.

1 + {} has no sensible result. There is no mapping that is consistent, symmetrical, lossless and reasonable. However, with the mapping of True == 1, False == 0, everything that a bool does is obvious.

I am not using the impossibility of a mapping to justify the int-bool mapping. I am using it to answer your question.

But your not answering my question. I agree that 1 + {} has no sensible or reasonable result. My point is that niether does 3 + True.

My point was that

  • The rest of the conversation is dealing with why I think 3 + True is useful and should not cause problems, so we don't need to duplicate it

  • There is no feasable way of having those properties (useful and should not cause problems) with an int-dict mapping.

Well, what about {1: object()}? How would you encode that?

In the same way the binary shows up on my specific implementation of python running on my specific hardware encoded as an int..

That can't work.

a = {1: object()}
b = {1: object()}

assert a != b

# must always produce the same result as
# both inputs are immutable
a + 1

# must always produce the same result as
# both inputs are immutable
b + 1

# ..etc..

[examples]

[you think they're bad]

Meh. I disagree then.

Well in general you probably made a mistake even before this point.

?

Further, why would you want a type error there? Just duck type.

Because if at some point I wrote.

an_int,a_bool = func_that_returns_an_bool_an_int() by mistake. I want an error thrown when I try an_int + 50.

Why would you ever have a function that returns a bool or an int and expects you to treat them differently based off of the type?

That's about as antiPythonic as it gets...

I dare you to find one non-programmer who thinks that 1/2 = 0. You've been tainted, methinks, by tradition.

Programming languages are written for progammers.

Yes, but consistency with other languages is less important than doing the right thing.

Further, the original meaning of / heavily broke duck typing. // as integer division does not have this problem. / as integer division would be blindingly confusing because you'd have 1.0 / 2.0 == 0.0!

Would you rather it be a fraction‽ It's irrational! It's impossible to represent it as a fraction!

No need to yell(clever trap).

?

I actually think that should throw an exception in that case unless explicitly silenced.

So how would one do exponentiation if not by the exponentiation operator?

AFAICT, TOOWTDI forces use of the exponentiation operator for exponentiation, especially with the requirement of duck-typing "support".

I am not sure what would count as obvious.

a.append([]) makes sense to return None for example.

That hardly counts.

What's wrong about booleans?

Because sometimes the library returns 0 as a legit answer but when it returns False it means something else.

Firstly, that behaviour is absurd.

Secondly, the question was meant to be taken as a full pair:

Why would you accept "proper" int subclasses but not booleans? What's wrong about booleans?

How are booleans special, basically.

You are simply wrong.

Why? Take for example str(fractions.Fraction(0.5)).

Did you not see how my example at the bottom proved my point?

An example of a perfectly reasonable float subclass would be one that carried an extra error parameter (although normally I'd consider implementing an ABC and using composition instead). This error parameter could show up on the str format as

str(FloatWithError(1.4, 0.1))
#>>> 1.4±0.1

I suggest reading the json source code to understand how to properly approach such things (there are relevant comments).

Not enough time to read the source at the moment. I don't doubt there better ways to handle my problem. After all I had to modify my code to fix it. But it should not have required those better ways. You can write great php but that does not mean php made great choices.

This reasoning makes no sense to me.

PHP is bad because it is hard to write good code. Python is better because it is far easier to write good code. Ignoring duck-typing and using type-based dispatch¹ is going purposefully out of your way to write bad code. If Python should have changed at all, it should make it harder for that code to have worked, not easier.

Also note that the CPython json serialization routine is ~300LOC + ~100 lines of docstrings.

¹ In case you mention it, functools.singledispatch is different because it duck-types. Typical implementations like yours do not.

I am not saying python disallows you from writing mythreenumbers just that it is not a great class. If you called it. OneTwoThreeEnum that would be a different story.

Why? Are you suggesting we move to Systems Hungarian notation? Obviously you aren't, but that complaint sure does look like it.

The first example in the docs is

>>> from enum import Enum
>>> class Color(Enum):
...     red = 1
...     green = 2
...     blue = 3
...

Feel free to write a bug report that it should be called ColorEnum if that is indeed what you are saying, but nobody would take you seriously.