'void' as a value

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

'void' as a value

Andrew Fedoniouk
Consider this function:

function foo( t ) {
  if( t ) return undefined;
  // no return here, sic!
}

As you see it returns 'undefined' when 't' gets true.
When 't' is false it also returns the same 'undefined'.

But conceptually these are two different return cases/values:
  'undefined' and 'nothing' (or 'void').

Allowing functions to return 'void' values will give us opportunity
to use ordinary functions as iterators without need of separate Iterator entity.

Consider this Range implementation:

function Range(low, high){
  var index = low;
  return function() { if( index < high )  return index++;  }
}

and its use:

for(var i in Range(0,10) )
  ...

Internal implementation of for..in is calling the function in each iteration
and stops when the function will return 'void'.

To keep backward compatibility the 'void' value shall not be assignable,
so after this:

function returnsNothing() { return; }

var retval = returnsNothing();

the retval will still contain 'undefined' value.

And expression:
   returnsNothing() === undefined
yields 'true'.

Therefore the 'void' value is mostly for internal use.

But in some cases user space code may also be interested in
checking returns for 'void' values. In this case we can provide
checkVoid(probe,valOrCallback) primitive:

var result = checkVoid( returnsNothing(), "nothing" );

in this case the result will get "nothing" value. If valOrCallback is a function
then it will be invoked to indicate 'void' value:

var gotNothing = false;
var result = checkVoid( returnsNothing(), function() { gotNothing = true } );

My pardon if something similar to this was already discussed by the group.

I am using this mechanism in my TIScript and found it quite useful and effective
for implementing iterator cases - at least no need for exceptions as shown here:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators

--
Andrew Fedoniouk.

http://terrainformatica.com
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
Lately people post overlong proposals that do not define the proposed
primitives first. Also errors in the sketching don't help credibility.

> Andrew Fedoniouk <mailto:[hidden email]>
> September 8, 2013 11:24 AM
> Consider this function:
>
> function foo( t ) {
> if( t ) return undefined;
> // no return here, sic!
> }
>
> As you see it returns 'undefined' when 't' gets true.
> When 't' is false it also returns the same 'undefined'.
>
> But conceptually these are two different return cases/values:
> 'undefined' and 'nothing' (or 'void').
>
> Allowing functions to return 'void' values will give us opportunity
> to use ordinary functions as iterators without need of separate
> Iterator entity.

You mean separate iteration protocol? This has been considered, but
first some problems.

>
> Consider this Range implementation:
>
> function Range(low, high){
> var index = low;
> return function() { if( index < high ) return index++; }
> }
>
> and its use:
>
> for(var i in Range(0,10) )

You must mean for (var i of Range(0, 10)) here, because for-in cannot be
changed to iterate without breaking backward compatibility.

> ...
>
> Internal implementation of for..in is calling the function in each
> iteration
> and stops when the function will return 'void'.

Assuming you mean for-of, the problems for any "new undefined-like
sentinel" remain:

* It will be too easily returned by accident, especially given how it is
hard to distinguish from undefined.

* It may end up in collections being iterated over, causing premature
termination.

Any in-band value is a problem by the latter point. Thus the previous
Pythonic out-of-band StopIteration exception, or the current ES6
wrapping of iteration protocol step results in {value, done} structure
to avoid overloading the returned value and creating a pigeon hole problem.
>
> To keep backward compatibility the 'void' value shall not be assignable,
> so after this:
>
> function returnsNothing() { return; }
>
> var retval = returnsNothing();
>
> the retval will still contain 'undefined' value.

This will make very hard-to-detect bugs, by the first bullet point above.

>
> And expression:
> returnsNothing() === undefined
> yields 'true'.
>
> Therefore the 'void' value is mostly for internal use.
>
> But in some cases user space code may also be interested in
> checking returns for 'void' values. In this case we can provide
> checkVoid(probe,valOrCallback) primitive:
>
> var result = checkVoid( returnsNothing(), "nothing" );
>
> in this case the result will get "nothing" value. If valOrCallback is
> a function
> then it will be invoked to indicate 'void' value:
>
> var gotNothing = false;
> var result = checkVoid( returnsNothing(), function() { gotNothing =
> true } );
>
> My pardon if something similar to this was already discussed by the group.

We have discussed in-band sentinels (including where the
iterator-creator can choose the sentinel), out-of-band exceptions, and
finally the chosen ES6 solution: out-of-band result wrapping with a done
flag, many times.

In no case does anyone that I've spoken to, on TC39 or anywhere else
around this planet, want *yet another* bottom type and singleton value a
la null and undefined. No one. Those who speak Spanish and nearby
languages tend to say "¡Basta!" -- I'm not kidding :-|.

/be
>
> I am using this mechanism in my TIScript and found it quite useful and
> effective
> for implementing iterator cases - at least no need for exceptions as
> shown here:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Andrew Fedoniouk
On Sun, Sep 8, 2013 at 12:39 PM, Brendan Eich <[hidden email]> wrote:

> Lately people post overlong proposals that do not define the proposed
> primitives first. Also errors in the sketching don't help credibility.
>
>> Andrew Fedoniouk <mailto:[hidden email]>
>> September 8, 2013 11:24 AM
>>
>> Consider this Range implementation:
>>
>> function Range(low, high){
>> var index = low;
>> return function() { if( index < high ) return index++; }
>> }
>>
>> and its use:
>>
>> for(var i in Range(0,10) )
>
>
> You must mean for (var i of Range(0, 10)) here, because for-in cannot be
> changed to iterate without breaking backward compatibility.

Correct, "for..of"  is the right construct for that.

>
>> ...
>>
>> Internal implementation of for..in is calling the function in each
>> iteration
>> and stops when the function will return 'void'.
>
>
> Assuming you mean for-of, the problems for any "new undefined-like sentinel"
> remain:
>
> * It will be too easily returned by accident, especially given how it is
> hard to distinguish from undefined.

I do not understand the problem to be honest. Are you saying that
it is hard to distinguish these two cases:

  return something;
  // and
  return;

?

>
> * It may end up in collections being iterated over, causing premature
> termination.

I think you've missed my point. 'void' IS 'undefined' by any means
except of slightly
different internal representation. It is like 'undefined' value has
special flag .isVoid that
is not exposed outside.

While assigning that undefined/isVoid value to any variable or field
the isVoid gets
cleared - in other words you cannot store void value anywhere.

So collections or variables simply cannot contain 'void' values. void is void.

>
> Any in-band value is a problem by the latter point. Thus the previous
> Pythonic out-of-band StopIteration exception, or the current ES6 wrapping of
> iteration protocol step results in {value, done} structure to avoid
> overloading the returned value and creating a pigeon hole problem.

{value, done}  creates another problem - heap pollution, this:

var counter = 0;
for( var n of Range(0,10) )
  ++counter;

should not cause heap allocations. In case of protocol you've described
{value, done} object gets allocated. And I suspect it is so on each iteration.

...

"ĄBasta!"

Creo en tu palabra.

--
Andrew Fedoniouk.

http://terrainformatica.com
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Chris-tina Whyte
In reply to this post by Andrew Fedoniouk

In no case does anyone that I've spoken to, on TC39 or anywhere else around this planet, want *yet another* bottom type and singleton value a la null and undefined. No one. Those who speak Spanish and nearby languages tend to say "ĄBasta!" -- I'm not kidding :-|.

This.They cause way more (subtle and hard-to-debug) problems than they're worth, just take a look at NullPointerExceptions in Java and the like. Nope. Explicitly wrapping in a Maybe/Option type is much better, and ES6's direction captures the same idea.

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
In reply to this post by Andrew Fedoniouk
September 8, 2013 2:11 PM

...

Internal implementation of for..in is calling the function in each
iteration
and stops when the function will return 'void'.
Assuming you mean for-of, the problems for any "new undefined-like sentinel"
remain:

* It will be too easily returned by accident, especially given how it is
hard to distinguish from undefined.

I do not understand the problem to be honest. Are you saying that
it is hard to distinguish these two cases:

  return something;
  // and
  return;

?

A reader can distinguish those, although return undefined; is less easy to spot at a glance. And delegation, meaning return bar(); where bar returns undefined, is in general beyond static analysis. So, yes!

The situation is worse when you consider the caller, not the callee (the iterator-consumer, not the iterator implementation). People *will* mix up undefined and void, Murphy was an optimist.

* It may end up in collections being iterated over, causing premature
termination.

I think you've missed my point. 'void' IS 'undefined' by any means
except of slightly
different internal representation. It is like 'undefined' value has
special flag .isVoid that
is not exposed outside.

While assigning that undefined/isVoid value to any variable or field
the isVoid gets
cleared - in other words you cannot store void value anywhere.

This fixes only part of the problem (see delegation point above). Worse, it requires a write barrier to censor void via undefined. That is going to lose any implementors who aren't sold otherwise.

So collections or variables simply cannot contain 'void' values. void is void.

Collection in space is stream in time, the delegation problem remains. But you are right, I should have added the write barrier to the bullet-list of problems!

Any in-band value is a problem by the latter point. Thus the previous
Pythonic out-of-band StopIteration exception, or the current ES6 wrapping of
iteration protocol step results in {value, done} structure to avoid
overloading the returned value and creating a pigeon hole problem.

{value, done}  creates another problem - heap pollution, this:

var counter = 0;
for( var n of Range(0,10) )
  ++counter;

should not cause heap allocations.

I quite agree, and proposed StopIteration (in general, a class, per PEP380) for years. But this heap allocation is relatively straightforward to avoid in modern JITs, compared to other optimizations already done for JS. When for-of drivers the iteration, there's no need for the allocation, which is typically done in a return expression:

function Range(start, end) {
  let i = start;
  return {
    next: function () {
      if (i >= end) return {done: true};
      return {value: i++, done: false};
    }
  };
}

Generator functions make optimization even easier, since the returned object shape is guaranteed:

function Range(start, end) {
  for (let i = start; i < end; i++)
    yield i;
}


In case of protocol you've described
{value, done} object gets allocated. And I suspect it is so on each iteration.

Not observably when for-of creates and drives the iteration protocol and the iterator does not pass or stash a reference to the returned {value, done} object anywhere else.

This optimization possibility is a crucial part of the design. Were it not so, I suspect we would still be using an OOB exception approach.

...

"ĄBasta!"

Creo en tu palabra.

Gracias.

/be


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Axel Rauschmayer
In reply to this post by Andrew Fedoniouk
Generators can also return values, not only yield them: That way, a generator function can call another one via `yield*` and receive a result (the value returned by the latter generator function [1]). That’s why a sentinel value is not enough, you need to be able to indicate that the iterator is done and to return a value at the same time.

As for allocating too many objects: To iterate, you already need to create an iterator object. If I’m not mistaken, the next() method could return `this` and the iterator itself could have the properties `value` and `done`.




On Sep 8, 2013, at 23:11 , Andrew Fedoniouk <[hidden email]> wrote:

On Sun, Sep 8, 2013 at 12:39 PM, Brendan Eich <[hidden email]> wrote:
Lately people post overlong proposals that do not define the proposed
primitives first. Also errors in the sketching don't help credibility.

Andrew Fedoniouk <[hidden email]>
September 8, 2013 11:24 AM

Consider this Range implementation:

function Range(low, high){
var index = low;
return function() { if( index < high ) return index++; }
}

and its use:

for(var i in Range(0,10) )


You must mean for (var i of Range(0, 10)) here, because for-in cannot be
changed to iterate without breaking backward compatibility.

Correct, "for..of"  is the right construct for that.


...

Internal implementation of for..in is calling the function in each
iteration
and stops when the function will return 'void'.


Assuming you mean for-of, the problems for any "new undefined-like sentinel"
remain:

* It will be too easily returned by accident, especially given how it is
hard to distinguish from undefined.

I do not understand the problem to be honest. Are you saying that
it is hard to distinguish these two cases:

 return something;
 // and
 return;

?


* It may end up in collections being iterated over, causing premature
termination.

I think you've missed my point. 'void' IS 'undefined' by any means
except of slightly
different internal representation. It is like 'undefined' value has
special flag .isVoid that
is not exposed outside.

While assigning that undefined/isVoid value to any variable or field
the isVoid gets
cleared - in other words you cannot store void value anywhere.

So collections or variables simply cannot contain 'void' values. void is void.


Any in-band value is a problem by the latter point. Thus the previous
Pythonic out-of-band StopIteration exception, or the current ES6 wrapping of
iteration protocol step results in {value, done} structure to avoid
overloading the returned value and creating a pigeon hole problem.

{value, done}  creates another problem - heap pollution, this:

var counter = 0;
for( var n of Range(0,10) )
 ++counter;

should not cause heap allocations. In case of protocol you've described
{value, done} object gets allocated. And I suspect it is so on each iteration.

...

"ĄBasta!"

Creo en tu palabra.

--
Andrew Fedoniouk.

http://terrainformatica.com
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

-- 
Dr. Axel Rauschmayer



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
September 8, 2013 3:34 PM
Generators can also return values, not only yield them: That way, a generator function can call another one via `yield*` and receive a result (the value returned by the latter generator function [1]). That’s why a sentinel value is not enough, you need to be able to indicate that the iterator is done and to return a value at the same time.

Great point. In the design decision space, we have

If iterator returns next value directly
  If fixed "done" sentinel value
    Andrew's void value or similar...
  else
    User-configured value per-iterator
Else if via thrown exception
  StopIteration or equivalent
Else
  iterator returns {value, done}.


No one wants another masquerades-as-undefined value. We rejected User-configured in-band done value per iterator a while ago. Your point that both of these "iterator returns next value directly" cases require an OOB value to stop iteration, but that precludes a final return value, is a good one. Any choice in the first "then" above fails this requirement.

StopIteration *did* support 'return expr;' from the generator body, per PEP380 -- the thrown StopIteration is a fresh instance with a value property. This is workable but it has a smell (that stinky exception smell), which drove TC39 under Dave's leadership toward the final option.

As for allocating too many objects: To iterate, you already need to create an iterator object. If I’m not mistaken, the next() method could return `this` and the iterator itself could have the properties `value` and `done`.

No, we can't spec that because it's observable and it makes a mutable-state pigeon-hole problem.

The for-of-drives-iterator case, with a well-written iterator (or by definition with a generator), has no problem optimizing, in spite of the general observability of the {value, done} object returned by each next.

Rather, it is the hand-coded task.js-like async libraries that will have to cope with some object allocation overhead.

Generational GC fans like to say these short-lived objects are "free", but I'm a known TANSTAAFL quoter. Still, pretty cheap, and if it ever became a problem for such libraries, we could solve it.

/be


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
Brendan Eich wrote:
> Rather, it is the hand-coded task.js-like async libraries that will
> have to cope with some object allocation overhead.

Even here, the destructuring optimization mentioned long ago by Lars
Hansen (see
http://wiki.ecmascript.org/doku.php?id=discussion:destructuring_assignment#performance):

   let {value, done} = task.thread.next(result);

and the object allocation could be optimized away.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

RE: 'void' as a value

Nathan Wall
In reply to this post by Brendan Eich-3
> In no case does anyone that I've spoken to, on TC39 or anywhere else
> around this planet, want *yet another* bottom type and singleton value a
> la null and undefined. No one. Those who speak Spanish and nearby
> languages tend to say "¡Basta!" -- I'm not kidding :-|.

Except those in favor of nil?

*Ahem*
Carry on!

Nathan    
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
> Nathan Wall <mailto:[hidden email]>
> September 8, 2013 8:04 PM
>
> Except those in favor of nil?

nil, None, Nothing -- I got a milion of 'em ;-).

/be

>
> *Ahem*
> Carry on!
>
> Nathan
> Andrew Fedoniouk <mailto:[hidden email]>
> September 8, 2013 11:24 AM
> Consider this function:
>
> function foo( t ) {
> if( t ) return undefined;
> // no return here, sic!
> }
>
> As you see it returns 'undefined' when 't' gets true.
> When 't' is false it also returns the same 'undefined'.
>
> But conceptually these are two different return cases/values:
> 'undefined' and 'nothing' (or 'void').
>
> Allowing functions to return 'void' values will give us opportunity
> to use ordinary functions as iterators without need of separate
> Iterator entity.
>
> Consider this Range implementation:
>
> function Range(low, high){
> var index = low;
> return function() { if( index < high ) return index++; }
> }
>
> and its use:
>
> for(var i in Range(0,10) )
> ...
>
> Internal implementation of for..in is calling the function in each
> iteration
> and stops when the function will return 'void'.
>
> To keep backward compatibility the 'void' value shall not be assignable,
> so after this:
>
> function returnsNothing() { return; }
>
> var retval = returnsNothing();
>
> the retval will still contain 'undefined' value.
>
> And expression:
> returnsNothing() === undefined
> yields 'true'.
>
> Therefore the 'void' value is mostly for internal use.
>
> But in some cases user space code may also be interested in
> checking returns for 'void' values. In this case we can provide
> checkVoid(probe,valOrCallback) primitive:
>
> var result = checkVoid( returnsNothing(), "nothing" );
>
> in this case the result will get "nothing" value. If valOrCallback is
> a function
> then it will be invoked to indicate 'void' value:
>
> var gotNothing = false;
> var result = checkVoid( returnsNothing(), function() { gotNothing =
> true } );
>
> My pardon if something similar to this was already discussed by the group.
>
> I am using this mechanism in my TIScript and found it quite useful and
> effective
> for implementing iterator cases - at least no need for exceptions as
> shown here:
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

David Bruant-5
In reply to this post by Brendan Eich-3
Le 08/09/2013 21:39, Brendan Eich a écrit :
> In no case does anyone that I've spoken to, on TC39 or anywhere else
> around this planet, want *yet another* bottom type and singleton value
> a la null and undefined. No one. Those who speak Spanish and nearby
> languages tend to say "¡Basta!" -- I'm not kidding :-|.
Two values are already arguably (!) a regrettable feature
https://github.com/DavidBruant/ECMAScript-regrets/issues/26

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Claude Pache

Le 9 sept. 2013 à 10:35, David Bruant <[hidden email]> a écrit :

> Le 08/09/2013 21:39, Brendan Eich a écrit :
>> In no case does anyone that I've spoken to, on TC39 or anywhere else around this planet, want *yet another* bottom type and singleton value a la null and undefined. No one. Those who speak Spanish and nearby languages tend to say "¡Basta!" -- I'm not kidding :-|.
> Two values are already arguably (!) a regrettable feature https://github.com/DavidBruant/ECMAScript-regrets/issues/26
>
> David

For me, it is a excellent feature, if we get the correct semantic:
* `undefined` means "no value", or "nothing";
* `null` means "empty value", or (well) "null".

Practical usefulness:
* ES5: JSON stringification of object: `null` means `null`, and `undefined` means "no value, don't include the corresponding key".
* ES6: default values in function arguments (and maybe destructuring assignment?): `null` means `null`, and `undefined` means "no value, take the default".

—Claude

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

David Bruant-5
Le 09/09/2013 11:41, Claude Pache a écrit :
> Le 9 sept. 2013 à 10:35, David Bruant <[hidden email]> a écrit :
>
>> Le 08/09/2013 21:39, Brendan Eich a écrit :
>>> In no case does anyone that I've spoken to, on TC39 or anywhere else around this planet, want *yet another* bottom type and singleton value a la null and undefined. No one. Those who speak Spanish and nearby languages tend to say "¡Basta!" -- I'm not kidding :-|.
>> Two values are already arguably (!) a regrettable feature https://github.com/DavidBruant/ECMAScript-regrets/issues/26
>>
>> David
> For me, it is a excellent feature, if we get the correct semantic:
The issue has a lengthy debate too ;-)

> * `undefined` means "no value", or "nothing";
> * `null` means "empty value", or (well) "null".
>
> Practical usefulness:
> * ES5: JSON stringification of object: `null` means `null`, and `undefined` means "no value, don't include the corresponding key".
> * ES6: default values in function arguments (and maybe destructuring assignment?): `null` means `null`, and `undefined` means "no value, take the default".
This is all after-the-fact justification. I understand the usefulness
made of this feature now that we have the 2 values, but I wonder if
given the choice to start over a newJS would be designed with 2 such values.

Among the nonsense of undefined-as-a-value:
     var wm = new WeakMap();
     var o = {};
     console.log(wm.has(o), wm.get(o)); // false, undefined
     wm.set(o, undefined);
     console.log(wm.has(o), wm.get(o)); // true, undefined

So we can "define" a weakmap entry with the "undefined" value. That's
how objects work, so that can't be changed. I wonder what has been
gained for weakmaps. For sure, some memory is wasted to keep the "has"
boolean working.
WeakMaps would feel simpler if wm.set(o, undefined) was an equivalent
for wm.delete... to me at least...

David
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Claude Pache

Le 9 sept. 2013 à 11:51, David Bruant <[hidden email]> a écrit :

> Le 09/09/2013 11:41, Claude Pache a écrit :
>> Le 9 sept. 2013 à 10:35, David Bruant <[hidden email]> a écrit :
>>
>>> Le 08/09/2013 21:39, Brendan Eich a écrit :
>>>> In no case does anyone that I've spoken to, on TC39 or anywhere else around this planet, want *yet another* bottom type and singleton value a la null and undefined. No one. Those who speak Spanish and nearby languages tend to say "¡Basta!" -- I'm not kidding :-|.
>>> Two values are already arguably (!) a regrettable feature https://github.com/DavidBruant/ECMAScript-regrets/issues/26
>>>
>>> David
>> For me, it is a excellent feature, if we get the correct semantic:
> The issue has a lengthy debate too ;-)
>
>> * `undefined` means "no value", or "nothing";
>> * `null` means "empty value", or (well) "null".
>>
>> Practical usefulness:
>> * ES5: JSON stringification of object: `null` means `null`, and `undefined` means "no value, don't include the corresponding key".
>> * ES6: default values in function arguments (and maybe destructuring assignment?): `null` means `null`, and `undefined` means "no value, take the default".
> This is all after-the-fact justification. I understand the usefulness made of this feature now that we have the 2 values, but I wonder if given the choice to start over a newJS would be designed with 2 such values.

Even if the two particular cases I've mentioned were not forecasted when designing JavaScript, it does not diminish the value of the feature. When designing JS, some decisions had been taken, whose usefulness or badness has been understood only after experience.

>
> Among the nonsense of undefined-as-a-value:
>    var wm = new WeakMap();
>    var o = {};
>    console.log(wm.has(o), wm.get(o)); // false, undefined
>    wm.set(o, undefined);
>    console.log(wm.has(o), wm.get(o)); // true, undefined
>
> So we can "define" a weakmap entry with the "undefined" value. That's how objects work, so that can't be changed. I wonder what has been gained for weakmaps. For sure, some memory is wasted to keep the "has" boolean working.
> WeakMaps would feel simpler if wm.set(o, undefined) was an equivalent for wm.delete... to me at least...
>

Yes, `undefined` does have its quirks. Maybe, when designing JS some years ago, it would have been semantically better to make `obj.foo = _i_dont_exist_` an equivalent of `delete obj.foo`, so that getting `obj.foo` would search the value in the prototype chain of `obj` instead of returning `undefined`?

—Claude

> David



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
In reply to this post by David Bruant-5
> David Bruant <mailto:[hidden email]>
> September 9, 2013 2:51 AM
> Le 09/09/2013 11:41, Claude Pache a écrit :
>> * `undefined` means "no value", or "nothing";
>> * `null` means "empty value", or (well) "null".
>>
>> Practical usefulness:
>> * ES5: JSON stringification of object: `null` means `null`, and
>> `undefined` means "no value, don't include the corresponding key".
>> * ES6: default values in function arguments (and maybe destructuring
>> assignment?): `null` means `null`, and `undefined` means "no value,
>> take the default".
> This is all after-the-fact justification. I understand the usefulness
> made of this feature now that we have the 2 values, but I wonder if
> given the choice to start over a newJS would be designed with 2 such
> values.

There's really no point, is there? FTR (I've written this before), I had
both null and undefined because JS was under not only "make it look like
Java" marching orders, it was meant to connect to Java, with objects
reflecting both ways. This was LiveConnect, shipped in Netscape 3.

But from the start I had null for Java's object reference types, meaning
"no object"; and undefined as the bottom of the semiattice, meaning "no
value". Java didn't have a way to express primitive | reference unions,
rather had boxing (has this changed?).

> Among the nonsense of undefined-as-a-value:
>     var wm = new WeakMap();
>     var o = {};
>     console.log(wm.has(o), wm.get(o)); // false, undefined
>     wm.set(o, undefined);
>     console.log(wm.has(o), wm.get(o)); // true, undefined

Why are you blaming undefined for this? If we didn't have it, the same
design decision could have been made for null. Isn't this really a
WeakMap design choice?

/be

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Brendan Eich-3
Brendan Eich wrote:
> But from the start I had null for Java's object reference types,
> meaning "no object"; and undefined as the bottom of the semiattice,

"semilattice"

> meaning "no value". Java didn't have a way to express primitive |
> reference unions, rather had boxing (has this changed?).

The alternative would have been to make everything an object and null
the bottom. Would have been better but I was in a tearing hurry, and
using unboxed primitives was easier, and "made it look like Java" --
which has primitives with boxing wrappers. So I do blame myself, but I
also blame Java :-|.

/be
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: 'void' as a value

Rick Waldron
In reply to this post by Claude Pache



On Mon, Sep 9, 2013 at 5:41 AM, Claude Pache <[hidden email]> wrote:

Le 9 sept. 2013 à 10:35, David Bruant <[hidden email]> a écrit :

> Le 08/09/2013 21:39, Brendan Eich a écrit :
>> In no case does anyone that I've spoken to, on TC39 or anywhere else around this planet, want *yet another* bottom type and singleton value a la null and undefined. No one. Those who speak Spanish and nearby languages tend to say "¡Basta!" -- I'm not kidding :-|.
> Two values are already arguably (!) a regrettable feature https://github.com/DavidBruant/ECMAScript-regrets/issues/26
>
> David

For me, it is a excellent feature, if we get the correct semantic:
* `undefined` means "no value", or "nothing";
* `null` means "empty value", or (well) "null".

This was exactly my response, and I'll add that the only regrettable aspect is the typeof null issue.


Practical usefulness:
* ES5: JSON stringification of object: `null` means `null`, and `undefined` means "no value, don't include the corresponding key".
* ES6: default values in function arguments (and maybe destructuring assignment?): `null` means `null`, and `undefined` means "no value, take the default".

Yep. I think that in the world of ES6 we'll see developers learning and respecting the difference between null and undefined.

Rick

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss