Just An Application

November 17, 2016

Java To Swift: Much Ado About Null

Filed under: Java, Java2Swift, Swift — Tags: , , — Simon Lewis @ 12:09 pm

The Java literal null is the only value of the null type.

The null type is anonymous, that is to say, there is no way to refer to it in a Java program so it is not possible to declare anything to be of type null.

But not to worry, although nothing can be declared to be of type null, any field, local variable or parameter which is a reference, that is to say, whose type is declared to be an array, class or interface, can have the value null.

The following code shows the things that can be done with a reference in Java

    package xper.nullexample;

    public class Cod 
    {
	public void swim()
	{
	    // TODO
	}
	
	public int numberOfFins;
    }

    public class XperNullExampleMain 
    {
	public static void main(String[] args)
	{
	    test((Cod)null);
	}
	
	private static void test(Cod fish)
	{
	    if (fish != null)
	    {
	        System.out.println("fish is not null");
	    }
	    else
	    {
		System.out.println("fish is null");
	    }
	    if (fish == null)
	    {
		System.out.println("fish is still null");
	    }
	    else
	    {
		System.out.println("fish is not null !");
	    }
	    if (fish instanceof Cod)
	    {
		System.out.println("fish is an instanceof Cod");
	    }
	    else
	    {
		System.out.println("fish is not an instanceof Cod");
	    }
		
	    System.out.println(fish + " concatenated with string");

	    try
	    {
		System.out.format("fish has %d fins\n", fish.numberOfFins);
	    }
	    catch (NullPointerException npe)
	    {
		System.out.println("Caught NPE when accessing numberOfFins field");
	    }
	    try
	    {
		fish.swim();
		System.out.println("fish is swimming");
	    }
	    catch (NullPointerException npe)
	    {
		System.out.println("Caught NPE when invoking swim method");
	    }
        }
    }	

They are

  • field access
  • method invocation
  • string concatenation
  • casting
  • comparison using == and !=
  • type checking using instanceof

As the example also shows, if you run it, all but two of these work even when the reference is null

The two that do not work are

  • field access

and

  • method invocation

Attempting to use a reference with the value null to access a field or invoke a method or will result in a NullPointerException (NPE).

There is no null in Swift.

The nearest thing is nil but in some respects nil is the anti-null.

In Java the field declaration

    private java.lang.Character c;

means that c can be a reference to an object of type java.lang.Character or null.

In Swift the declaration

    private c : java_lang_Character

means that c cannot be nil.

So whereas in Java the default is that c can be null, in Swift the default is that c cannot be nil.

In Swift an ‘equivalent’ to the Java declaration would be

    private c : java_lang_Character?

The property c must be explicitly declared optional.

To invoke a method on c in Java we can simply do

    c.compareTo(d)

and if c has the value null we get an NPE.

There are two ways of doing the same thing in Swift.

Either

    c?.compareTo(d)

or

    c!.compareTo(d)

The first is optional-chaining, the second is forced unwrapping.

Optional chaining results in the value nil if something in the chain is nil or an optional value of the same type as the last thing in the chain.

Optional chaining works by stopping the first time it encounters nil.

If c is nil in the first example then nothing happens. No attempt is made to invoke the compareTo method.

Forced unwrapping takes a more robust approach.

If c is not nil then the result is a value of type java_lang_Character. If c is nil then the program goes bang.

To preserve the runtime behaviour of Java in Swift when using nil as null is obviously going to require some additional effort.

This is the definition of the compareTo method for java.lang.Character

    public int compareTo(Character anotherCharacter) {
        return compare(this.value, anotherCharacter.value);
    }

The value field is defined like this

    private final char value;

and the compare method is defined like this

    public static int compare(char x, char y) {
        return x - y;
    }

Since anotherCharacter can legitimately be null in Java, the equivalent in Swift would have to be something like

    public func compareTo(anotherCharacter:java_lang_Character?)
    {
        return java_lang_Character.compare(self.value, anotherCharacter?.value)
    }

Assuming the compare method is defined something like this in Swift

    public func compare(x:JavaChar, y:JavaChar) -> Int
    {
        return x - y
    }

and the field value like this

 private let value : JavaChar

then compareTo won’t compile.

The result of the optional chaining on anotherChar is going to be an optional JavaChar

    JavaChar?

To make it compile it is necessary to unwrap anotherCharacter.

One way to do this is like so

    public func compareTo(anotherCharacter:java_lang_Character?)
    {
        return java_lang_Character.compare(self.value, anotherCharacter!.value)
    }

This now compiles but if anotherCharacter is nil then the program stops abruptly.

To preserve the Java runtime semantics it should throw a NullPointerException.

One way to achieve this by defining a ‘magic’ function which checks whether is something is nil, throws an NPE if it is, or returns the unwrapped value if it is not.

The signature needs to be something like this.

    func JRTEnsureNotNull(reference:R?) throws -> R

Assuming such a thing existed it would be possible to define the compareTo ‘method’ like this

    func compareTo(anotherCharacter:java_lang_Character?) throws
    {
        return java_lang_Character.compare(self.value, try JRTEnsureNotNull(anotherCharacter).value)
    }

Because the function JRTEnsureNotNull is declared to throw the call to it must be prefaced by try and since there is no attempt to catch whatever is thrown the ‘method’ itself must be declared to throw as well.

Clearly there is an overhead associated with doing this but the same overhead must exist in some form in the Java runtime since it can detect when a reference is null and throw a NullPointerException if necessary.

In addition, it should be possible in some circumstances to reduce this overhead during the conversion from Java to Swift by identifying when a reference has successfully been dereferenced and using it directly on subsequent occasions rather than checking it each time.

Advertisements

November 16, 2016

Java To Swift: Packages, Imports And Access Control

Filed under: Java, Java2Swift, Swift — Tags: , , — Simon Lewis @ 11:30 am

Packages

Java has packages and is in the process of acquiring modules.

Swift has modules.

It is tempting to map Java packages on to Swift modules but, amongst other things, that would leave the vexed of question of what to map Java modules on to when they eventually arrive.

Instead I’m going to go with a flat namespace for now.

Everything gets named explicitly using the package prefix, for example,

   java.lang.Boolean

becomes

   java_lang_Boolean

Imports

Swift has an import declaration which is pretty much to Swift modules as the Java import declaration is to Java packages but since I’m not using Swift modules to represent Java packages I don’t really have a use for it.

Rather more useful in this context is the typealias declaration, for example, declaring

   public typealias Object = java_lang_Object

means that I can write

    public final java_lang_Boolean: Object ... 

Not brilliant but its a start.

Given its uniquity being able to declare

   public typealias String = java_lang_String

would be handy but it collides with the Swift’s String so it can’t be done.

Access Control

Java has

  • public
  • protected
  • private

and the access control level with no name, aka package

Now the dust has settled Swift has

  • open
  • public
  • internal
  • fileprivate
  • private

Of these, the first three are module-relative so strictly speaking they are not relevant but public is at least familiar so I’ll use that.

The fileprivate level doesn’t correspond to anything in Java but may be useful for transformation generated artifacts.

Swift’s private which does correspond to Java’s private so I’ll use that as well.

That leaves Java’s protected and package without an equivalent so they will just have to be Swift internal for now.

November 13, 2016

Java To Swift: Thirty Three And A Third Things You Might Like To Know

Filed under: Java, Java2Swift, Swift — Tags: , , — Simon Lewis @ 8:26 pm

What ?

Its not my fault. Its an epidemic. Everybody’s doing it.

Consider yourselves lucky I didn’t go with

Java To Swift: You’ll Be Astonished By What Happens Next !

Anyway Java has classes and Swift has classes, so transforming Java source into Swift source should be trivial.

Probably an afternoon’s work, if that.

Well, maybe, but probably not.

Here is the result of running my first attempt at a tool for turning Java into Swift on Boolean.java.

import Foundation


public final class java_lang_Boolean: java_lang_Object
{
    public init(_ value:JavaBoolean)
    {
        self.value = value
        
    }
    
    public convenience init(_ s:java_lang_String?)
    {
        self.init(java_lang_Boolean.parseBoolean(s))
        
    }
    
    public static func parseBoolean(s:java_lang_String?) -> JavaBoolean
    {
        return s != nil && s!.equalsIgnoreCase(javaStringConstant("true"))
    }
    
    public func booleanValue() -> JavaBoolean
    {
        return value
    }
    
    public static func valueOf(b:JavaBoolean) -> java_lang_Boolean
    {
        return b ? TRUE : FALSE
    }
    
    public static func valueOf(s:java_lang_String?) -> java_lang_Boolean
    {
        return parseBoolean(s) ? TRUE : FALSE
    }
    
    public static func toString(b:JavaBoolean) -> java_lang_String
    {
        return b ? javaStringConstant("true") : javaStringConstant("false")
    }
    
    public func toString() -> java_lang_String
    {
        return value ? javaStringConstant("true") : javaStringConstant("false")
    }
    
    public func hashCode() -> JavaInt
    {
        return java_lang_Boolean.hashCode(value)
    }
    
    public static func hashCode(value:JavaBoolean) -> JavaInt
    {
        return value ? JavaInt(1231) : JavaInt(1237)
    }
    
    public func equals(obj:java_lang_Object?) -> JavaBoolean
    {
        if obj is java_lang_Boolean
        {
            return value == (obj as! java_lang_Boolean).booleanValue()
        }
        return false
    }
    
    public static func getBoolean(name:java_lang_String?) -> JavaBoolean
    {
        var result : JavaBoolean = false
        do
        {
            result = parseBoolean(java_lang_System.getProperty(name))
        }
        catch let e where e is java_lang_IllegalArgumentException || e is java_lang_NullPointerException
        {
        }
        return result
    }
    
    public func compareTo(b:java_lang_Boolean?) -> JavaInt
    {
        return java_lang_Boolean.compare(self.value, b!.value)
    }
    
    public static func compare(x:JavaBoolean, _ y:JavaBoolean) -> JavaInt
    {
        return x == y ? JavaInt(0) : x ? JavaInt(1) : JavaInt(-1)
    }
    
    public static func logicalAnd(a:JavaBoolean, _ b:JavaBoolean) -> JavaBoolean
    {
        return a && b
    }
    
    public static func logicalOr(a:JavaBoolean, _ b:JavaBoolean) -> JavaBoolean
    {
        return a || b
    }
    
    public static func logicalXor(a:JavaBoolean, _ b:JavaBoolean) -> JavaBoolean
    {
        return a ^ b
    }
    
    public static let TRUE : java_lang_Boolean = java_lang_Boolean( true)
    
    public static let FALSE : java_lang_Boolean = java_lang_Boolean(false)
    
    private let value : JavaBoolean
    
    private static let serialVersionUID : JavaLong = JavaLong(-3665804199014368530)
    
}

Pretty convincing don’t you think ?

It even compiles with a bit of judicious pushing and shoving.

But looks can be deceptive.

The class java.lang.Boolean isn’t a particularly Java’ry class as Java classes go so it is not really a very good test.

There are a number of ways in which Java and Swift are not at all alike, so it looks as though it is probably going to be more like two afternoon’s work.

Create a free website or blog at WordPress.com.

%d bloggers like this: