Boolean objects in conditionals

# Peter Michaux (16 years ago)

The following suggests (i.e. could be interpreted as) a false Boolean object is a "truthy" value.

(new Boolean(false)) ? "a" : "b" "a"

The following suggests a false Boolean object is a "falsy" value

((new Boolean(false)) == true) ? "a" : "b" "b"

I understand what is going on here but it seems like a bad state of affairs.

Does this need to be remedied? Can it be?

It would be useful to have an object that is effectively "false" in an "if" conditional but which can also have properties like an object can.

Peter

# Lasse R.H. Nielsen (16 years ago)

On Fri, 28 Nov 2008 22:42:45 +0100, Peter Michaux <petermichaux at gmail.com> wrote:

The following suggests (i.e. could be interpreted as) a false Boolean object is a "truthy" value.

(new Boolean(false)) ? "a" : "b" "a"

Yes.

The following suggests a false Boolean object is a "falsy" value

((new Boolean(false)) == true) ? "a" : "b" "b"

It clearly shows that "new Boolean(false)" is not equal to "true". However, there are lots of non-falsy values that are not equal to true, so I don't see it suggesting anything about the falsy-ness of "new Boolean(false)", any more than
((new String("pickles") == true) ? "a" : "b"

I understand what is going on here but it seems like a bad state of affairs.

Wrapper objects are generally bad, if you ask me. They serve no purpose, except as a specification device for allowing properties on basic values.

Does this need to be remedied? Can it be?

I don't think it is needed. The current rules are sometimes surprising, but they are clear: all objects are considered true.

It would be useful to have an object that is effectively "false" in an "if" conditional but which can also have properties like an object can.

If objects are no longer all "true", then I would prefer each object to be able to decide its truth value. However, it would probably break a lot of idiomatic constructs, like if (obj) { obj.method(); } or var x = obj || defaultObj;

# David-Sarah Hopwood (16 years ago)

Peter Michaux wrote:

The following suggests (i.e. could be interpreted as) a false Boolean object is a "truthy" value.

(new Boolean(false)) ? "a" : "b" "a"

The following suggests a false Boolean object is a "falsy" value

((new Boolean(false)) == true) ? "a" : "b" "b"

I understand what is going on here but it seems like a bad state of affairs.

I think the problem is that wrapper objects exist at all, not any specific aspect of their semantics. There is no reason to have such wrappers in a language in which is is possible for a given variable to hold either a primitive value or an object reference. Programmers should simply avoid using them (except where they are created and immediately discarded as a result of calling a method on a primitive value).

# Peter Michaux (16 years ago)

On Fri, Nov 28, 2008 at 2:20 PM, Lasse R.H. Nielsen

If objects are no longer all "true", then I would prefer each object to be able to decide its truth value.

An object's toString method is called when the object is coerced to a string. Why not toNumber and toBoolean?

Peter

# Brendan Eich (16 years ago)

On Nov 28, 2008, at 5:07 PM, Peter Michaux wrote:

On Fri, Nov 28, 2008 at 2:20 PM, Lasse R.H. Nielsen

If objects are no longer all "true", then I would prefer each
object to be able to decide its truth value.

An object's toString method is called when the object is coerced to a string. Why not toNumber and toBoolean?

An object has valueOf(hint) for the former. In ES1 we agreed not to
convert object to boolean, to avoid re-conversion in expressions such
as the right-hand side of the final assignment in this program:

a = {valueOf: function(hint){if (hint == "boolean")return false;
return 42}}; b = falsy(); c = truthy(); x = (a && b) || c;

Evaluating (a && b) would, if we converted object to boolean using
valueOf, convert a to false to decide whether to short-circuit and
yield false instead of evaluating b. But the result of (a && b) would
still be the reference to the object denoted by a -- the result would
not be false.

Then we would evaluate (a || c) which would convert a to boolean
again, getting false and not short-circuiting evaluation of c. The
result of the whole thing stored in x would be whatever c evaluated to.

Because the object denoted by a could convert several times, some
members of TC39 at the time (esp. Shon of Microsoft) objected. No
other conversion/operator combo has such a multiple-implicit-calls-in- an-expression-where-denoted-once property.

Efficiency might favor caching intermediates but that would be
detectable if the valueOf function has effects. The spec can't mandate
caching or not-caching, so the degree of freedom here would degrade
interoperation marginally. Anyway mutation makes the multiple calls
particularly hazardous compared to other conversion/op pairs.

This may seem like too minor or abstract a point to get hung up on,
but it almost broke the standardization of && and || as Perl-ish value- preserving multiplexing operators.

I don't see a way to overcome this objection, and I don't think it's
in anyone's interest to allow object-to-false custom conversion at
this stage. There are falsy-object use cases, but they're rare. The
boolean primitive, if modeled as an object (we did this in ES4's RI),
is unique among the built-ins. Bridging to other languages may be a
use-case for implicit conversion from object to boolean, but these
bridge cases usually involve deep magic not expressible in JS.

Since we have valueOf and will in Harmony, I see little gain and much
complexity in adding toNumber or anything else, never mind toBoolean.
The big lesson here is EIBTI (google it). Enough implicit conversions!

# Peter Michaux (16 years ago)

On Fri, Nov 28, 2008 at 6:17 PM, Brendan Eich <brendan at mozilla.com> wrote:

The big lesson here is EIBTI

The class sugar discussion in the last few days didn't seem to go too far but I was thinking about EIBTI in relation to "this". Automatic variables like "this" and "arguments" are quite uncomfortable. For the example of a point class, what about

class Point (self, x, y) { // ... }

Has this idea been kicked around for ES classes?

Peter

# Brendan Eich (16 years ago)

On Nov 28, 2008, at 7:54 PM, Peter Michaux wrote:

On Fri, Nov 28, 2008 at 6:17 PM, Brendan Eich <brendan at mozilla.com>
wrote:

The big lesson here is EIBTI

The class sugar discussion in the last few days didn't seem to go too far but I was thinking about EIBTI in relation to "this". Automatic variables like "this" and "arguments" are quite uncomfortable. For the example of a point class, what about

class Point (self, x, y) {

That formal parameter list doesn't match the actual arguments supplied
to the constructor.

// ... }

Has this idea been kicked around for ES classes?

Mark M. sketched an idea for lexical "this" where the declarative
syntax went something like:

class C(x,y) { ... private self { function m1(a,b) { /* use "self" to denote receiver / ... } function m2(c) { / ditto */ ... } ... } }

I may have misremembered, but Mark will follow up if so. This was
during a discussion of private vs. public.

# Peter Michaux (16 years ago)

On Fri, Nov 28, 2008 at 8:43 PM, Brendan Eich <brendan at mozilla.com> wrote:

class C(x,y) { ... private self { function m1(a,b) { /* use "self" to denote receiver / ... } function m2(c) { / ditto */ ... } ... } }

Almost may as well just always start the class with a first line like the following.

class C(x,y) { var self = this; function m1(a,b) { /* use "self" to denote receiver / ... } function m2(c) { / ditto */ ... } }

It gives non-dynamically bound "this" access which was on of the issues in the wiki page. Probably not enough boiler plate to warrant sugar.

Peter

# Brendan Eich (16 years ago)

On Nov 28, 2008, at 9:05 PM, Peter Michaux wrote:

Almost may as well just always start the class with a first line like the following.

class C(x,y) { var self = this; function m1(a,b) { /* use "self" to denote receiver / ... } function m2(c) { / ditto */ ... } }

It gives non-dynamically bound "this" access which was on of the issues in the wiki page. Probably not enough boiler plate to warrant sugar.

Possibly. It could get old if one is often referring to the whole
receiver object. How often does that occur?

It's easy to argue that desugaring should be minimal to convey to
readers who grok the desugared language exactly what's going on. This
is like arguing against ++x because x += 1 is short enough and more
clear about order of operation -- but += is itself subject to such
reductionistic opposition. What's wrong with x = x + 1 every annoying
time? C'mon, it was enough for Pascal and most BASICs!

We need user testing to get a better handle on usability. In the
absence of that, I'm likely to oppose pedagogical reductionism in
sugared additions. I've seen such over-minimized proposals cancel
themselves out by taking everything away one slice at a time, as the
proposal slides downslope toward the simpler but probably less usable
kernel language.

# Peter Michaux (16 years ago)

On Fri, Nov 28, 2008 at 9:23 PM, Brendan Eich <brendan at mozilla.com> wrote:

On Nov 28, 2008, at 9:05 PM, Peter Michaux wrote:

Almost may as well just always start the class with a first line like the following.

class C(x,y) { var self = this; function m1(a,b) { /* use "self" to denote receiver / ... } function m2(c) { / ditto */ ... } }

It gives non-dynamically bound "this" access which was on of the issues in the wiki page. Probably not enough boiler plate to warrant sugar.

Possibly. It could get old if one is often referring to the whole receiver object. How often does that occur?

It's easy to argue that desugaring should be minimal to convey to readers who grok the desugared language exactly what's going on. This is like arguing against ++x because x += 1 is short enough and more clear about order of operation -- but += is itself subject to such reductionistic opposition. What's wrong with x = x + 1 every annoying time? C'mon, it was enough for Pascal and most BASICs!

We need user testing to get a better handle on usability. In the absence of that, I'm likely to oppose pedagogical reductionism in sugared additions. I've seen such over-minimized proposals cancel themselves out by taking everything away one slice at a time, as the proposal slides downslope toward the simpler but probably less usable kernel language.

I wonder if macros will come to ES before there is an agreement about classes. Anyone putting money on that?

Peter

# Lasse R.H. Nielsen (16 years ago)

On Sat, 29 Nov 2008 01:15:53 +0100, David-Sarah Hopwood <david.hopwood at industrial-designers.co.uk> wrote:

I think the problem is that wrapper objects exist at all, not any specific aspect of their semantics. There is no reason to have such wrappers in a language in which is is possible for a given variable to hold either a primitive value or an object reference. Programmers should simply avoid using them (except where they are created and immediately discarded as a result of calling a method on a primitive value)

It's a hassle on implementers that you have to create these implicit objects at all, when they aren't needed most (99%) of the time. You still need to create them for the last 1% of the cases, since user written methods can escape the object, e.g., Number.prototype.box = function() { return this; }; var n = (42).box();

I would prefer to have "this" refer to a basic value instead when calling "methods on primitive values". I.e.: (42).toString() should not be equivalent to "new Number(42).toString()", but to something simliar to "Number.prototype.toString.call(42)" that actually uses "42" as the value of "this".

Alas, that's probably too big a change for 3.1 :(

# Mark S. Miller (16 years ago)

On Sat, Nov 29, 2008 at 5:40 AM, Lasse R.H. Nielsen <atwork at infimum.dk>wrote:

Number.prototype.box = function() { return this; }; var n = (42).box();

I would prefer to have "this" refer to a basic value instead when calling "methods on primitive values". I.e.: (42).toString() should not be equivalent to "new Number(42).toString()", but to something simliar to "Number.prototype.toString.call(42)" that actually uses "42" as the value of "this".

Alas, that's probably too big a change for 3.1 :(

It's not too big a change from ES3.1-strict, but it may be too late. If it's not too late, I would be in favor of this change. (I have previously advocated this change on es-discuss.) Note that

Number.prototype.box = function() {
  "use strict";
  return this;
}
var n = (42).box.call(42);

will correctly do what you want in ES3.1, so it seems a shame if we can't fix the simpler form.

# Mark S. Miller (16 years ago)

On Fri, Nov 28, 2008 at 7:54 PM, Peter Michaux <petermichaux at gmail.com>wrote:

The class sugar discussion in the last few days didn't seem to go too far [...]

Partially my fault. Your excellent responses to some of my earlier messages deserve a careful read before responding. Likewise for Kris' post. I hope to do so today or tomorrow.

# David-Sarah Hopwood (16 years ago)

Peter Michaux wrote:

I wonder if macros will come to ES before there is an agreement about classes. Anyone putting money on that?

No, I'd say it is vanishingly unlikely. There are at least as many technically difficult and/or controversial issues in the design of a macro system as there are in a class-based OO system.