A 15 minute talk on the differences between the Fantom programming language and Java, showing some of the reasons why Fantom is a real viable alternative to writing pure Java.

Presented to the SkyFoundry Partner Meeting in Washington DC on Wednesday 30 November 2016.

The presentation has been reproduced in the article below, the contents of each are the same.

What is Fantom?

Fantom is a Future Proof, Next Generation Language.

Now, that's a bold statement so we're going to look at some examples of why I think it to be true.

But to do so, we'll have to compare Fantom against a normal, current generation language. For that we're going to use Java.

Java's Duke Mascot

I've picked Java because it's a popular language many will be familiar with.

But who am I to be making this comparison? Well, I would call myself a full stack, web application developer. I have a lot of experience with many languages including, of course, Fantom. Java in particular I've used for most of my career, and have over 13 continuous years of Java development.

But given an option, I wouldn't use most of these languages. Not that I particularly dislike them, but I do consider them to be:

Assembler    - Tedious
Visual Basic - Limited
Java         - Complicated
Javascript   - Anti-Agile
Ruby         - Dangerous
C#           - Ugly

Which leaves...

Fanny the Fantom

Fantom!

And to prove it, we're going to look at the topics of:

  1. Literals
  2. Core API
  3. Concurrency
  4. Language Sugar
  5. X-Platform Development

1. Literals

Fantom is a Forward Thinking Language

Let's see how.

Integers

In Java, if you want to represent a whole number you have a crazy amount of choices!

Java Integers:

byte  -  8 bits
short - 16 bits
char  - 16 bits
int   - 32 bits
long  - 64 bits

And in C# you even have signed and unsigned choices!

Woah! I don't care! I have a number, let's say 10. Perhaps it'll change to 2,000, maybe 200,000. I don't know, I don't want to pre-calculate the min max range!

The thing is, all of this unwanted choice is to deal with legacy architectures from a time when it wasn't efficient to perform 64 bit addition. And that in-efficiency was mocked by C and assembler developers, even if it didn't matter in the grand scheme of programming.

More to the point in today's world of 64 bit architecture supremacy, it isn't even more efficient to process smaller bit numbers! Some even argue it takes longer because of extra bit masking that may be involved! (1)

So what of Fantom then?

Fantom Integers:

Int   - 64 bits

It has one Int that's 64 bits.

Job done.

Would you ever need more bits? Realistically, for general purpose numbers, probably not. 64 bits is pretty huge!

Fantom stores time in an Int - it represents NANO seconds since the year 2000, and that gives us +/-292 years at a pretty high precision. (2) Especially as:

1 ms == 1,000,000 ns

See this comparison on how dates are stored:

Java:  milli seconds since 1970 (unix epoc)

Fantom: nano seconds since 2000 (millennium)

That's pretty forward thinking!

Durations

When it comes to literals - that is, types understood by the compiler, most languages only recognise numbers, booleans, and strings.

So lets talk about a pet hate of mine.

What's wrong with this Java code?

int countdown = 10;
System.out.println("This spaceship will self destruct in " + countdown);

Well, it's going to print,

This spaceship will self destruct in 10

10! 10 what!?

10 seconds? 10 hours? What!? Damn it, units are important! Especially if my spaceship is about to explode!

But more realistically, I see this a lot in APIs when setting timeouts - it leaves the developer guessing whether to pass in minutes, seconds, or milli-seconds. Get it wrong and your 1 second timeout may turn into 16½ minutes!

So Fantom introduces a handy Duration literal. Meaning if you add the word sec or a min to a number, the Fantom compiler doesn't create an instance of a number. Instead it creates an instance of a Duration class.

Now I know exactly when my spaceship will explode!

Which is good news for some!

Joyous SpaceMen!

URIs

Fantom doesn't stop there. It also has a URI literal. Use back ticks instead of normal quotes to create an instance of a URI class.

url := `http://fantom-lang.org/download`

It may seem strange at first, but think about it. We're in the age of the Internet. The Internet of Things!

It not just web pages that have URLs any more. There are images, sounds, REST APIs, databases, and even local file systems!

But it's not just URLs, the Fantom literal is a UR-I (Universal Resource Indicator) meaning, much like how XML is to HTML, you can use it to create your own schemes and IDs!

Why use simple numbers or strings as database IDs when you could be using recognisable and hierarchical URIs!?

For example, why use the obscure number 36 when you could use an URI that comes complete with useful metadata such as what application it belongs to and what collection it represents?

Int '36' vs URI `myApp:/pages/36`

2. Core API

Fantom's Concise and Sane API is a Developer's Dream!

That's nice! But first let's look at what's not a developer's dream!

Lists

The Java Collections Framework!

Say you want a simple list of objects in Java. Arrays are fixed and too inflexible, so you opt for a List object. But do you want a:

Java Lists:

java.util.Collection
java.util.Set
java.util.SortedSet
java.util.NavigableSet
java.util.List
java.util.Queue
java.util.Deque

And that's just the Interfaces! From there you have to choose an implementation! It is Array based? Linked, hashed, or tree based!? Synchronized or fail fast!? The mind boggles!

In all there are about 45 classes and interfaces just for lists and maps in Java! (3)

If you think all this is okay then look at this...

Simple View of Java Lists

The Java Ultimate website presents this Simple View of a List! (4)

Boy, I'd hate to see the complicated view!

I just want an ordered list of 10 things. I really shouldn't need a computer science degree to choose the right implementation!

So by comparison, lets see what Fantom has to offer.

Fantom Lists:

sys::List

It has one.

It handles generics, it has functional methods with closures, and all the methods you need.

Especially for a new comer to Fantom, or programming, it's easy to remember and easy to use.

Job done.

Streams

Another Java example, this time with Streams.

The java.io package has some 80 classes! (5)

Fantom has 2. An InStream, and an OutStream.

Again, they're functional, use closures and have all the methods you need.

Easy to remember, easy to use.

Let's put some of these 80 Java classes to work and read a plain text file.

This is the accepted answer from a StackOverflow question on how to read a plain text file in Java. (6)

select all
// How to read a plain text file in Java

FileReader fr = new FileReader("file.txt")
BufferedReader br = new BufferedReader(fr);
try {
    StringBuilder sb = new StringBuilder();
    String line = br.readLine();
    while (line != null) {
        sb.append(line);
        sb.append(System.lineSeparator());
        line = br.readLine();
    }
    String everything = sb.toString();
} finally {
   br.close();
}

It's 14 lines long! How complicated and convoluted is that!?

Lets look at Fantom...

// How to read a plain text file in Fantom

everything := File(`file.txt`).readAllStr

One line. It's that simple!

This is not just some handy utility method, this the core API and it is one small example of the thought gone into making common tasks really simple.

Note how we use a URI to represent a file on the file system!

Character Sets

On the subject of text files, what of character sets and text encoding?

The great Joel Spolsky once said:

"There is no such thing as plain text" - Joel Spolsky (7)

But lets face it, UTF-8 comes pretty close. And thankfully, Fantom defaults to UTF-8 for everything text related and hence truly becomes platform independent.

Note that Java gets Characters Sets very wrong and uses a platform default, meaning (unless you're very, very careful) you end up with incompatible text files on different systems. Even the Maven build tool fell foul of this one! (8)

3. Concurrency

Fantom uses Actors and the Message Processing Model

This is quite a technical topic that really deserves its own presentation to do it justice, but it is also too important not to mention. So we'll just skim over some of the main points.

Java - Mutable State

First we'll look at Java's stance on concurrency; it uses mutable state.

Mutable state is simple enough to understand. each thread has access to the same bit of data and each thread may update it any time.

Java Threads

Unfortunately java tries to be clever and introduces things like thread data caching. And what happens when you need to update 2 bits of data at the same time and don't want any other thread to access any of it until you're finished!? (Like the contrived example of crediting one bank account and debiting the other).

All this and more, means you need to be an expert in mutable concurrency models just to implement the basics! (9)

Difficult to Implement Safely

In brief, mutable state in Java is difficult to implement safely because to do it properly you also need to fully understand:

  • Threads,
  • Locks,
  • Semaphores,
  • JSR133,
  • Broken double locking mechanisms,
  • and more!

Functional programming says that "All state is evil!" If that's true then surely mutable state must be the ultimate evil!

Error Prone

Java has 60 classes dedicated to doing concurrency properly. (10) Given all the complications of the above, then implementing mutable state safely is also prone to errors and mistakes.

Not Scalable

And it's not even scalable. If you wanted more processing threads then you're just creating a bottle neck on the synchronised data.

Fantom - Message Processing

By comparison, Fantom employs an Actor framework and the message processing model.

Here threads, also known as Actors, send messages to each other. These messages are just instances of Fantom classes. But not just any classes, immutable classes! This means the message content can not change, hence we don't have the mutable state conundrum that Java has.

Fantom Actors

Easy to Implement Safely

Better yet, it is not even possible to compile a Fantom program whereby different threads have access to the same bit of data! Therefore when it comes to concurrency, Fantom as a language is inherently safe!

Actors are easy to understand and implement and it only take 4 classes in the Fantom concurrent pod.

Less Error Prone

The compiler forces the use of immutable message classes between Actors which makes it safe and less prone to errors.

Scalable

The Actor model is also scalable, allowing you to add more threaded workers as you wish.

4. Language Sugar

Fantom's Language Sugar makes it a joy to program!

There are sooo many little things to mention here I've found it difficult to limit myself - but I've picked 3 to share with you...

Field Accessors

Java has fields. But if you wanted to alter the behaviour slightly, like trimming and a validating inputs, then you would need a method. And then you'd need to change ALL your code from using the field to using the method.

As this is painful, Java programmers usually forgo fields altogether and instead create lots of boiler plate getter and setter methods. (11)

select all
// Example Java field with getter / setter

private String greeting;

public String getGreeting() {
    return "Hello " + greeting + "!";
}
public void setGreeting(String greeting) {
    this.greeting = greeting.trim();
}

// code to set a field value changes from ...
myClass.greeting = "Mum";
// to ...
myClass.setGreeting("Mum");

It's tedious.

Fantom, on the other hand, has real field accessors! Something I've missed since my early days of programming Visual Basic! Not even C# properties come close to the real power of Fantom fields!

Here, we have examples of 3 Fantom fields.

select all
// standard field
Str greeting1

// field with getter / setter
Str greeting2 {
    get { "Hello ${&greeting}!" }
    set { &greeting = it.trim }
}

// read only field
Str greeting3 {
    private set
}

Note that the second has a getter and setter. These are optional, any field may or may not have them. It doesn't matter if they exist or not, all the code that uses that field stays the same.

Even better, if you want to make the field read only, just make the setter private!

No boiler plate code, no getter and setter methods. Just intelligent fields.

Type Inference

Next a quick look at the Java syntax.

Here we create a new StringBuilder class, and we assign it to a StringBuilder variable.

// create a Java variable
StringBuilder sb = new StringBuilder();

Note how we've just had to type StringBuilder twice.

And this happens a lot in Java. It's strongly typed and we have to repeat ourselves over and over and over... which makes for long lines of code. Especially when you start adding in generics!

Fantom is different. It uses Type Inference to determine what the variables should be.

Here we create a StrBuf (similar to java's StringBuilder) but Fantom knows what it is and hence assigns it to automatically to a StrBuf variable.

// create a Fantom variable
sb := StrBuf()

We don't repeat ourselves and it cuts down a lot of code.

Other languages have cottoned on to the concise expressiveness of type inference, but Fantom gives real power to the programmer and goes one step further...

It has a unique "loose" type inference whereby if something could work then it assumes it does work!

A quick example with 3 classes to explain it.

Animal class with Cat and Dog subclasses

Assume we have a method eat() that takes a Cat:

Void eat(Cat cat) { ... }

// ✔ - passing in a Cat instance is fine
cat := Cat()
eat(cat)

The compiler will bork if we try to pass in a Dog:

Void eat(Cat cat) { ... }

// ✗- compilation error when passing a Dog instance
dog := Dog()
eat(dog)

But the compiler will let us pass in an animal instance, even if it is wrong.

Void eat(Cat cat) { ... }

// ? - runtime error if animal is not a Cat
animal := Dog() as Animal
eat(animal)

This will, of course, cause a runtime error. But because it could work, the compiler trusts that the programmer knows what they're doing and inserts an implicit cast. (Java would force us to explicitly add the cast ourselves.)

But in the course of static programming, 99.9% of the time we do know what our variables are. And in practice, this is never an issue.

But what it does do for us, is dramatically cut down the amount of casting and type coercion, meaning we type a heck of a lot less!

Code Visibility

This is a such a small thing, but it means so much to me because I write so many libraries and pods for Fantom.

Fantom has 3 main visibility types:

Fantom Visibility

Private visibility means it is private to the class.

Public visibility means everyone can see it. This is the public API that your library exposes to the outside world.

Then there's internal visibility that means it is only accessible to the containing pod.

This is brilliant because it means you can pick and choose what to share with the outside world and keep all your internals hidden from view! For example, the Sizzle pod which performs CSS selectors on XML documents, it has a tiny public API of 1 class and 6 methods. But internally it has 10 classes and countless methods! (12)

A common problem in other languages, like Java, is that they expose everything which makes it very daunting for users to know which classes and methods they should be using!

Honourable Mentions

Other cool language sugar that I could mention include:

  • Default method parameters
  • Everything is an Object
  • Nullable types
  • No checked exceptions
  • Simple reflection
  • Dynamic programming
  • Human readable object serialisation
  • Markdown documentation
  • ...

In fact, there are just too many to mention!

5. X-Platform Development

Fantom for Cross Platform Development

Fantom runs great on a Java JVM, and there's a lot of work gone into a .NET implementation. But annotate any class with @Js and it automatically gets compiled to Javascript. That's right, the entire Fantom runtime and sys pod is available in Javascript, and runs in a browser!

If you want to specifically write Fantom that targets the browser environment, then the dom and domkit libraries give you some kick ass performance.

But better yet, the core Fantom graphics library, and the windowing toolkit, initially written for desktops, also runs in a browser! I can't tell you how cool this is! In fact, I can only show you!

Fanny the Fantom

So here is a little game I created. I wrote it in Fantom and I wrote the entire game to run as a desktop application. I then set about making it run in a browser. To do that took just 25 minutes, including creating a web site to serve it from!

Fanny the Fantom Title Screen

It is called Fanny the Fantom, features some retro looking vector graphics, and even persists its high scores to a server on the internet! (13)

Play with Fanny in a browser here:

Fanny the Fantom Game

Epilogue

To find out more about Fantom you can visit:

http://fantom.org/ (official site)

http://fantom-lang.org/ (community site)

I am Steve Eynon.

And this has been why I consider Fantom to be the Developers Choice!

References

  1. StackOverflow - On 32-bit CPUs, is an 'int' type more efficient than a 'short' type?
  2. Fantom - DateTime Trade Offs
  3. Oracle - java.util package summary
  4. Java Ultimate - Introduction to Collection Framework
  5. Oracle - java.io package summary
  6. StackOverflow - Reading a plain text file in Java
  7. Joel on Software - The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!)
  8. StackOverflow - Error: unmappable character for encoding UTF8 during maven compilation
  9. Software Engineering - Why is Akka good for concurrency?
  10. Oracle - java.util.concurrent package summary
  11. StackOverflow - What is a JavaBean exactly?
  12. Eggbox Pod Repository - Sizzle API
  13. Fantom-Factory - Fanny the Fantom Game

Edits

  • 10 Dec 2016 - Original article.

Discuss