The Artima Developer Community
Sponsored Link

Weblogs Forum
CEDSimply - Nil Pointer Safe Assignment

11 replies on 1 page. Most recent reply: May 5, 2006 1:53 PM by piglet

Welcome Guest
  Sign In

Go back to the topic listing  Back to Topic List Click to reply to this topic  Reply to this Topic Click to search messages in this forum  Search Forum Click for a threaded view of the topic  Threaded View   
Previous Topic   Next Topic
Flat View: This topic has 11 replies on 1 page
Andy Dent

Posts: 165
Nickname: andydent
Registered: Nov, 2005

CEDSimply - Nil Pointer Safe Assignment (View in Weblogs)
Posted: May 3, 2006 11:21 AM
Reply to this message Reply
Summary
Introducing the CEDSimply project and some thoughts on a clean way to assign pointers using safe multiple dereferences of possibly nil pointers: CurrentLogger = gRS.runner.UI.LogTo unless nil
Advertisement

I often see code like (slightly ugly contrived example):

if (gRS.runner!=0 && gRS.runner.UI!=0 && gRS.runner.UI.LogTo!=0)
  CurrentLogger = gRS.runner.UI.LogTo

or, taking advantage of the c treatment of nil pointers as false:

if (gRS.runner && gRS.runner.UI && gRS.runner.UI.LogTo)
  CurrentLogger = gRS.runner.UI.LogTo

In an abstract syntax form, this can be expressed as:

(if-no-pointers-nil (CurrentLogger = gRS.runner.UI.LogTo) )

This is the kind of assumption, like having zeroed memory by default, that could be built into a language. Indeed, it might be nice to only be allowed to assign a nil pointer explicitly:

CurrentLogger = gRS.runner.UI.LogTo

or:

CurrentLogger = Nil

However, I keep being really really uncomfortable when a language does things that are going to subvert the instincts of a good c++ or Java programmer.

I find myself rather liking the simple form:

CurrentLogger = gRS.runner.UI.LogTo unless nil
  1. it retains the original assignment statement in its normal location, read first.
  2. the added nil protection is expressed succintly so would not be too noisy if repeated often.

I miss the Object Pascal with statement, dreadfully so when I first moved to C++.

Trying to write a nil-safe with leads to:

with gRS.runner.UI unless nil:
  CurrentLogger = LogTo

Which doesn't really work for me:

  1. the with statement no longer ends with the expression being dereferenced.
  2. it doesn't say the same thing, we don't have a check of LogTo being nil, although sometimes we might not care.

I'm not sure there's a readable alternative, maybe some of these meet your fancy:

with unless nil gRS.runner.UI:
  CurrentLogger = LogTo


with nil-safe gRS.runner.UI:
  CurrentLogger = LogTo


with guaranteed gRS.runner.UI:
  CurrentLogger = LogTo


safely with gRS.runner.UI:
  CurrentLogger = LogTo

Safer Code Through Clarity

I will probably blog again on this topic because it's dear to my heart and deserves more detail.

People avoid errors of tired misinterpretation when code is easy to read.

As you can see from the above examples, this means trying things in nit-picking detail.

Of CEDSimply and Overweening Ambition

I came to Christopher Diggins' blog and Heron project because for a few years I've been dissatisfied with existing programming languages and how well they allow me and many others to communicate to a computer and other programmers.

CEDSimply is currently a theoretical project in establishing a clear vision for a language, it may end up as:

  • a set of idioms for using an existing programming language,
  • a DSL (Domain-Specific Language) or
  • as an interpreter and c++ Code Generator.

I have realised it might be a tiny bit ambitious to aim at developing the entire language and environment alone so it is going to have to be an open source project. Maybe I'll at least establish a BDFL-like reputation, rather than getting rich :-)

I've spent a lot of time in the Macintosh world working in the code generation space: writing code generators that target c++ frameworks such as Think Class Library (for Prototyper) and enhancing AppMaker from Bowers Development.

From publishing a Windows code generator and PowerPlant framework portability kit for AppMaker, I've now moved on to acquiring the product (Spec Bowers has retired to run cabins).

AppMaker has a JSP-like template environment for code generation, using its own OO language. This, Python and years of trying to write highly-usable C++ API's (OOFILE) were the seeds of my thinking in CEDSimply, watered with dabblings in Forth and Scheme.

Awful Puns

CEDSimply is pronounced "said simply"

yes it's a kind of pun on Smalltalk

it's also a pun/jibe at another famous old language - you can't say it clearly with a lisp.

CED started out as an acronym for Connecting Events and Data, then it became Contexts, Events and Data

or maybe it now means many other things, some of which start with Community.

Anyway, I think it's a great pun!


Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 3, 2006 10:44 PM
Reply to this message Reply
You could write:
try {
  currentLogger = gRS.runner.UI.LogTo;
} catch ( NullPointerException notUsed ) {
  // ignore or assign a default
}

However I would probably write class UI so that LogTo was private and get and set methods are used instead of field access. Then when a UI was created or setLogTo is called I can ensure that LogTo is set to a none-null-default value if null is given as the argument.

As an aside I have never actually written code that has any significant null testing in it. Probably because I tend to use get and set methods rather than field access.

PS I also work for CSIRO.

Andy Dent

Posts: 165
Nickname: andydent
Registered: Nov, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 4, 2006 12:30 AM
Reply to this message Reply
Howard Lovatt writes
> You could write:
>
> try {
>   currentLogger = gRS.runner.UI.LogTo;
> } catch ( NullPointerException notUsed ) {
>   // ignore or assign a default
> }
> 


To check the final pointer value, the one you're copying, I think this would have to be:

try {
  if (gRS.runner.UI.LogTo != null)
    currentLogger = gRS.runner.UI.LogTo;
} catch ( NullPointerException notUsed ) {
  // ignore or assign a default
}



> However I would probably write class UI so
> that LogTo was private and get and set
> methods are used instead of field access.

In both REALbasic and C++ the above code could be using getter functions, not necessarily simple field access. You can't assume they are simple fields without more context.

REALbasic has for years allowed function invocation to drop empty parens and there are operator overloads to achieve similar in C++.

In the latest REALbasic you can also map properties with getter and setter functions.

> As an aside I have never actually written code that has
> any significant null testing in it. Probably
> because I tend to use get and set methods rather than
> field access.
Don't you write null checks inside some of those methods? :-)

I'm mostly a c++ programmer but I note that triggering null pointer exceptions is listed as the number one error Java programmers make: http://www.javacoffeebreak.com/articles/toptenerrors.html.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 4, 2006 12:58 AM
Reply to this message Reply
The points you make above are correct. Perhaps if I flesh the example out a bit that will help (to keep it short I will just do UI - the same process is applicable to the other classes).
class UI {
  private Logger logTo = Logger.default;
  void setLogTo( Logger logTo ) {
    this.logTo = logTo == null ? Logger.default : logTo;
  }
  ...
}

IE I am interpreting a null argument as use the default logger. You could change this to use the current logger - it depends on your application:
  void setLogTo( Logger logTo ) {
    if ( logTo != null ) this.logTo = logTo;
  }

Or even throw an exception:
  void setLogTo( Logger logTo ) {
    if ( logTo != null ) throw new IllegalArgumentException( "Argument logTo is null" );
    this.logTo = logTo;
  }

The point is that by using access methods the problem goes away. You don't need to test at the point of use that everything isn't null because it can't be null. The advantage of this technique are that:

1. The checking and resulting actions are well contained and documented in the classes that are resposible for the feature and not left to the user to deal with.

2. Generally there is only one point of assignment to a private field, the set method. Whereas the user code contains many reads using the getter and therefore encapsulating the null handelling saves a lot of effort.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 4, 2006 6:36 AM
Reply to this message Reply
Just a thought, you appropriate an XPath construct:

exists (gRS.runner.UI)

The reason I thought of this is that I have had to use the
if (great-grandparent != null) {
   if (grandparent != null) {
      if (parent != null) {
         if (child != null)

'pattern' mostly when using JAXB generated classes (blech!)

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 4, 2006 6:39 AM
Reply to this message Reply
Also, I'm not sure about the with construct. I find it a little confusing. Also, the scoping rules of such a construct are not obvious to me. I guess I would assume that the 'with' context would be narrower than the local context.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 4, 2006 7:22 AM
Reply to this message Reply
> Also, I'm not sure about the with construct. I find it a
> little confusing. Also, the scoping rules of such a
> construct are not obvious to me. I guess I would assume
> that the 'with' context would be narrower than the local
> context.

That's not really clear. I mean that the with scope hides the names in the surrounding scope in the case of collisions.

Howard Lovatt

Posts: 321
Nickname: hlovatt
Registered: Mar, 2003

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 5, 2006 12:22 AM
Reply to this message Reply
You can code an exists if you wish:
package nulltesting;
 
import static java.lang.System.*;
 
public class Test {
    static class Wrapper { // the thing that has a field that could be null
        final String wrapped;
        Wrapper( final String value ) { wrapped = value; }
    }
    static abstract class Thunk< T > { // common class used many times
        T eval( final T defVal ) {
            try {
                final T temp = f();
                return temp == null ? defVal : temp;
            } catch ( NullPointerException e ) {
                return defVal;
            }
        }
        abstract T f();
    }
    static final Wrapper defVal = new Wrapper( "No" ); // default for wrappers that don't exist
    static String exists( final Wrapper wrapper ) { // a wrapper exists method, other overloaded methods for other wrapper types
        return new Thunk< String >() {
            public String f() { return wrapper.wrapped; }
        }.eval( defVal.wrapped );
    }
    public static void main( final String[] notUsed) {
        final Wrapper ok = new Wrapper( "Yes" );
        final Wrapper null1 = new Wrapper( null );
        final Wrapper null2 = null;
        out.println( "ok exists? " +  exists( ok ) ); // prints Yes
        out.println( "null1 exists? " +  exists( null1 ) ); // prints No
        out.println( "null2 exists? " +  exists( null2 ) ); // prints No
    }
}

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 5, 2006 6:15 AM
Reply to this message Reply
> You can code an exists if you wish:

That only works for classes I write, correct? I could create a solution using reflection but I agree with the author that a language level syntax for this could be useful, albeit in limited circumstances.

piglet

Posts: 63
Nickname: piglet
Registered: Dec, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 5, 2006 8:40 AM
Reply to this message Reply
I agree with some of the comments. I think the usefulness of the unless construct is doubtful. It avoids a NullPointerException, yes, but in many cases you would have to code something by hand anyway in the case of a null argument. I have found that in many cases, it is possible to deal with null pointers in a general way. Some idioms that I have found useful:

- Coding getters to never return null, as Howard suggested. A frequent usage is in struts with objects (usually Strings or Lists) that are bound to JSP pages via bean:define tag. If it is null, the page just refuses to display with a mysterious error message. No problem if the getter method is coded appropriately.

- In many cases, you want to compare a String but it may be null. I have seen a lot of code like

  
if (myString!= null) {
if (myString.equals("something"){
...
} else if (myString.equals("that"){
...
} else "){
...
}
}


This is crazy. I just write
myString = notNull(myString); , where notNull() returns myString==null? "": myString .

- It is often worthwile to rewrite standard methods in order to accept an object that can be null. E.g.
boolean equals( Object o1, Object o2)
instead of o1.equals(o2) saves you a lot of null checks.

When coding to JDBC, you often need close statements in finally clauses but you can't be sure whether the connection is initialized at all. Instead of writing endless null checks thousands of time in the code, use a generic close() method:

 
protected static final void closeDBResource(Object resource) {
if (resource==null)
return;
try {
if (resource instanceof ResultSet) {
((ResultSet) resource).close();
} else if (resource instanceof Statement) {
((Statement) resource).close();
} else if (resource instanceof Connection) {
((Connection) resource).close();
} else {
throw new IllegalArgumentException("Invalid resource class: " + resource.getClass().getName());
}
}
catch (SQLException e) {
staticLog.info( "Exception in closeDBResource(): " + e);
}
}


A further benefit of this approach is that the exception handling is also encapsulated. In this case, it is appropriate to swallow the exception, otherwise you'll have to catch it in the finally handler which is simply awkward.

I use analogous methods for rollback (exceptions are swallowed) and commit (exceptions are propagated) so that I can write very clean code without ever having to check for null pointers.

James Watson

Posts: 2024
Nickname: watson
Registered: Sep, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 5, 2006 9:18 AM
Reply to this message Reply
> I agree with some of the comments. I think the usefulness
> of the unless construct is doubtful. It avoids a
> NullPointerException, yes, but in many cases you would
> have to code something by hand anyway in the case of a
> null argument. I have found that in many cases, it is
> possible to deal with null pointers in a general way. Some
> idioms that I have found useful:
>
> - Coding getters to never return null, as Howard
> suggested. A frequent usage is in struts with objects
> (usually Strings or Lists) that are bound to JSP pages via
> bean:define tag. If it is null, the page just refuses to
> display with a mysterious error message. No problem if the
> getter method is coded appropriately.
>
> - In many cases, you want to compare a String but it may
> be null. I have seen a lot of code like
>
>
  
> if (myString!= null) {
> if (myString.equals("something"){
> ...
> } else if (myString.equals("that"){
> ...
> } else "){
> ...
> }
> }

>
> This is crazy. I just write

A simple solution that solves at least this specific example is:
if ("something".equals(myString){
  ...
} else if ("that".equals(myString){
  ...

piglet

Posts: 63
Nickname: piglet
Registered: Dec, 2005

Re: CEDSimply - Nil Pointer Safe Assignment Posted: May 5, 2006 1:53 PM
Reply to this message Reply
"A simple solution that solves at least this specific example..." That's right. However, I find this idiom a little less intuitive. Also, you can use the notNull() idiom to make existing code null-safe in just one line instead of ahving to check several statements.

I think the Java designers could have done us a great favour by providing a few simple null-safe methods in the standard library, like

 
static boolean String.isEmpty( String s) {
return s == null || s.length() == 0;
}
static boolean String.hasData( String s) {
return s != null && s.length() != 0;
}
static String String.notNull( String s) {
return s == null ? "" : s;
}

static boolean Object.equals( Object o1, Object o2) {
return (o1 == null && o2 == null) || o1.equals(o2);
}

static boolean Collection.isEmpty( Collection c) {
return c == null || c.isEmpty();
}

static List List.notNull( List l) {
// less generic, but most often needed
return l == null ? new ArrayList() : l;
}

Having to write such methods oneself is a minor hassle but I feel Java code quality would generally benefit from having them in the standard. I see a lot of code cluttered with null checks that could so easily be avoided.

Flat View: This topic has 11 replies on 1 page
Topic: CEDSimply - Nil Pointer Safe Assignment Previous Topic   Next Topic Topic: Adding wsgiref to the Python 2.5 Standard Library

Sponsored Links



Google
  Web Artima.com   

Copyright © 1996-2019 Artima, Inc. All Rights Reserved. - Privacy Policy - Terms of Use