public inbox for kawa@sourceware.org
 help / color / mirror / Atom feed
* proposed changes to handling of false and end-of-list
@ 2013-06-29  6:47 Per Bothner
  2013-07-01  3:09 ` Matthieu Vachon
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Per Bothner @ 2013-06-29  6:47 UTC (permalink / raw)
  To: kawa

A discussion on the kawa-commonlisp-dev list has suggested
we might want to consider some changes in Kawa's handling
of null, false, and the empty list.

The high-level summary:
* Java null (#!null in Scheme syntax) would be considered false
(rather than true).  I.e. in an expression (if c e1 e2) if c
evaluates to Java null *or* a java.lang.Boolean such that
c.booleanValue()==false, then e2 is evaluated; otherwise e1 is evaluated.
* The function null? would return true both of the empty list '()
(the value of LList.Empty) and Java null.  A linked-list may be
terminated by either '() (i.e. LList.Empty) or Java null.  Lists
constructed using the Scheme reader or the 'list' function would
by terminated by LList.Empty as now.
* Common Lisp, Emacs Lisp, and similar languages (which we will
call "Lisp") would represent nil using Java null (rather than as
now LList.Empty).  Lisp would recognize the same values as "true"
as Scheme does; likewise for end-of-list.
* This change would have some negative performance impact, but
hopefully not much.

The biggest motivation for this change is improved compatibility
with Lisp.  This is similar to the solution adopted by Guile:
http://www.gnu.org/software/guile/manual/html_node/Nil.html
(We might consider implementing #nil as a synonym for #!null,
for Guile compatibility.)

However, even if you don't care about Lisp, it probably seems
reasonable to consider Java null "false" rather than "true".
Allowing #!null as the end of a list may be less valuable,
but it does seem preferable for (null? #!null) to be true.

There are also some anomalies it would be nice to fix.
Java (and Kawa) allow you to create fresh java.lang.Boolean
objects:
     (define-constant b1 (java.lang.Boolean #f))
However, this object is considered true, not false:
     (if b1 1 0) ==> 1 ; not (as one might expect) 0

Currently (if c e1 e2) is compiled to the equivalent of:
     (c != Boolean.FALSE ? e1 : e2)
The proposal would change this to:
     (isTrue(c) ? e1 : e2)
where isTrue is this library method:

public static final boolean isTrue(Object value) {
    return value != null
       && (! (value instanceof Boolean)
           || ((Boolean) value).booleanValue()));
}

This is obviously slower; however, it is not as bad as it seems.
If the compiler determines that the type of the expression c
is 'boolean', then the generated code is the same as Java:
     (c ? e1 : e2)
The Kawa type 'boolean' is the same as Java - i.e. a primitive
(non-object) type.

For example:
    (if (> x y) e1 e2)
compiles to:
    (NumberCompare.$Gr(x, y) ? e1 : e2)
because NumberCompare.$Gr has return-type boolean.
The same is true of other predicates, comparisons,
and types tests.  (Or at least it is supposed to be -
bugs may exist.)

Finally, you can always optimize by hand.  If you want
the old behavior (and generated code) you can always do:
    (if (not (eq? c #f)) e1 e2)
Since both 'not' and 'eq?' are optimized this generates
the same code as (if c e1 e2) now does.

Comments?  Does this seem like a worthwhile change?
Of course this is a not a simple one-line change, so
it would take a while (and some intermediate steps)
to implement fully.
-- 
	--Per Bothner
per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-06-29  6:47 proposed changes to handling of false and end-of-list Per Bothner
@ 2013-07-01  3:09 ` Matthieu Vachon
  2013-07-01  6:20   ` Per Bothner
  2013-07-01 11:17 ` Alex Mitchell
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 11+ messages in thread
From: Matthieu Vachon @ 2013-07-01  3:09 UTC (permalink / raw)
  To: Per Bothner; +Cc: kawa

On Sat, Jun 29, 2013 at 2:47 AM, Per Bothner <per@bothner.com> wrote:
> A discussion on the kawa-commonlisp-dev list has suggested
> we might want to consider some changes in Kawa's handling
> of null, false, and the empty list.
>
> The high-level summary:
> * Java null (#!null in Scheme syntax) would be considered false
> (rather than true).  I.e. in an expression (if c e1 e2) if c
> evaluates to Java null *or* a java.lang.Boolean such that
> c.booleanValue()==false, then e2 is evaluated; otherwise e1 is evaluated.
> * The function null? would return true both of the empty list '()
> (the value of LList.Empty) and Java null.

All-in for this change, this is really a good move and will ease creation of
conditional code that handles both #!null and #f construction at one time
when checking for edge-cases. In my opinion, this will increase interoperability
between Scheme and Java code

> A linked-list may be
> terminated by either '() (i.e. LList.Empty) or Java null.  Lists
> constructed using the Scheme reader or the 'list' function would
> by terminated by LList.Empty as now.

I'm less sure about this change, how would this work. If I understand
correctly, writing `(1 2 3)` or `(list 1 2 3)` would have a '() as the last
element. For the null part, I would I create such list. Something like
this `(list 1 2 3 #!null)` would not end with a '() but rather a #!null ?

> * Common Lisp, Emacs Lisp, and similar languages (which we will
> call "Lisp") would represent nil using Java null (rather than as
> now LList.Empty).  Lisp would recognize the same values as "true"
> as Scheme does; likewise for end-of-list.
> * This change would have some negative performance impact, but
> hopefully not much.
>
> The biggest motivation for this change is improved compatibility
> with Lisp.  This is similar to the solution adopted by Guile:
> http://www.gnu.org/software/guile/manual/html_node/Nil.html
> (We might consider implementing #nil as a synonym for #!null,
> for Guile compatibility.)
>

This seems reasonable. But I'm unsure of all the implications
for this change on my existing code base. Do you think this change
would be fully backward compatible?

> However, even if you don't care about Lisp, it probably seems
> reasonable to consider Java null "false" rather than "true".
> Allowing #!null as the end of a list may be less valuable,
> but it does seem preferable for (null? #!null) to be true.
>

Totally right.

> There are also some anomalies it would be nice to fix.
> Java (and Kawa) allow you to create fresh java.lang.Boolean
> objects:
>     (define-constant b1 (java.lang.Boolean #f))
> However, this object is considered true, not false:
>     (if b1 1 0) ==> 1 ; not (as one might expect) 0
>
> Currently (if c e1 e2) is compiled to the equivalent of:
>     (c != Boolean.FALSE ? e1 : e2)
> The proposal would change this to:
>     (isTrue(c) ? e1 : e2)
> where isTrue is this library method:
>
> public static final boolean isTrue(Object value) {
>    return value != null
>       && (! (value instanceof Boolean)
>           || ((Boolean) value).booleanValue()));
> }
>
> This is obviously slower; however, it is not as bad as it seems.
> If the compiler determines that the type of the expression c
> is 'boolean', then the generated code is the same as Java:
>     (c ? e1 : e2)
> The Kawa type 'boolean' is the same as Java - i.e. a primitive
> (non-object) type.
>
> For example:
>    (if (> x y) e1 e2)
> compiles to:
>    (NumberCompare.$Gr(x, y) ? e1 : e2)
> because NumberCompare.$Gr has return-type boolean.
> The same is true of other predicates, comparisons,
> and types tests.  (Or at least it is supposed to be -
> bugs may exist.)
>
> Finally, you can always optimize by hand.  If you want
> the old behavior (and generated code) you can always do:
>    (if (not (eq? c #f)) e1 e2)
> Since both 'not' and 'eq?' are optimized this generates
> the same code as (if c e1 e2) now does.
>

This is a good idea, it will be easier to think and reason about
the code if a Boolean object false is considered as false
in condition. It is all good from my point of view, even
for the performance hit, that is not bad as it seems
as you stated.

> Comments?  Does this seem like a worthwhile change?
> Of course this is a not a simple one-line change, so
> it would take a while (and some intermediate steps)
> to implement fully.

It's all for the best.

I will probably be free to help either by testing the changes on
my code base of by giving a hand with the implementation.

> --
>         --Per Bothner
> per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-01  3:09 ` Matthieu Vachon
@ 2013-07-01  6:20   ` Per Bothner
  2013-07-05  1:13     ` Matthieu Vachon
  0 siblings, 1 reply; 11+ messages in thread
From: Per Bothner @ 2013-07-01  6:20 UTC (permalink / raw)
  To: Matthieu Vachon; +Cc: kawa

On 06/30/2013 08:09 PM, Matthieu Vachon wrote:
> On Sat, Jun 29, 2013 at 2:47 AM, Per Bothner <per@bothner.com> wrote:
>> A linked-list may be
>> terminated by either '() (i.e. LList.Empty) or Java null.  Lists
>> constructed using the Scheme reader or the 'list' function would
>> by terminated by LList.Empty as now.
>
> I'm less sure about this change, how would this work. If I understand
> correctly, writing `(1 2 3)` or `(list 1 2 3)` would have a '() as the last
> element.

Not the "last element" - the "tail".  The last element is 3.  The
last (i.e. 3rd) cons cell (pair) has 3 as the value of its car and '()
(i.e.  LList.Empty) as the value of its cdr.

> For the null part, I would I create such list. Something like
> this `(list 1 2 3 #!null)` would not end with a '() but rather a #!null ?

You're confusing car and cdr.  `(1 2 3 #!null)` is a 4-element list,
whose last (i.e. 4th) cons cell (pair) has #!null as the value of its
car and '() (i.e.  LList.Empty) as the value of its cdr.

However, `(1 2 3 . #!null)` (note the dot) is a 3-element list
last (i.e. 3rd) cons cell (pair) has 3 as the value of its car and #!null
as the value of its cdr.

`(1 2 3 . ())` is in all respects equivalent to `(1 2 3)`.  However,
`(1 2 3 . ())` and `(1 2 3 . #!null)` are the same *when viewed as
a list*, however they would not be equal?  They're not equal? because
as explained in the "Equality" section here:
http://www.gnu.org/software/guile/manual/html_node/Nil.html

However, most functions that work on lists, such as length and map,
would treat `(1 2 3 . ())` and `(1 2 3 . #!null)` the same.

> This seems reasonable. But I'm unsure of all the implications
> for this change on my existing code base. Do you think this change
> would be fully backward compatible?

No, it will not.  Most obviously:
   (if #!null 't 'f)
would return 'f where it currently returns 't.
Even if you don't use #!null explicitly, it will show up
if you call a Java method that returns null.
-- 
	--Per Bothner
per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-06-29  6:47 proposed changes to handling of false and end-of-list Per Bothner
  2013-07-01  3:09 ` Matthieu Vachon
@ 2013-07-01 11:17 ` Alex Mitchell
  2013-07-05 18:44 ` Jamison Hope
  2015-02-21  4:04 ` Per Bothner
  3 siblings, 0 replies; 11+ messages in thread
From: Alex Mitchell @ 2013-07-01 11:17 UTC (permalink / raw)
  To: Per Bothner; +Cc: kawa

Hi Per,

This seems like a worthwhile change to me. I know I've had to explicitly handle Java null in a few places in HypeDyn, so having null? behave consistently would be helpful. I'm not sure if the change to have Java null considered false will cause me any problems but I think it's worth the trouble for the benefits the resulting consistency will bring.

Alex

On Jun 29, 2013, at 2:47 PM, Per Bothner <per@bothner.com> wrote:

> A discussion on the kawa-commonlisp-dev list has suggested
> we might want to consider some changes in Kawa's handling
> of null, false, and the empty list.
> 
> The high-level summary:
> * Java null (#!null in Scheme syntax) would be considered false
> (rather than true).  I.e. in an expression (if c e1 e2) if c
> evaluates to Java null *or* a java.lang.Boolean such that
> c.booleanValue()==false, then e2 is evaluated; otherwise e1 is evaluated.
> * The function null? would return true both of the empty list '()
> (the value of LList.Empty) and Java null.  A linked-list may be
> terminated by either '() (i.e. LList.Empty) or Java null.  Lists
> constructed using the Scheme reader or the 'list' function would
> by terminated by LList.Empty as now.
> * Common Lisp, Emacs Lisp, and similar languages (which we will
> call "Lisp") would represent nil using Java null (rather than as
> now LList.Empty).  Lisp would recognize the same values as "true"
> as Scheme does; likewise for end-of-list.
> * This change would have some negative performance impact, but
> hopefully not much.
> 
> The biggest motivation for this change is improved compatibility
> with Lisp.  This is similar to the solution adopted by Guile:
> http://www.gnu.org/software/guile/manual/html_node/Nil.html
> (We might consider implementing #nil as a synonym for #!null,
> for Guile compatibility.)
> 
> However, even if you don't care about Lisp, it probably seems
> reasonable to consider Java null "false" rather than "true".
> Allowing #!null as the end of a list may be less valuable,
> but it does seem preferable for (null? #!null) to be true.
> 
> There are also some anomalies it would be nice to fix.
> Java (and Kawa) allow you to create fresh java.lang.Boolean
> objects:
>    (define-constant b1 (java.lang.Boolean #f))
> However, this object is considered true, not false:
>    (if b1 1 0) ==> 1 ; not (as one might expect) 0
> 
> Currently (if c e1 e2) is compiled to the equivalent of:
>    (c != Boolean.FALSE ? e1 : e2)
> The proposal would change this to:
>    (isTrue(c) ? e1 : e2)
> where isTrue is this library method:
> 
> public static final boolean isTrue(Object value) {
>   return value != null
>      && (! (value instanceof Boolean)
>          || ((Boolean) value).booleanValue()));
> }
> 
> This is obviously slower; however, it is not as bad as it seems.
> If the compiler determines that the type of the expression c
> is 'boolean', then the generated code is the same as Java:
>    (c ? e1 : e2)
> The Kawa type 'boolean' is the same as Java - i.e. a primitive
> (non-object) type.
> 
> For example:
>   (if (> x y) e1 e2)
> compiles to:
>   (NumberCompare.$Gr(x, y) ? e1 : e2)
> because NumberCompare.$Gr has return-type boolean.
> The same is true of other predicates, comparisons,
> and types tests.  (Or at least it is supposed to be -
> bugs may exist.)
> 
> Finally, you can always optimize by hand.  If you want
> the old behavior (and generated code) you can always do:
>   (if (not (eq? c #f)) e1 e2)
> Since both 'not' and 'eq?' are optimized this generates
> the same code as (if c e1 e2) now does.
> 
> Comments?  Does this seem like a worthwhile change?
> Of course this is a not a simple one-line change, so
> it would take a while (and some intermediate steps)
> to implement fully.
> -- 
>    --Per Bothner
> per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-01  6:20   ` Per Bothner
@ 2013-07-05  1:13     ` Matthieu Vachon
  0 siblings, 0 replies; 11+ messages in thread
From: Matthieu Vachon @ 2013-07-05  1:13 UTC (permalink / raw)
  To: Per Bothner; +Cc: kawa

On Mon, Jul 1, 2013 at 2:20 AM, Per Bothner <per@bothner.com> wrote:
> On 06/30/2013 08:09 PM, Matthieu Vachon wrote:
>>
>> On Sat, Jun 29, 2013 at 2:47 AM, Per Bothner <per@bothner.com> wrote:
>>>
>>> A linked-list may be
>>> terminated by either '() (i.e. LList.Empty) or Java null.  Lists
>>> constructed using the Scheme reader or the 'list' function would
>>> by terminated by LList.Empty as now.
>>
>>
>> I'm less sure about this change, how would this work. If I understand
>> correctly, writing `(1 2 3)` or `(list 1 2 3)` would have a '() as the
>> last
>> element.
>
>
> Not the "last element" - the "tail".  The last element is 3.  The
> last (i.e. 3rd) cons cell (pair) has 3 as the value of its car and '()
> (i.e.  LList.Empty) as the value of its cdr.
>
>
>> For the null part, I would I create such list. Something like
>> this `(list 1 2 3 #!null)` would not end with a '() but rather a #!null ?
>
>
> You're confusing car and cdr.  `(1 2 3 #!null)` is a 4-element list,
> whose last (i.e. 4th) cons cell (pair) has #!null as the value of its
> car and '() (i.e.  LList.Empty) as the value of its cdr.
>
> However, `(1 2 3 . #!null)` (note the dot) is a 3-element list
> last (i.e. 3rd) cons cell (pair) has 3 as the value of its car and #!null
> as the value of its cdr.
>
> `(1 2 3 . ())` is in all respects equivalent to `(1 2 3)`.  However,
> `(1 2 3 . ())` and `(1 2 3 . #!null)` are the same *when viewed as
> a list*, however they would not be equal?  They're not equal? because
> as explained in the "Equality" section here:
> http://www.gnu.org/software/guile/manual/html_node/Nil.html
>
> However, most functions that work on lists, such as length and map,
> would treat `(1 2 3 . ())` and `(1 2 3 . #!null)` the same.
>

You are right, I confused two different things. Now I understand more
the feature.
Since a list would still ends with an empty list, I don't see any
problem with this
feature anymore.

>
>> This seems reasonable. But I'm unsure of all the implications
>> for this change on my existing code base. Do you think this change
>> would be fully backward compatible?
>
>
> No, it will not.  Most obviously:
>   (if #!null 't 'f)
> would return 'f where it currently returns 't.
> Even if you don't use #!null explicitly, it will show up
> if you call a Java method that returns null.
>

Yes, that one was obvious, I was thinking more of the other change,
the one with the
list. But now that I understand more, I don't think there will be any
BC with this new
feature.

> --
>         --Per Bothner
> per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-06-29  6:47 proposed changes to handling of false and end-of-list Per Bothner
  2013-07-01  3:09 ` Matthieu Vachon
  2013-07-01 11:17 ` Alex Mitchell
@ 2013-07-05 18:44 ` Jamison Hope
  2013-07-05 20:50   ` Charles Turner
  2013-07-19  0:09   ` Per Bothner
  2015-02-21  4:04 ` Per Bothner
  3 siblings, 2 replies; 11+ messages in thread
From: Jamison Hope @ 2013-07-05 18:44 UTC (permalink / raw)
  To: kawa

Hi Per,

On Jun 29, 2013, at 2:47 AM, Per Bothner <per@bothner.com> wrote:

> A discussion on the kawa-commonlisp-dev list has suggested
> we might want to consider some changes in Kawa's handling
> of null, false, and the empty list.
> 
> The high-level summary:
> * Java null (#!null in Scheme syntax) would be considered false
> (rather than true).  I.e. in an expression (if c e1 e2) if c
> evaluates to Java null *or* a java.lang.Boolean such that
> c.booleanValue()==false, then e2 is evaluated; otherwise e1 is evaluated.

That would be welcome.  I routinely have code that looks like
(if (not (eq? #!null o)) ...), which would now be written as
(if o ...).  Since in Scheme #f is often used as the default
value where Java uses #!null, this change makes a lot of sense.

> * The function null? would return true both of the empty list '()
> (the value of LList.Empty) and Java null.  A linked-list may be
> terminated by either '() (i.e. LList.Empty) or Java null.  Lists
> constructed using the Scheme reader or the 'list' function would
> by terminated by LList.Empty as now.

How will #!null-terminated lists be printed?

I presume that you mean the Scheme 'list' function here, and that the
similarly-named Common Lisp 'LIST' function would be terminated by
nil/#!null/#nil.  So, a list created in Lisp code would not
(necessarily) have exact representational equivalence with one created
in Scheme code.

But Scheme would be able to iterate over Lisp lists correctly, as long
as it uses null? to check for the end of list (which is the idiomatic
thing to do anyway):

(define (mylength lst)
  (if (null? lst)
      0
      (+ 1 (mylength (cdr lst)))))

This is a good thing.

> * Common Lisp, Emacs Lisp, and similar languages (which we will
> call "Lisp") would represent nil using Java null (rather than as
> now LList.Empty).  Lisp would recognize the same values as "true"
> as Scheme does; likewise for end-of-list.

Would LList.Empty evaluate as true or false in Lisp code?  Methinks it
would need to be false, if we want to be able to pass Scheme lists to
idiomatic Lisp:

(defun mylength (list)
  (if list
      (1+ (mylength (rest list)))
      0))

> * This change would have some negative performance impact, but
> hopefully not much.
> 
> The biggest motivation for this change is improved compatibility
> with Lisp.  This is similar to the solution adopted by Guile:
> http://www.gnu.org/software/guile/manual/html_node/Nil.html
> (We might consider implementing #nil as a synonym for #!null,
> for Guile compatibility.)
> 
> However, even if you don't care about Lisp, it probably seems
> reasonable to consider Java null "false" rather than "true".
> Allowing #!null as the end of a list may be less valuable,
> but it does seem preferable for (null? #!null) to be true.
> 
> There are also some anomalies it would be nice to fix.
> Java (and Kawa) allow you to create fresh java.lang.Boolean
> objects:
>    (define-constant b1 (java.lang.Boolean #f))
> However, this object is considered true, not false:
>    (if b1 1 0) ==> 1 ; not (as one might expect) 0
> 
> Currently (if c e1 e2) is compiled to the equivalent of:
>    (c != Boolean.FALSE ? e1 : e2)
> The proposal would change this to:
>    (isTrue(c) ? e1 : e2)
> where isTrue is this library method:
> 
> public static final boolean isTrue(Object value) {
>   return value != null
>      && (! (value instanceof Boolean)
>          || ((Boolean) value).booleanValue()));
> }
> 
> This is obviously slower; however, it is not as bad as it seems.
> If the compiler determines that the type of the expression c
> is 'boolean', then the generated code is the same as Java:
>    (c ? e1 : e2)
> The Kawa type 'boolean' is the same as Java - i.e. a primitive
> (non-object) type.
> 
> For example:
>   (if (> x y) e1 e2)
> compiles to:
>   (NumberCompare.$Gr(x, y) ? e1 : e2)
> because NumberCompare.$Gr has return-type boolean.
> The same is true of other predicates, comparisons,
> and types tests.  (Or at least it is supposed to be -
> bugs may exist.)

I would also propose the other obvious optimization, that if the
compiler can determine that the type of the expression c is
any-class-other-than-Boolean, then the generated code can just
be ((c != null) ? e1 : e2).

A similar optimization would make sense for null? - if you know
that the argument is of a non-pair type, then you can just check
for #!null and not even try LList.Empty equality.

> Finally, you can always optimize by hand.  If you want
> the old behavior (and generated code) you can always do:
>   (if (not (eq? c #f)) e1 e2)
> Since both 'not' and 'eq?' are optimized this generates
> the same code as (if c e1 e2) now does.
> 
> Comments?  Does this seem like a worthwhile change?
> Of course this is a not a simple one-line change, so
> it would take a while (and some intermediate steps)
> to implement fully.

Makes sense to me.  Common Lisp's nil is a bit of a mess, in that it
corresponds at different times to '(), #f, #!null, and #!void, but
it's something that Kawa needs to address.  Of those four values,
Scheme dictates that '() be true and #f be false, so we can't touch
those -- but #!null and #!void are both outside of the purview of
standard Scheme, so in principle they could go either way.

I would probably go one further and argue that not only should #!null
be false, so should #!void.

-J

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-05 18:44 ` Jamison Hope
@ 2013-07-05 20:50   ` Charles Turner
  2013-07-19  0:09   ` Per Bothner
  1 sibling, 0 replies; 11+ messages in thread
From: Charles Turner @ 2013-07-05 20:50 UTC (permalink / raw)
  To: Jamison Hope; +Cc: Kawa mailing list

On 5 July 2013 19:43, Jamison Hope <jrh@theptrgroup.com> wrote:
> I would probably go one further and argue that not only should #!null
> be false, so should #!void.

Absolutely. I made a case for that on the commonlisp mailing list as
well, it would simplify the interaction between Scheme and CL for
sure.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-05 18:44 ` Jamison Hope
  2013-07-05 20:50   ` Charles Turner
@ 2013-07-19  0:09   ` Per Bothner
  2013-07-19  0:36     ` Jamison Hope
  1 sibling, 1 reply; 11+ messages in thread
From: Per Bothner @ 2013-07-19  0:09 UTC (permalink / raw)
  To: Jamison Hope; +Cc: kawa

On 07/05/2013 11:43 AM, Jamison Hope wrote:
> How will #!null-terminated lists be printed?

I think printing them the same way as LList.Empty-terminated lists:
'(3 4 5 . #!null) print as "(3 4 5)".

> I presume that you mean the Scheme 'list' function here
> [i.e. would construct an LList.Empty-terminated list)], and that the
> similarly-named Common Lisp 'LIST' function would be terminated by
> nil/#!null/#nil.  So, a list created in Lisp code would not
> (necessarily) have exact representational equivalence with one created
> in Scheme code.

Right.  Furthermore, note there is an awkwardness with equal?:
Should: (equal? '(3 4 5) '(3 4 5 . #!null)) ?
I think the answer has to be #f, because (equal? '() #!null) --> #f.

> But Scheme would be able to iterate over Lisp lists correctly, as long
> as it uses null? to check for the end of list (which is the idiomatic
> thing to do anyway):
>
> (define (mylength lst)
>    (if (null? lst)
>        0
>        (+ 1 (mylength (cdr lst)))))

Right.

> Would LList.Empty evaluate as true or false in Lisp code?  Methinks it
> would need to be false, if we want to be able to pass Scheme lists to
> idiomatic Lisp:
>
> (defun mylength (list)
>    (if list
>        (1+ (mylength (rest list)))
>        0))

Probably.  Guile ELisp treats '(), #f, and nil as all equal (though not eq).
So I assume it treats them all as false.

> I would also propose the other obvious optimization, that if the
> compiler can determine that the type of the expression c is
> any-class-other-than-Boolean, then the generated code can just
> be ((c != null) ? e1 : e2).

That seems a worthwhile optimization.

> I would probably go one further and argue that not only should #!null
> be false, so should #!void.

I'm reluctant for a couple of reasons.  Mainly, Kawa treats #!void
as equivalent (though not necessarily eq?) to the result of (values).
I.e. #!void is zero values.  It is not clear that zero values
should be false.  I think a zero-length tuple is true.

There is also the pragmatic issue in Kawa in that multiple values
are represented using the gnu.mapping.Values, so you have to check
Values#isEmpty().  Also, Values instances may sometimes be mutable.
For example there is the ValueStack class, which extends Values.
This is admittedly not very clean, but I think that is an
issue for another day.
-- 
	--Per Bothner
per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-19  0:09   ` Per Bothner
@ 2013-07-19  0:36     ` Jamison Hope
  2013-07-19  1:16       ` Jamison Hope
  0 siblings, 1 reply; 11+ messages in thread
From: Jamison Hope @ 2013-07-19  0:36 UTC (permalink / raw)
  To: kawa@sourceware.org list

On Jul 18, 2013, at 8:09 PM, Per Bothner <per@bothner.com> wrote:

>> I would probably go one further and argue that not only should #!null
>> be false, so should #!void.
> 
> I'm reluctant for a couple of reasons.  Mainly, Kawa treats #!void
> as equivalent (though not necessarily eq?) to the result of (values).
> I.e. #!void is zero values.  It is not clear that zero values
> should be false.  I think a zero-length tuple is true.

#!void == (values) was precisely my reasoning.  This whole thing
started with a desire to be more compatible with Lisp, right?

In CL if a continuation expects more values than are provided,
then the extra values are filled in with NIL:

> * (multiple-value-bind (a b) (values 1) (list a b))
> 
> (1 NIL)


So in particular, when (values) is used in a context expecting
one value, it evaluates to false:

> * (if (values) 'true 'false)
> 
> FALSE

(Those were evaluated in SBCL.)

--
Jamison Hope
The PTR Group
www.theptrgroup.com



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-07-19  0:36     ` Jamison Hope
@ 2013-07-19  1:16       ` Jamison Hope
  0 siblings, 0 replies; 11+ messages in thread
From: Jamison Hope @ 2013-07-19  1:16 UTC (permalink / raw)
  To: kawa@sourceware.org list

On Jul 18, 2013, at 8:36 PM, I wrote:

>> * (if (values) 'true 'false)
>> 
>> FALSE

Also, R6RS and the R7RS WG1 draft say we're free to release the nasal
demons for (values) in a 1-value context:

"The effect of passing no value or more than one value to
continuations that were not created by call-with-values is
unspecified."

(N.B. Guile and MIT Scheme treat it as true, Racket treats it as an
error.  I haven't tested any other implementations.)


[But there's still the craziness that NIL in Common Lisp is not only
() and #f and #!null and #!void, it's also a _symbol_, namely 'NIL.]


--
Jamison Hope
The PTR Group
www.theptrgroup.com



^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: proposed changes to handling of false and end-of-list
  2013-06-29  6:47 proposed changes to handling of false and end-of-list Per Bothner
                   ` (2 preceding siblings ...)
  2013-07-05 18:44 ` Jamison Hope
@ 2015-02-21  4:04 ` Per Bothner
  3 siblings, 0 replies; 11+ messages in thread
From: Per Bothner @ 2015-02-21  4:04 UTC (permalink / raw)
  To: kawa

I checked in the following change (proposed and discussed June-July 2013):

* Java null (#!null in Scheme syntax) would be considered false
(rather than true).  I.e. in an expression (if c e1 e2) if c
evaluates to Java null *or* a java.lang.Boolean such that
c.booleanValue()==false, then e2 is evaluated; otherwise e1 is evaluated.

Let now know if you run into problems or anomalies.
-- 
	--Per Bothner
per@bothner.com   http://per.bothner.com/

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-02-21  4:04 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-06-29  6:47 proposed changes to handling of false and end-of-list Per Bothner
2013-07-01  3:09 ` Matthieu Vachon
2013-07-01  6:20   ` Per Bothner
2013-07-05  1:13     ` Matthieu Vachon
2013-07-01 11:17 ` Alex Mitchell
2013-07-05 18:44 ` Jamison Hope
2013-07-05 20:50   ` Charles Turner
2013-07-19  0:09   ` Per Bothner
2013-07-19  0:36     ` Jamison Hope
2013-07-19  1:16       ` Jamison Hope
2015-02-21  4:04 ` Per Bothner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).