RP
Ronaldo Persiano
Sat, Jul 25, 2020 12:32 PM
In the stable version all that echo false:
echo(true==1);
echo((0==0)==1);
echo(false==0);
echo((0==1)==0);
In the version 2020.07.02, all echo true!
It seems that the identities true==1 and false==0 were valid in ancient
versions.
Why the change? Is it intentional?
That breaks some search() of my codes.
In the stable version all that echo false:
echo(true==1);
echo((0==0)==1);
echo(false==0);
echo((0==1)==0);
In the version 2020.07.02, all echo true!
It seems that the identities true==1 and false==0 were valid in ancient
versions.
Why the change? Is it intentional?
That breaks some search() of my codes.
P
Parkinbot
Sat, Jul 25, 2020 2:00 PM
With 2019.12.21 I get:
echo(true==1); // false
echo(true==0); // false
this means not more and not less: a boolean is not a number (apples are no
pears) and you could also write:
echo(true=="1"); // false
echo(true=="0"); // false
Thus any code testing a condition like "true == x" imposes an implicit type
check. Changing this behavior can break such checks as well as reveal buggy
code written under the assumption Booleans are represented as numbers.
In my libs I have tons of code that uses some backward compatible testing
for lists like "a[0]!=undef". Obviously it has the pitfall:
a=[undef, 1,2,3];
But, I can live with it :-), since using is_list() will break even more code
as it hits people using older versions of OpenSCAD who are usally less
experienced programmers.
However, of course you are right: There is no obvious reason to drop the
Boolean data type and introduce old fashioned and error prone semantics in
OpenSCAD.
--
Sent from: http://forum.openscad.org/
With 2019.12.21 I get:
echo(true==1); // false
echo(true==0); // false
this means not more and not less: a boolean is not a number (apples are no
pears) and you could also write:
echo(true=="1"); // false
echo(true=="0"); // false
Thus any code testing a condition like "true == x" imposes an implicit type
check. Changing this behavior can break such checks as well as reveal buggy
code written under the assumption Booleans are represented as numbers.
In my libs I have tons of code that uses some backward compatible testing
for lists like "a[0]!=undef". Obviously it has the pitfall:
a=[undef, 1,2,3];
But, I can live with it :-), since using is_list() will break even more code
as it hits people using older versions of OpenSCAD who are usally less
experienced programmers.
However, of course you are right: There is no obvious reason to drop the
Boolean data type and introduce old fashioned and error prone semantics in
OpenSCAD.
--
Sent from: http://forum.openscad.org/
HL
Hans L
Sat, Jul 25, 2020 4:52 PM
This was part of a change to make comparisons more consistent in general.
See my comment here for more explanation:
https://github.com/openscad/openscad/pull/3164#issuecomment-569158586
(Basically try <= or >= operations between 0 / 1 and false / true on
your older versions, and tell me if that makes sense)
Can you provide a self contained example where the change causes a
problem in actual usage?
Boolean types are not "dropped", but there is type coercion which is
now applied consistently between numbers and bools.
is_bool() and is_num() can also be used to determine exact type if needed.
On Sat, Jul 25, 2020 at 9:01 AM Parkinbot rudolf@digitaldocument.de wrote:
With 2019.12.21 I get:
echo(true==1); // false
echo(true==0); // false
this means not more and not less: a boolean is not a number (apples are no
pears) and you could also write:
echo(true=="1"); // false
echo(true=="0"); // false
Thus any code testing a condition like "true == x" imposes an implicit type
check. Changing this behavior can break such checks as well as reveal buggy
code written under the assumption Booleans are represented as numbers.
In my libs I have tons of code that uses some backward compatible testing
for lists like "a[0]!=undef". Obviously it has the pitfall:
a=[undef, 1,2,3];
But, I can live with it :-), since using is_list() will break even more code
as it hits people using older versions of OpenSCAD who are usally less
experienced programmers.
However, of course you are right: There is no obvious reason to drop the
Boolean data type and introduce old fashioned and error prone semantics in
OpenSCAD.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
This was part of a change to make comparisons more consistent in general.
See my comment here for more explanation:
https://github.com/openscad/openscad/pull/3164#issuecomment-569158586
(Basically try <= or >= operations between 0 / 1 and false / true on
your older versions, and tell me if that makes sense)
Can you provide a self contained example where the change causes a
problem in actual usage?
Boolean types are not "dropped", but there is type coercion which is
now applied consistently between numbers and bools.
is_bool() and is_num() can also be used to determine exact type if needed.
On Sat, Jul 25, 2020 at 9:01 AM Parkinbot <rudolf@digitaldocument.de> wrote:
>
> With 2019.12.21 I get:
>
> echo(true==1); // false
> echo(true==0); // false
>
> this means not more and not less: a boolean is not a number (apples are no
> pears) and you could also write:
>
> echo(true=="1"); // false
> echo(true=="0"); // false
>
> Thus any code testing a condition like "true == x" imposes an implicit type
> check. Changing this behavior can break such checks as well as reveal buggy
> code written under the assumption Booleans are represented as numbers.
> In my libs I have tons of code that uses some backward compatible testing
> for lists like "a[0]!=undef". Obviously it has the pitfall:
>
> a=[undef, 1,2,3];
>
> But, I can live with it :-), since using is_list() will break even more code
> as it hits people using older versions of OpenSCAD who are usally less
> experienced programmers.
>
> However, of course you are right: There is no obvious reason to drop the
> Boolean data type and introduce old fashioned and error prone semantics in
> OpenSCAD.
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
P
Parkinbot
Sat, Jul 25, 2020 5:44 PM
Hans,
with
echo(true>=1); // true
echo(true<=1); // true
it seems consequent to alter the result
echo(true==1); // false -> true
However, I would never try to use
echo(true <= 1); // true
in user code. But if I was to implement this kind of logic, I would simply
always return "false" whenever the operands don't have the same data type.
--
Sent from: http://forum.openscad.org/
Hans,
with
echo(true>=1); // true
echo(true<=1); // true
it seems consequent to alter the result
echo(true==1); // false -> true
However, I would never try to use
echo(true <= 1); // true
in user code. But if I was to implement this kind of logic, I would simply
always return "false" whenever the operands don't have the same data type.
--
Sent from: http://forum.openscad.org/
A
adrianv
Sat, Jul 25, 2020 5:46 PM
It seems that the motivation for the changes was a theoretical sorting
process that needs to sort items of different types. The current dev
version behavior doesn't make much sense and is almost like dropping
booleans and just making "true" a synonym for 1. Except for the fact that
"3" is true. And this is a major inconsistency, not an improvement in
consistency as claimed.
If I search a vector for true entries, e.g. with search([true], [....]) then
the new behavior makes no sense. It gives me entries that are true and
entries that are 1. The two defensible results are entries that are exactly
"true" (as happened in older version) or all entries that would be
interpreted as true in a boolean context, which means all strings, nonempty
lists, nonzero numbers, and so on should be returned. There's no
conceivable reason a user would expect to get back all the "true" and "1"
entries. It's just not a consistent return result. Unless true isn't
really a separate boolean type but is just a synonym for 1.
For relative comparisons it seems like the only reason to compare true to 3
(other than programmer error) is in the sorting context, which was suggested
in the github issue. But does the choice to make true=1 and false=0
actually make sense? I argue that it does not. If I'm sorting a list of
objects I do not find the following to be a reasonable output from a sort
algorithm and can't conceive of a situation where it would be desirable:
[-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
but this would be a legitimate "sorted" output if true==1 and false==0 and
the same for comparisons.
I note that the same dubious logic has not bee applied to strings.
echo(""==0);
echo(""<0);
echo("">0);
all give false in both the july dev and the stable version. Similarly
comparison between lists and scalars also
echo([3]<3);
echo([3]>3);
echo([3]==3);
all give false. So the user who wants to sort a list mixed with lists and
strings and numbers is still on their own to handle comparisons in a
reasonable manner.
I can think of two behaviors that make sense for comparisons between types.
They should either be undef, or there should be a defined order OF TYPES, so
for example:
boolean < number < string < list
In this case the above sort example would presumably sort as
[false,false,true,true,-1, -.5, 0,0, .5, 1, 1, 1, 1.5, 2]
I don't think anybody interested in sorting mixed type lists would be happy
with the previous result, where false and 0 intermix and 1 and true
intermix, so such a user would have to write their own comparison operator
that uses is_bool to check the type to produce a reasonable output---either
with the old behavior or the dev behavior. The updated behavior is
confusing, inconsistent, and hasn't actually helped anything. Is there a
concrete example where the new behavior is actually useful?
So if you want a concrete example, with the updated behavior, search for
booleans becomes difficult to use because outputs from search must be
post-processed to select only the results with boolean output. And the
result without such postprocessing is basically nonsense.
And if I want to search for arrays containing booleans then it's really
painful to screen the return value from search for booleans. Consider:
search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1], [1,3]],
0)
which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
version. For a general search post-process we now need to scan the returned
entries from search and check whether isbool gives the same result on each
entry to identify which ones are valid returns. What a mess!
I can also say that it's very unexpected to a user that
x==true
will return true when x is equal to 1. And once this is absorbed,
particularly odd that it returns false when x==3. In fact, one could argue
that the only reason a user would ever write "x==true" is to check whether x
is in fact exactly equal to the boolean true and not just a value that gets
cast to true in a boolean context.
thehans wrote
This was part of a change to make comparisons more consistent in general.
See my comment here for more explanation:
https://github.com/openscad/openscad/pull/3164#issuecomment-569158586
(Basically try <= or >= operations between 0 / 1 and false / true on
your older versions, and tell me if that makes sense)
Can you provide a self contained example where the change causes a
problem in actual usage?
Boolean types are not "dropped", but there is type coercion which is
now applied consistently between numbers and bools.
is_bool() and is_num() can also be used to determine exact type if needed.
On Sat, Jul 25, 2020 at 9:01 AM Parkinbot <
With 2019.12.21 I get:
echo(true==1); // false
echo(true==0); // false
this means not more and not less: a boolean is not a number (apples are
no
pears) and you could also write:
echo(true=="1"); // false
echo(true=="0"); // false
Thus any code testing a condition like "true == x" imposes an implicit
type
check. Changing this behavior can break such checks as well as reveal
buggy
code written under the assumption Booleans are represented as numbers.
In my libs I have tons of code that uses some backward compatible testing
for lists like "a[0]!=undef". Obviously it has the pitfall:
a=[undef, 1,2,3];
But, I can live with it :-), since using is_list() will break even more
code
as it hits people using older versions of OpenSCAD who are usally less
experienced programmers.
However, of course you are right: There is no obvious reason to drop the
Boolean data type and introduce old fashioned and error prone semantics
in
OpenSCAD.
--
Sent from: http://forum.openscad.org/
OpenSCAD mailing list
It seems that the motivation for the changes was a theoretical sorting
process that needs to sort items of different types. The current dev
version behavior doesn't make much sense and is almost like dropping
booleans and just making "true" a synonym for 1. Except for the fact that
"3" is true. And this is a major inconsistency, not an improvement in
consistency as claimed.
If I search a vector for true entries, e.g. with search([true], [....]) then
the new behavior makes no sense. It gives me entries that are true and
entries that are 1. The two defensible results are entries that are exactly
"true" (as happened in older version) or all entries that would be
interpreted as true in a boolean context, which means all strings, nonempty
lists, nonzero numbers, and so on should be returned. There's no
conceivable reason a user would expect to get back all the "true" and "1"
entries. It's just not a consistent return result. Unless true isn't
really a separate boolean type but is just a synonym for 1.
For relative comparisons it seems like the only reason to compare true to 3
(other than programmer error) is in the sorting context, which was suggested
in the github issue. But does the choice to make true=1 and false=0
actually make sense? I argue that it does not. If I'm sorting a list of
objects I do not find the following to be a reasonable output from a sort
algorithm and can't conceive of a situation where it would be desirable:
[-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
but this would be a legitimate "sorted" output if true==1 and false==0 and
the same for comparisons.
I note that the same dubious logic has not bee applied to strings.
echo(""==0);
echo(""<0);
echo("">0);
all give false in both the july dev and the stable version. Similarly
comparison between lists and scalars also
echo([3]<3);
echo([3]>3);
echo([3]==3);
all give false. So the user who wants to sort a list mixed with lists and
strings and numbers is still on their own to handle comparisons in a
reasonable manner.
I can think of two behaviors that make sense for comparisons between types.
They should either be undef, or there should be a defined order OF TYPES, so
for example:
boolean < number < string < list
In this case the above sort example would presumably sort as
[false,false,true,true,-1, -.5, 0,0, .5, 1, 1, 1, 1.5, 2]
I don't think anybody interested in sorting mixed type lists would be happy
with the previous result, where false and 0 intermix and 1 and true
intermix, so such a user would have to write their own comparison operator
that uses is_bool to check the type to produce a reasonable output---either
with the old behavior or the dev behavior. The updated behavior is
confusing, inconsistent, and hasn't actually helped anything. Is there a
concrete example where the new behavior is actually useful?
So if you want a concrete example, with the updated behavior, search for
booleans becomes difficult to use because outputs from search must be
post-processed to select only the results with boolean output. And the
result without such postprocessing is basically nonsense.
And if I want to search for arrays containing booleans then it's really
painful to screen the return value from search for booleans. Consider:
search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1], [1,3]],
0)
which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
version. For a general search post-process we now need to scan the returned
entries from search and check whether isbool gives the same result on each
entry to identify which ones are valid returns. What a mess!
I can also say that it's very unexpected to a user that
x==true
will return true when x is equal to 1. And once this is absorbed,
particularly odd that it returns false when x==3. In fact, one could argue
that the only reason a user would ever write "x==true" is to check whether x
is in fact exactly equal to the boolean true and not just a value that gets
cast to true in a boolean context.
thehans wrote
> This was part of a change to make comparisons more consistent in general.
>
> See my comment here for more explanation:
> https://github.com/openscad/openscad/pull/3164#issuecomment-569158586
> (Basically try <= or >= operations between 0 / 1 and false / true on
> your older versions, and tell me if that makes sense)
>
> Can you provide a self contained example where the change causes a
> problem in actual usage?
>
> Boolean types are not "dropped", but there is type coercion which is
> now applied consistently between numbers and bools.
> is_bool() and is_num() can also be used to determine exact type if needed.
>
>
> On Sat, Jul 25, 2020 at 9:01 AM Parkinbot <
> rudolf@
> > wrote:
>>
>> With 2019.12.21 I get:
>>
>> echo(true==1); // false
>> echo(true==0); // false
>>
>> this means not more and not less: a boolean is not a number (apples are
>> no
>> pears) and you could also write:
>>
>> echo(true=="1"); // false
>> echo(true=="0"); // false
>>
>> Thus any code testing a condition like "true == x" imposes an implicit
>> type
>> check. Changing this behavior can break such checks as well as reveal
>> buggy
>> code written under the assumption Booleans are represented as numbers.
>> In my libs I have tons of code that uses some backward compatible testing
>> for lists like "a[0]!=undef". Obviously it has the pitfall:
>>
>> a=[undef, 1,2,3];
>>
>> But, I can live with it :-), since using is_list() will break even more
>> code
>> as it hits people using older versions of OpenSCAD who are usally less
>> experienced programmers.
>>
>> However, of course you are right: There is no obvious reason to drop the
>> Boolean data type and introduce old fashioned and error prone semantics
>> in
>> OpenSCAD.
>>
>>
>>
>>
>> --
>> Sent from: http://forum.openscad.org/
>>
>> _______________________________________________
>> OpenSCAD mailing list
>>
> Discuss@.openscad
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@.openscad
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
--
Sent from: http://forum.openscad.org/
HL
Hans L
Sat, Jul 25, 2020 8:42 PM
In cases that expect a boolean such as conditional "if"s, ternary ( ? : ),
or "not" ( ! ) operators, etc, numbers have always been coerced into
bool.
Where 0 (or -0) is false, and all other numbers are true.
This example has same results in any version including 2015.03 :
for (x=[-1,0,1,3,true,false, 1/0, -1/0, 0/0 ]) {
if (x) echo(str(x," is 'true'"));
else echo(str(x," is 'false'"));
if (!x) echo(str("!",x," is 'true'"));
else echo(str("!",x," is 'false'"));
}
echo();
for (x=[-1,0,1,3,true,false, 1/0, -1/0, 0/0 ]) {
echo(str(x," is ", x ? "'true'" : "'false'"));
echo(str("!",x," is ", !x ? "'true'" : "'false'"));
}
So to me, it seems consistent that if: "if(x)" is true, then "if (x==true)"
should also be true.
For relative comparisons it seems like the only reason to compare true to
(other than programmer error) is in the sorting context, which was
in the github issue. But does the choice to make true=1 and false=0
actually make sense? I argue that it does not. If I'm sorting a list of
objects I do not find the following to be a reasonable output from a sort
algorithm and can't conceive of a situation where it would be desirable:
[-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
but this would be a legitimate "sorted" output if true==1 and false==0 and
the same for comparisons.
Yes I did mention this in the context of sorting mixed types, but mainly
just to say that thinking more closely about how mixed types behave was
what led me to discover the inconsistencies in comparison operators.
But I also acknowledged that such sorting would be a weird / rare case, so
I'm not really too upset if it would require special handling for a library
to support such things.
Also note that even though the sorting seems strange here, this is the
exact behavior in Python for example:
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
x=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
y=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
x.sort()
x==y
[-1, -0.5, 0, False, 0, False, 0.5, 1, True, 1, 1, True, 1.5, 2]
If this is "old fashioned" as parkinbot says , then I would be curious to
know what modern language(s) which allow mixed type collections, would
serve a better role-model for OpenSCAD in this regard.
So if you want a concrete example, with the updated behavior, search for
booleans becomes difficult to use because outputs from search must be
post-processed to select only the results with boolean output. And the
result without such postprocessing is basically nonsense.
And if I want to search for arrays containing booleans then it's really
painful to screen the return value from search for booleans. Consider:
search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1],
which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
version. For a general search post-process we now need to scan the
entries from search and check whether isbool gives the same result on each
entry to identify which ones are valid returns. What a mess!
OK, so far I'm hearing that the main thing this actually breaks is certain
usages of the builtin search() function, where the user is searching on
"keys" of mixed boolean and number types. Although WHY they would want to
do this in a real script is not clear to me (outside of adversarially
contrived test-cases).
If this is really wanted/needed for builtin search, then a quick fix could
be to change search() so that it checks for strictly matching types in
addition to "equivalence".
Hans
In cases that expect a boolean such as conditional "if"s, ternary ( ? : ),
or "not" ( ! ) operators, etc, numbers have *always* been coerced into
bool.
Where 0 (or -0) is false, and all other numbers are true.
This example has same results in any version including 2015.03 :
for (x=[-1,0,1,3,true,false, 1/0, -1/0, 0/0 ]) {
if (x) echo(str(x," is 'true'"));
else echo(str(x," is 'false'"));
if (!x) echo(str("!",x," is 'true'"));
else echo(str("!",x," is 'false'"));
}
echo();
for (x=[-1,0,1,3,true,false, 1/0, -1/0, 0/0 ]) {
echo(str(x," is ", x ? "'true'" : "'false'"));
echo(str("!",x," is ", !x ? "'true'" : "'false'"));
}
So to me, it seems consistent that if: "if(x)" is true, then "if (x==true)"
should also be true.
> For relative comparisons it seems like the only reason to compare true to
3
> (other than programmer error) is in the sorting context, which was
suggested
> in the github issue. But does the choice to make true=1 and false=0
> actually make sense? I argue that it does not. If I'm sorting a list of
> objects I do not find the following to be a reasonable output from a sort
> algorithm and can't conceive of a situation where it would be desirable:
>
> [-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
>
> but this would be a legitimate "sorted" output if true==1 and false==0 and
> the same for comparisons.
>
Yes I did mention this in the context of sorting mixed types, but mainly
just to say that thinking more closely about how mixed types behave was
what led me to discover the inconsistencies in comparison operators.
But I also acknowledged that such sorting would be a weird / rare case, so
I'm not really too upset if it would require special handling for a library
to support such things.
Also note that even though the sorting seems strange here, this is the
exact behavior in Python for example:
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> x=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
>>> y=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
>>> x.sort()
>>> x==y
True
>>> x
[-1, -0.5, 0, False, 0, False, 0.5, 1, True, 1, 1, True, 1.5, 2]
If this is "old fashioned" as parkinbot says , then I would be curious to
know what modern language(s) which allow mixed type collections, would
serve a better role-model for OpenSCAD in this regard.
> So if you want a concrete example, with the updated behavior, search for
> booleans becomes difficult to use because outputs from search must be
> post-processed to select only the results with boolean output. And the
> result without such postprocessing is basically nonsense.
>
> And if I want to search for arrays containing booleans then it's really
> painful to screen the return value from search for booleans. Consider:
>
> search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1],
[1,3]],
> 0)
>
> which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
> version. For a general search post-process we now need to scan the
returned
> entries from search and check whether isbool gives the same result on each
> entry to identify which ones are valid returns. What a mess!
OK, so far I'm hearing that the main thing this actually breaks is certain
usages of the builtin search() function, where the user is searching on
"keys" of mixed boolean and number types. Although WHY they would want to
do this in a real script is not clear to me (outside of adversarially
contrived test-cases).
If this is really wanted/needed for builtin search, then a quick fix could
be to change search() so that it checks for strictly matching types in
addition to "equivalence".
Hans
A
adrianv
Sun, Jul 26, 2020 12:07 AM
In cases that expect a boolean such as conditional "if"s, ternary ( ? : ),
or "not" ( ! ) operators, etc, numbers have always been coerced into
bool.
Where 0 (or -0) is false, and all other numbers are true.
So to me, it seems consistent that if: "if(x)" is true, then "if
(x==true)"
should also be true.
This doesn't follow. You are arguing that because 1 becomes true in a
boolean context that therefore true must be one in an integer context.
There is no reason this is true. And actually there's definitely no
reason to expect any kind of typecasting to occur in an expression "if
(x==true)". Why would the type of x get changed? I expect x to be compared
as it is to "true" and the result to be false unless they are the same. The
same type and the same value. I don't think an equality test should ever
change the type of something.
Also the argument above means that you need " if (5==true)" to also evaluate
to true. As I said before, for consistency here, true should test as equal
to all nonzeros, nonempty strings and nonempty lists. "if (3)" is true so
"if (3==true)" should be true. "if ([false])" is true so "if
([false]==true)" should be true.
For relative comparisons it seems like the only reason to compare true to
(other than programmer error) is in the sorting context, which was
in the github issue. But does the choice to make true=1 and false=0
actually make sense? I argue that it does not. If I'm sorting a list of
objects I do not find the following to be a reasonable output from a sort
algorithm and can't conceive of a situation where it would be desirable:
[-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
but this would be a legitimate "sorted" output if true==1 and false==0
and
the same for comparisons.
Yes I did mention this in the context of sorting mixed types, but mainly
just to say that thinking more closely about how mixed types behave was
what led me to discover the inconsistencies in comparison operators.
But I also acknowledged that such sorting would be a weird / rare case, so
I'm not really too upset if it would require special handling for a
library
to support such things.
Also note that even though the sorting seems strange here, this is the
exact behavior in Python for example:
Python 3.8.2 (default, Jul 16 2020, 14:00:26)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
x=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
y=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
x.sort()
x==y
[-1, -0.5, 0, False, 0, False, 0.5, 1, True, 1, 1, True, 1.5, 2]
Indeed. This is because in Python, True and False are in fact integers.
The boolean type is a subclass of the integer type, so this behavior is an
unavoidable consequence of that. This also means that the statement
(x==True) in python doesn't require a typecast if x is 1 because both types
are integers already. As someone said earlier, the decision to make true
and false equal to 1 and 0 is basically getting rid of the boolean type and
making booleans into integers. If that's what you want to do, shouldn't you
make it fully consistent the way it is in Python? Namely that true+true=2,
true*false=0, etc? And indexing works, so you can do foo[true]? Which
might honestly be useful---probably THE only useful thing that comes out of
booleans actually being integers.
If you define true and false to be integers then everything becomes
consistent and also well defined. OpenSCAD is a long way from this, because
most integer operations fail on booleans. Also, why do this? I assume it
was done in Python because python didn't have a boolean type until version
2.3, and then they wanted to make it backward compatible with how people did
things before. I don't think it makes sense to copy a feature of a
language that's basically a historical artifact of that language's
development path.
If this is "old fashioned" as parkinbot says , then I would be curious to
know what modern language(s) which allow mixed type collections, would
serve a better role-model for OpenSCAD in this regard.
Probably any strongly type language that has a real boolean type would be a
better role model. Before the boolean type existed people did comparisons
using numbers. But making the boolean type act half like an integer and
half not isn't old fashioned. It's just inconsistent and confusing. It
doesn't make sense, so users will be surprised. And there's no
justification for the current inconsistent behavior that explains why
booleans are integers when you wish they wouldn't be but not when you might
want them to be.
So if you want a concrete example, with the updated behavior, search for
booleans becomes difficult to use because outputs from search must be
post-processed to select only the results with boolean output. And the
result without such postprocessing is basically nonsense.
And if I want to search for arrays containing booleans then it's really
painful to screen the return value from search for booleans. Consider:
search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1],
which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
version. For a general search post-process we now need to scan the
entries from search and check whether isbool gives the same result on
each
entry to identify which ones are valid returns. What a mess!
OK, so far I'm hearing that the main thing this actually breaks is certain
usages of the builtin search() function, where the user is searching on
"keys" of mixed boolean and number types. Although WHY they would want to
do this in a real script is not clear to me (outside of adversarially
contrived test-cases).
If this is really wanted/needed for builtin search, then a quick fix could
be to change search() so that it checks for strictly matching types in
addition to "equivalence".
No, any use of booleans breaks with search, not just complicated ones.
It's just that the workaround is more awkward when it's a complicated
search.
Here's the simple case. What if I want to find the first true entry, which
does not seem like a contrived operation.
Old way:
final_result = search([true], data, 1);
New way:
results = search([true], data, 0);
true_results = [for (entry=results[0]) if (is_bool(data[entry])) entry];
final_result2 = len(true_results)>0 ? [true_results[1]] : [[]];
So yeah, if you insist on keeping the new, inconsistent and confusing
behavior for booleans, then I changing search to reproduce the old behavior
seems advisable. Would be nice to have a real equality operator while
you're at it that gives the true result of comparisons without unexpected
typecasting.
What I'm really puzzled about is that this change seems to break things, and
it is counter-intuitive, and it offers NO BENEFIT. Where is your example of
the advantage of this version. As I see it:
Disadvantages of the new approach:
- Inconsistent behavior where true/false are sort of treated as integers
like in Python, but only sometimes.
- Treating booleans as integers is not required or necessarily the best way
to do things. OpenSCAD is not Python.
- Counterintuitive results like "true==1" evaluates as true. (Guess this
makes sense to Python users, but it does not make sense if booleans are
their own type.)
- To test that x is true must write "x && is_bool(x)", decidedly
non-obvious.
- Makes search() hard to use with boolean inputs
Advantages of new approach:
- Consistency in treatment of booleans as integers in relative comparison
with integers
This isn't a real advantage. Can you give any example of a real advantage,
where one can write better code with this? When would I want to use
relative comparisons with booleans at all??? The argument for consistency
is basically taking the useful case of equality comparison and breaking it
to support consistency for the non-useful case of relative comparisons.
The right way to address the consistency problem is to ban relative
comparisons between types, that is, a<b is undef if the operands are
different types. In a strongly typed language this is the expected
outcome.
But if you want to make booleans act like integers in the name of
consistency then you should get rid of the boolean type and just make them
integers, with true and false simply synonyms for 1 and 0. This simplifies
the language a bit and then nobody is surprised by behavior once this
underlying definition is understood.
--
Sent from: http://forum.openscad.org/
thehans wrote
> In cases that expect a boolean such as conditional "if"s, ternary ( ? : ),
> or "not" ( ! ) operators, etc, numbers have *always* been coerced into
> bool.
> Where 0 (or -0) is false, and all other numbers are true.
>
>
> So to me, it seems consistent that if: "if(x)" is true, then "if
> (x==true)"
> should also be true.
This doesn't follow. You are arguing that because 1 becomes true in a
boolean context that therefore true must be one in an integer context.
There is no reason this is true. And actually there's *definitely* no
reason to expect any kind of typecasting to occur in an expression "if
(x==true)". Why would the type of x get changed? I expect x to be compared
as it is to "true" and the result to be false unless they are the same. The
same type and the same value. I don't think an equality test should *ever*
change the type of something.
Also the argument above means that you need " if (5==true)" to also evaluate
to true. As I said before, for consistency here, true should test as equal
to all nonzeros, nonempty strings and nonempty lists. "if (3)" is true so
"if (3==true)" should be true. "if ([false])" is true so "if
([false]==true)" should be true.
>> For relative comparisons it seems like the only reason to compare true to
> 3
>> (other than programmer error) is in the sorting context, which was
> suggested
>> in the github issue. But does the choice to make true=1 and false=0
>> actually make sense? I argue that it does not. If I'm sorting a list of
>> objects I do not find the following to be a reasonable output from a sort
>> algorithm and can't conceive of a situation where it would be desirable:
>>
>> [-1, -.5, 0, false, 0, false, .5, 1, true, 1, 1, true, 1.5, 2]
>>
>> but this would be a legitimate "sorted" output if true==1 and false==0
>> and
>> the same for comparisons.
>>
>
> Yes I did mention this in the context of sorting mixed types, but mainly
> just to say that thinking more closely about how mixed types behave was
> what led me to discover the inconsistencies in comparison operators.
> But I also acknowledged that such sorting would be a weird / rare case, so
> I'm not really too upset if it would require special handling for a
> library
> to support such things.
>
> Also note that even though the sorting seems strange here, this is the
> exact behavior in Python for example:
> Python 3.8.2 (default, Jul 16 2020, 14:00:26)
> [GCC 9.3.0] on linux
> Type "help", "copyright", "credits" or "license" for more information.
>>>> x=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
>>>> y=[-1, -.5, 0, False, 0, False, .5, 1, True, 1, 1, True, 1.5, 2]
>>>> x.sort()
>>>> x==y
> True
>>>> x
> [-1, -0.5, 0, False, 0, False, 0.5, 1, True, 1, 1, True, 1.5, 2]
Indeed. This is because in Python, True and False are in fact integers.
The boolean type is a subclass of the integer type, so this behavior is an
unavoidable consequence of that. This also means that the statement
(x==True) in python doesn't require a typecast if x is 1 because both types
are integers already. As someone said earlier, the decision to make true
and false equal to 1 and 0 is basically getting rid of the boolean type and
making booleans into integers. If that's what you want to do, shouldn't you
make it fully consistent the way it is in Python? Namely that true+true=2,
true*false=0, etc? And indexing works, so you can do foo[true]? Which
might honestly be useful---probably THE only useful thing that comes out of
booleans actually being integers.
If you define true and false to be integers then everything becomes
consistent and also well defined. OpenSCAD is a long way from this, because
most integer operations fail on booleans. Also, why do this? I assume it
was done in Python because python didn't have a boolean type until version
2.3, and then they wanted to make it backward compatible with how people did
things before. I don't think it makes sense to copy a feature of a
language that's basically a historical artifact of that language's
development path.
> If this is "old fashioned" as parkinbot says , then I would be curious to
> know what modern language(s) which allow mixed type collections, would
> serve a better role-model for OpenSCAD in this regard.
Probably any strongly type language that has a real boolean type would be a
better role model. Before the boolean type existed people did comparisons
using numbers. But making the boolean type act half like an integer and
half not isn't old fashioned. It's just inconsistent and confusing. It
doesn't make sense, so users will be surprised. And there's no
justification for the current inconsistent behavior that explains why
booleans are integers when you wish they wouldn't be but not when you might
want them to be.
>> So if you want a concrete example, with the updated behavior, search for
>> booleans becomes difficult to use because outputs from search must be
>> post-processed to select only the results with boolean output. And the
>> result without such postprocessing is basically nonsense.
>>
>> And if I want to search for arrays containing booleans then it's really
>> painful to screen the return value from search for booleans. Consider:
>>
>> search([[true,1]], [[true,true],[true,1],[true,3], [1,true], [1,1],
> [1,3]],
>> 0)
>>
>> which returns [[1]] in the old version and [[0, 1, 3, 4]] in the new
>> version. For a general search post-process we now need to scan the
> returned
>> entries from search and check whether isbool gives the same result on
>> each
>> entry to identify which ones are valid returns. What a mess!
>
> OK, so far I'm hearing that the main thing this actually breaks is certain
> usages of the builtin search() function, where the user is searching on
> "keys" of mixed boolean and number types. Although WHY they would want to
> do this in a real script is not clear to me (outside of adversarially
> contrived test-cases).
> If this is really wanted/needed for builtin search, then a quick fix could
> be to change search() so that it checks for strictly matching types in
> addition to "equivalence".
No, *any* use of booleans breaks with search, not just complicated ones.
It's just that the workaround is more awkward when it's a complicated
search.
Here's the simple case. What if I want to find the first true entry, which
does not seem like a contrived operation.
Old way:
final_result = search([true], data, 1);
New way:
results = search([true], data, 0);
true_results = [for (entry=results[0]) if (is_bool(data[entry])) entry];
final_result2 = len(true_results)>0 ? [true_results[1]] : [[]];
So yeah, if you insist on keeping the new, inconsistent and confusing
behavior for booleans, then I changing search to reproduce the old behavior
seems advisable. Would be nice to have a real equality operator while
you're at it that gives the true result of comparisons without unexpected
typecasting.
What I'm really puzzled about is that this change seems to break things, and
it is counter-intuitive, and it offers NO BENEFIT. Where is your example of
the advantage of this version. As I see it:
Disadvantages of the new approach:
* Inconsistent behavior where true/false are sort of treated as integers
like in Python, but only sometimes.
* Treating booleans as integers is not required or necessarily the best way
to do things. OpenSCAD is not Python.
* Counterintuitive results like "true==1" evaluates as true. (Guess this
makes sense to Python users, but it does not make sense if booleans are
their own type.)
* To test that x is true must write "x && is_bool(x)", decidedly
non-obvious.
* Makes search() hard to use with boolean inputs
Advantages of new approach:
* Consistency in treatment of booleans as integers in relative comparison
with integers
This isn't a real advantage. Can you give any example of a real advantage,
where one can write better code with this? When would I want to use
relative comparisons with booleans at all??? The argument for consistency
is basically taking the useful case of equality comparison and breaking it
to support consistency for the non-useful case of relative comparisons.
The right way to address the consistency problem is to ban relative
comparisons between types, that is, a<b is undef if the operands are
different types. In a strongly typed language this is the expected
outcome.
But if you want to make booleans act like integers in the name of
consistency then you should get rid of the boolean type and just make them
integers, with true and false simply synonyms for 1 and 0. This simplifies
the language a bit and then nobody is surprised by behavior once this
underlying definition is understood.
--
Sent from: http://forum.openscad.org/
DM
Doug Moen
Sun, Jul 26, 2020 5:22 AM
So to me, it seems consistent that if: "if(x)" is true, then "if (x==true)" should also be true.
OpenSCAD boolean operations treat [] as equivalent to false. For consistency, should [] == false?
OpenSCAD boolean operations treat 3 as equivalent to true. For consistency, should 3 == true?
OpenSCAD arithmetic operations do not treat booleans as equivalent to numbers. 1+true is undef, not 2.
For consistency, shouldn't true != 1?
I think that in general, a==b should return true if a and b are operationally equivalent in all contexts, and false otherwise. Another formulation that I like is: a == b should return true if and only if a and b have the same printed representation. Any exceptions to this general rule should be justified by interoperability concerns. For example, 0 == -0 can be justified to support interoperability with floating point algorithms ported from other programming languages, since the IEEE float standard requires 0 == -0 and almost all other programming languages follow that.
> So to me, it seems consistent that if: "if(x)" is true, then "if (x==true)" should also be true.
OpenSCAD boolean operations treat [] as equivalent to false. For consistency, should [] == false?
OpenSCAD boolean operations treat 3 as equivalent to true. For consistency, should 3 == true?
OpenSCAD arithmetic operations do *not* treat booleans as equivalent to numbers. 1+true is undef, not 2.
For consistency, shouldn't true != 1?
I think that in general, a==b should return true if a and b are operationally equivalent in all contexts, and false otherwise. Another formulation that I like is: a == b should return true if and only if a and b have the same printed representation. Any exceptions to this general rule should be justified by interoperability concerns. For example, 0 == -0 can be justified to support interoperability with floating point algorithms ported from other programming languages, since the IEEE float standard requires 0 == -0 and almost all other programming languages follow that.
HL
Hans L
Sun, Jul 26, 2020 6:44 AM
OK, I see your points and admit that my logic in that statement was
flawed.
I suppose I hadn't put a ton of thought into it and was attempting to
post-rationalize, but upon reflection, really the main reason this behavior
was chosen is that it is consistent with C++.
So it seemed natural to me, developing for OpenSCAD in C++, to treat double
to bool comparisons in the same way (the code literally returns the result
of the corresponding C++ operator between double and bool). And as an
aside, there are no integers in OpenSCAD.
Now everyone can balk that C++ is old fashioned with all its legacy quirks
and OpenSCAD is not Python / C / C++ / Javascript / etc. but I honestly
didn't think anyone would even consider this change controversial... and
there was no input of other opinions at the time (nor in the 7months that
the change has been in nightlies).
I only knew that the existing behavior (where <= and >= behaved C-like, but
not other comparisons) made absolutely no sense, but I suppose the change
could have just as easily gone the other way: to make <= and >= always
return false when comparing between numbers and bools.
If we can agree that's what our users want/expect in general, then
personally I would be fine with changing it around.
As for the more drastic option of trying to make OpenSCAD strongly typed
(which I don't believe anyone has ever claimed it to be), by having
comparisons between any two different types returning undef instead of
false... I have a feeling doing that would cause significantly more
breakages to existing scripts, and general confusion, than the previous
change.
On Sun, Jul 26, 2020 at 12:26 AM Doug Moen doug@moens.org wrote:
So to me, it seems consistent that if: "if(x)" is true, then "if
(x==true)" should also be true.
OpenSCAD boolean operations treat [] as equivalent to false. For
consistency, should [] == false?
OpenSCAD boolean operations treat 3 as equivalent to true. For
consistency, should 3 == true?
OpenSCAD arithmetic operations do not treat booleans as equivalent to
numbers. 1+true is undef, not 2.
For consistency, shouldn't true != 1?
I think that in general, a==b should return true if a and b are
operationally equivalent in all contexts, and false otherwise. Another
formulation that I like is: a == b should return true if and only if a and
b have the same printed representation. Any exceptions to this general rule
should be justified by interoperability concerns. For example, 0 == -0 can
be justified to support interoperability with floating point algorithms
ported from other programming languages, since the IEEE float standard
requires 0 == -0 and almost all other programming languages follow that.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
OK, I see your points and admit that my logic in that statement was
flawed.
I suppose I hadn't put a ton of thought into it and was attempting to
post-rationalize, but upon reflection, really the main reason this behavior
was chosen is that it is consistent **with C++**.
So it seemed natural to me, developing for OpenSCAD in C++, to treat double
to bool comparisons in the same way (the code literally returns the result
of the corresponding C++ operator between double and bool). And as an
aside, there are no integers in OpenSCAD.
Now everyone can balk that C++ is old fashioned with all its legacy quirks
and OpenSCAD is not Python / C / C++ / Javascript / etc. but I honestly
didn't think anyone would even consider this change controversial... and
there was no input of other opinions at the time (nor in the 7months that
the change has been in nightlies).
I only knew that the existing behavior (where <= and >= behaved C-like, but
not other comparisons) made absolutely no sense, but I suppose the change
could have just as easily gone the other way: to make <= and >= always
return false when comparing between numbers and bools.
If we can agree that's what our users want/expect in general, then
personally I would be fine with changing it around.
As for the more drastic option of trying to make OpenSCAD strongly typed
(which I don't believe anyone has ever claimed it to be), by having
comparisons between any two different types returning undef instead of
false... I have a feeling doing that would cause significantly more
breakages to existing scripts, and general confusion, than the previous
change.
On Sun, Jul 26, 2020 at 12:26 AM Doug Moen <doug@moens.org> wrote:
> > So to me, it seems consistent that if: "if(x)" is true, then "if
> (x==true)" should also be true.
>
> OpenSCAD boolean operations treat [] as equivalent to false. For
> consistency, should [] == false?
> OpenSCAD boolean operations treat 3 as equivalent to true. For
> consistency, should 3 == true?
>
> OpenSCAD arithmetic operations do *not* treat booleans as equivalent to
> numbers. 1+true is undef, not 2.
> For consistency, shouldn't true != 1?
>
> I think that in general, a==b should return true if a and b are
> operationally equivalent in all contexts, and false otherwise. Another
> formulation that I like is: a == b should return true if and only if a and
> b have the same printed representation. Any exceptions to this general rule
> should be justified by interoperability concerns. For example, 0 == -0 can
> be justified to support interoperability with floating point algorithms
> ported from other programming languages, since the IEEE float standard
> requires 0 == -0 and almost all other programming languages follow that.
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
P
Parkinbot
Sun, Jul 26, 2020 10:14 AM
As for the more drastic option of trying to make OpenSCAD strongly typed
(which I don't believe anyone has ever claimed it to be), by having
comparisons between any two different types returning undef instead of
false... I have a feeling doing that would cause significantly more
breakages to existing scripts, and general confusion, than the previous
change.
This is not an option for a boolean operation unless you identify "undef" as
"false" and get caught in the same pitfall. You could throw an error or at
least a warning, but this will break tons of legacy code.
I would opt for a clear and consistent implementation, which is neither
the new nor the old implementation.
--
Sent from: http://forum.openscad.org/
thehans wrote
> As for the more drastic option of trying to make OpenSCAD strongly typed
> (which I don't believe anyone has ever claimed it to be), by having
> comparisons between any two different types returning undef instead of
> false... I have a feeling doing that would cause significantly more
> breakages to existing scripts, and general confusion, than the previous
> change.
This is not an option for a boolean operation unless you identify "undef" as
"false" and get caught in the same pitfall. You could throw an error or at
least a warning, but this will break tons of legacy code.
I would opt for a clear and *consistent* implementation, which is neither
the new nor the old implementation.
--
Sent from: http://forum.openscad.org/