Why I Don’t Care About Swift

Swift is a new programming language created by Apple for use on OS X and iOS devices. The programming world is agog. Apple’s fantastic new language apparently solves all their problems, as evidenced, they say, by the fact that some programmer ported Flappy Birds to it in a few hours.

I’ve been around long enough to see languages come and go. Each claimed to solve all the problems introduced by its predecessors, yet each was replaced by a language that solved all its problems. In some cases, the new language surpassed the success of the language it replaced (C++ and Java); in other cases, the new language faded into obscurity (Modula-2 and Ada).

Lately the motivations for new languages have been dubious. There is a big emphasis on making a language easy to learn and having it hide nasty issues related to memory management and type safety. One review of Swift I read stated, “Apple hopes to make the language more approachable, and hence encourage a new group of self-taught programmers”. While that sounds great, it means that those of us who have mastered our craft after 30 years or more of practice are saddled with the training wheels and water wings that are written into these languages for the noobs.

A classic example is the lack of unsigned integers in Java. The motivation for this was to simplify the language for “new and self-taught programmers” by avoiding errors caused by a lack of understanding of sign-extension. However, for those of us who showed up for class the day that sign extension was taught (that would be day two), we’re left with a language that unnecessarily limits the range of positive integers and requires us to actually have mastered sign extension in order to understand what is happening when we directly manipulate the bits in our integer variables.

Explicit vs. Implicit Typing

One of the simplifications Swift makes is that it infers the types of variables from the values assigned to them rather than requiring the programmer to explicitly type variables. If this was true “weak typing” like I’m familiar with in VBScript, it would be great (though it would come with its own set of problems). But all Swift does is infer the type of the variable from the first value you assign to it.

This actually introduces problems, because it’s not always possible to unequivocally determine the type of a literal value. So Swift gives you ways to force it to interpret a literal value as a given type. Rather than removing the necessity of the programmer understanding types, Swift thus requires “new and self-taught” programmers to have a mastery of types so that they can understand how Swift is working behind the scenes and make sure that their variables have the desired type.

Strings

Swift is said to improve string-handling over Objective-C (the current language used on OS X and iOS). There is certainly room for improvement there. When I first started programming in Objective-C, one of the first things I did was bring over my own C++ string class, as I found NSString to be overly complicated and muddled. Over the years I’ve gotten better with NSString.

I would argue, however, that some of the so-called “improvements” in Swift with respect to strings are differences without a distinction. So instead of this in Objective-C:

[NSString stringWithFormat:@"The value of num is %d", num]

you say this in Swift:

"The value of num is \(num)"

The Swift version is obviously more concise, but it is also less powerful. To add more complex format specifications to Swift you actually have to invoke the functionality of the underlying NSString class, which means the “new and self-taught” programmer, again, needs to understand the details of the implementation in order to do anything beyond the simplest strings.

One of the stated benefits of string handling in Swift is that “all strings are mutable”. One need not worry about whether the string is declared as an NSString (immutable) or NSMutableString (mutable). Well, you don’t have to worry unless you do have to worry — strings assigned to constants are immutable in Swift. So:

var myString1 = "Mutable string"
let myString2 = "Immutable string"
myString1 += myString2    // perfectly legal
myString2 += myString1    // compile-time error

Switch Statements

Swift eliminates the “fall-through” behavior of switch statements, which is said to eliminate bugs caused by omitting the break at the end of each case block. But, oops, sometimes the fall-through behavior is exactly what you want. So Swift adds the fallthrough keyword. It could be argued that Swift eliminates a line of code (the break) while giving the behavior one normally desires. But at the same time, it adds a keyword (fallthrough) that does the opposite. This requires “new and self-taught” programmers to have the same thorough understanding of switch behavior that Objective-C and C++ programmers do.

Single-line Blocks

The Swift compiler will warn you if you omit the braces in any block (such as after an if) and does not allow single-line blocks, thus avoiding this error:

if (x < 0)
    goto fail;
    goto fail;

The code above will always execute one or the other of the goto statements in Objective-C or C++. Even though the second goto is indented, it is not part of the if-block and will be executed if the condition is false.

Swift will warn you about the missing braces and force you to write this:

if (x < 0)
    {
    goto fail;
    }
goto fail;

Or, for those of you who don’t do your braces the right way, this…

if (x < 0) {
   goto fail;
}
goto fail;

This is fine, and hard to argue with. The supposition is that the programmer will immediately recognize the flaw or won’t make the mistake in the first place. On the other hand, I would argue that the same C++ programmer who wrote the erroneous code will write this in Swift:

if (x < 0) {
    goto fail; }
    goto fail;

I always put braces around my blocks, even if they are one-line, so this doesn’t affect me. It’s ironic, however, that while Swift prides itself in eliminating the unnecessary break statement at the end of a case block, it requires two to four additional lines (braces) in if, for, and while statements, which are more numerous.

PocketBible and Swift

I will be more than happy to learn and use Swift for programming on iOS and OS X. I just don’t believe the hype and won’t convert just for the sake of doing something new.

I am a strong proponent of platform-independent languages like C, C++, Java, and, to a lesser extent, Objective-C (the latter is primarily an Apple language, though it has its origins outside of Apple). Such languages allow me to develop code on one platform and re-use it on another. One of the promises of C++ and Java was that you could develop the code for one platform and use it on many others. Swift is an Apple language (the same way C# is a Microsoft language). It only works on Apple devices. While those are numerous, they’re not the only devices out there. So rather than moving toward the “write once, read everywhere” model promised by Java, we’re back to “write everywhere” as each platform requires its own language.

I don’t mind learning a new language. I already jump from C++ to C# to Java to VBScript to Javascript to MS-SQL on a daily basis. For those of us who write code for a living, being multilingual is a job requirement. This is precisely why I care so very little about the supposed advantages of Swift; this isn’t a religious war for me, it’s just a tool. When someone comes out with a new kind of screwdriver, I may or may not buy it until I need it. And then I’ll just buy one and use it — I won’t try to convert all my screwdriver-toting friends.

So will PocketBible for OS X and/or iOS be re-written in Swift? Probably not today, and probably not until Apple requires it. But Swift depends on Objective-C under the hood, so my guess is that Apple will continue to support Objective-C apps for a long time.

Braces and Indenting: You’re Doing it Wrong

Screen Shot 2014-01-28 at 8.33.08 AMJava, C++, Objective-C, and C# all use braces ( { and } ) to delineate the beginning and end of blocks of code. Over the years, several styles have evolved, with the worst of them dominating the literature. Once you see The Light you’ll wonder how we ever let this get out of hand.

Before we begin, let’s remind ourselves what braces are for: They mark the beginning and end of blocks of code. In many contexts a block stands in place of a single statement. It allows us to put two or more statements in a place where a single statement is called for in the grammar. In those contexts a block is functionally equivalent to the single statement it replaces. This will be important in our understanding of the One Right Way to indent.

In other contexts, such as the bodies of functions, surrounding the cases in a switch statement, and surrounding the declarations in a class definition, braces demarcate the contents of the function, switch, and class. For convenience, I’ll refer to any group of lines of code surrounded by braces as a “block”, even though the language definition may not always use that term in every context in which braces are used.

So the the first question is to ask: “To what do the braces belong: the block they surround or the syntactical element (if, for, switch, class etc.) to which the block belongs?”

When braces are used to surround a true block (the else clause of an if statement, for example), it’s clear the braces belong to the block. Together with the lines of code they contain, they replace a single statement.

The implication is that the braces should be indented at the same level as the lines of code in the block they surround, for they are part of that block.

The second question we need to ask is: “Should braces share the line with any other code; either a statement from the block they surround or the statement the block belongs to?”

Clearly we would not format code like this:

    x
    = y
    +
    z
    ;

We might break a very long line into two or more lines, but a short statement should always be on one line. Similarly, we try to avoid code like this:

    x = y + z; if ( x > 10 ) foo(x); bar(z); switch (y) {case 1: x = 2 * y; break; case 2: default: foo(x); break;}

The commonly accepted practice is to put one statement on each line. (There are exceptions but they are rare.) Similarly, I would argue that braces belong on a line by themselves. They are not “inline operators” like + or ==. They do not belong to the statement to their right or left; they surround those statements.

The reason we don’t put two or more statements on one line is that it is more difficult to read. It’s why we break up our thoughts into sentences and paragraphs. It aids in comprehension. The same is true of code. Consider the following:

    if ( x < 10 ) { foo(x);
        bar(y); }

The call to foo(x) belongs to the then-clause because it is inside the brace but it would be easy to glance at the code and assume bar(y) is the only statement executed when the if-condition is true because the call to foo(x) is “hidden” at the end of the if statement.

For this reason I would argue that braces belong on a line by themselves. It is too easy to miss them when they are “hidden” at the end of another line of code. So unless you’re in the habit of writing a dozen statements on one line, it doesn’t make sense to put a brace on the same line as another line of code.

With these two rules (i.e. braces belong to the block they surround and braces belong on a line by themselves), there’s only One Right Way to indent your code:

    if ( x < 10 )
        {
        foo(x);
        bar();
        }
    else
        {
        x += 10;
        foo(x);
        }

Now we can see why the predominant indenting style is so, so wrong:

    if ( x < 10 ) {    // should not be on same line as "if"; should be indented with block
        foo(x);
        bar();
    } else {              // should not be on same line as else (*2); should be indented like block above/below
        x += 10;
        foo(x);
    }                     // should be indented like block above

I realize those of you who grew up doing this wrong and reading all the literature from others who do it wrong will find the One Right Way more difficult to read. But it can be argued that you only find it difficult to read because you’re not accustomed to doing things the One Right Way, while the wrong style as illustrated above is difficult for me to read because it makes no attempt to be logically consistent. This makes it objectively wrong, not just a matter of personal preference.


Postscript
In the spirit of unity and the cause of world peace, practitioners of the One Right Way will accept the following style with the hope that those practicing it will see the one small error in their way and with proper mentoring and encouragement, will correct it:

    if ( x < 10 )
    {
        foo(x);
        bar();
    }
    else
    {
        x += 10;
        foo(x);
    }

Parcelable

General Description

An object that implements the Parcelable interface can be “flattened” for inter-process communication or, as is the case most of the time when I use it, for placing in a Bundle (which is a Java associative array or dictionary).

The documentation makes this seem a lot harder than it is. The sample code from the documentation pretty much covers it.

Implementation

1. Implement the Parcelable interface

public class MyClass implements Parcelable
    ...
    @Override
    public int describeContents()
        {
        // From what I've read on the Web, this function should always 
        // return this value. The documentation is very, very vague. I 
        // think this value is actually used only when the parcel really 
        // is a file descriptor.

        // return CONTENTS_FILE_DESCRIPTOR;

        // The sample in the documentation for a general object like mine
        // just returns 0 here.

        return 0;
        }

    @Override
    public void writeToParcel(Parcel dest, int flags)
        {
        // Order is important. The order here should be the same as the
        // is expected in the constructor

	// It sometimes comes in handy to write arrays of values. The 
        // syntax looks like this:

        dest.writeIntArray(new int[] {publisherID, bookID, section});
        dest.writeStringArray(new String[] {verseReference, anchor, TOCPath});
        dest.writeBooleanArray(new boolean[] {wasHyperlink, noHistory});
        }

2. Implement the CREATOR field

Again, the documentation is weirdly vague, but here’s what it looks like. Yours can look identical to this with the exception of “MyClass”, which is the name of your class:

    public static final Parcelable.Creator CREATOR = 
        new Parcelable.Creator() 
        {
        public MyClass createFromParcel(Parcel in) 
            {
            // Calls our constructor that takes a Parcel

            return new MyClass(in); 
            }

        public MyClass[] newArray(int size) 
            {
            return new MyClass[size];
            }
        };

3. Implement a constructor that takes a Parcel

The parcel will have been created with your writeToParcel() method, so it should read values back from the parcel in the same order that you wrote them out:

    public MyClass(Parcel in)
        {
        // Since we used some arrays to demonstrate the writeToParcel()
        // method, read them back here in the same order.

        int [] intData = new int[3];
        in.readIntArray(intData);
        publisherID = intData[0];
        bookID = intData[1];
        section = intData[2];

        String [] stringData = new String[3];
        in.readStringArray(stringData);
        verseReference = stringData[0];
        anchor = stringData[1];
        TOCPath = stringData[2];

        boolean [] booleanData = new boolean[2];
        in.readBooleanArray(booleanData);
        wasHyperlink = booleanData[0];
        noHistory = booleanData[1];
        }

Putting a Parcel in a Bundle

I often use Parcelable objects as parameters to an Intent:

    // Create the parameter object

    MyClass param = new MyClass();

    // Load it up

    param.publisherID = 3;
    param.bookID = 4;
    param.verseReference = "John 3:16";
    // etc.

    // Create the intent

    Intent intent = new Intent("com.laridian.pocketbible.DOSOMETHING");

    // Put the flattened parameter in the Intent and broadcast it

    intent.putExtra(getString(R.string.someparam), (Parcelable) param);
    sendBroadcast(intent);

Retrieving a Parcel from a Bundle

Retrieving the flattened object is no different than retrieving any other object from the Bundle. It will be un-parceled by the cast:

    MyClass reconstructedObject =
        (MyClass) intent.getExtras().getParcelable(context.getString(R.string.someparam));

Don’t store Parcels!

Parcels are not meant to be persistent. They are meant to have short lives, since the format could change between releases of the API/SDK/JRE. Don’t store them anywhere.

Externalizable

Introduction

Java supports two techniques for object permanence: Serializable and Externalizable. These two are related but different. Serializable is more automatic and less flexible. Externalizable is less automatic but more flexible. Serializable is rumored to be slower in some implementations than Externalizable. Because Externalizable gives me a lot more flexibility, I choose to use it exclusively.

Making a class Externalizable is relatively easy. It amounts to implementing two methods: One for writing the state of your object and one for reading it. It also requires that you provide a no-parameter constructor so the system can automatically instantiate your object prior to asking you to read its fields from the file.

By default, any change you make to your class (such as adding a field) will cause any previously serialized data to be incompatible with the class. To resolve this, I take over responsibility for all versioning, as detailed below.

Details

1. Implement Externalizable

Your class needs to implement Externalizable, which requires two functions:

    @Override
    public void writeExternal(ObjectOutput output) throws IOException
        {
        // Write the version number to output using writeInt().
        // Write the fields from your object to output.
        }

    @Override
    public void readExternal(
        ObjectInput input) 
        throws IOException, ClassNotFoundException
        {
        // Read and test the version number.
        // Read the fields of this object in the same order that you wrote them.
        }

2. Add a public constructor with no parameters

You need to add a no-parameter constructor to your class if there isn’t one already. It must be declared “public”. When reading your serialized objects, your object will be constructed using this constructor, then readExternal() will be called.

3. Define serialVersionUID

Add the following field to your class. This identifies the class so the serialization code knows what kind of object to instantiate in its readObject() method:

    private static final long serialVersionUID = 91089626578087866L;

The value of this UID is irrelevant, but it should be unique among the other serialized classes in your document. I use random.org to generate a couple random numbers less than or equal to a million, then concatenate them to create a random long. If you omit this step, the compiler will generate a UID for you, but since it’s based on the class signature it will change if you change just about anything in the class. This will cause an exception to be thrown when you try to deserialize a previously created file. So it’s best to define your own.

4. Manage changes to your class fields

Since you’re defining your own serialVersionUID, you need to completely manage version changes in your serialized file. I create another constant for this purpose:

    private static final int serializationVersion = 1;

In writeExternal() this is the first value I write to the file. When reading, I read this value and test it to make sure I understand the version of the file being read, then make decisions based on the version of the file I’m reading. I may have to supply default values for new fields added to the class since the file was written.

If I don’t recognize the version, I throw a new IOException with a description of the problem:

    throw new IOException("Unrecognized archive version");

5. Notes on writeExternal()

In writeExternal(), use writeInt(), writeBoolean(), etc. to write field values. For enums, use writeObject(). For Strings, use writeUTF(). For your own classes, use writeObject(), then implement Externalizable in those classes.