This is the mail archive of the kawa@sourceware.org mailing list for the Kawa project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: proposed changes to handling of false and end-of-list


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/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]