Page MenuHomePhabricator

non-commutativity of short-circuiting operations due to truthy/falsy values
Open, Needs TriagePublicBUG REPORT

Description

Steps to Reproduce:

Run the following snippets and see the results:

coderesultlink
("0"&123) === "0"truehere
(123&"0") === "0"falsehere
(""&123) === ""truehere
(123&"") === ""falsehere
("1"|123) === "1"truehere
(false|"1") === "1"falsehere
("2"|123) === "2"truehere
(false|"2") === "2"falsehere

Expected Results:

Either all true, or all false.

Discussion:

This really depends on the design decision, but it should be consistent. That is:

  • Either a boolean operation always cast the answer to a boolean; or
  • it returns one of the operands

Right now, we return one of the operands when it's short-circuiting, but cast to a boolean when it's not.

Event Timeline

Well, the title is a little bit misleading actually. Commutativity would not be desirable if we want to return one of the operands, because

("1" | 1) === "1"

but

(1 | "1") === 1

IOW, if we do want to return one of the operands, short-circuiting would make commutativity impossible to achieve.

For <a> & <b>

Here's one possible specification for it: it should be equivalent (or even rewrite) to

gensym := <a>; if gensym then <b> else gensym end

Note that <a> could have a side effect (e.g., appending an element to an array), so we need := so that the expression is evaluated only once, not twice. gensym refers to any new symbol that does not occur in the entire program.

Here's another possibility:

if <a> then (if <b> then true else false end) else false end
For <a> | <b>:

One possibility is:

gensym := <a>; if gensym then gensym else <b>

Another possibility is:

if <a> then true else (if <b> then true else false end) end

To make it compatible with other boolean operation, i.e., ^, I think the better way should be to cast the result to a boolean. This is also great if one want to implement via re-interpretation of <a> & <b> as if <a> then (if <b> then true else false end) else false end.

Looking at this again, I'm for the "return a boolean" option. This seems more predictable, and possibly more useful (or at least what people might expect) in the context of abuse filters. I guess the change itself wouldn't be super-hard, the problem here is understanding what filters would be affected by this change, and I don't think this is really doable...

Huji updated the task description. (Show Details)

Most programming languages I know which allow non-strict coding (i.e. variables or operations with mixed data types) seem to try to convert anything to Boolean if there is a Boolean involved (and in cases not involving a Boolean, they will try to convert everything to a number if a number is involved). While my knowledge and experience is limited, I agree that "convert everything to a Boolean if a Boolean is involved" makes sense.

Indeed, the results are a bit inconsistent currently…

CodeResult
"foo" & "bar"true
"foo" | "bar""foo"
"foo" & ""false
"foo" | """foo"
"" & "bar"""
"" | "bar"true

I would also opt for returning a boolean in all of the above cases.