Dart Type System

I'm currently looking at the Dart Language.

I previously had a go at building a Proof of Concept mobile app in Flutter, though I didn't truly understand what I was doing, I just did enough to find my way through and get a working concept. By working, I mean, it had a layout and responded to clicks, it didn't actually do anything interesting, there ws no engineering under the hood. I just figured out how to get the layout I wanted and for it to do things on clicking. As it was, the PoC was unsuccessful, the potential client went with something built in Mendix instead but regardless, I realised that I quite like Flutter and would like to come back and visit this again at some point.

Now this PoC wasn't a core business activity, I was already working for the client on another part of the project but when that client started looking for a mobile application with cross-platform compatibility, I decided I might as well have a go at winning that new piece of work, I know the customer and the work is what I want to be doing anyway, so why not?

Cross-platform Compatibility

This is where Flutter shines, it allows you to build apps for iOS, Android, Desktop and the Web using a single language base. I've been following the Flutter developments, from afar, since around 2019/2020 when I first became aware of it, though never had a reason to do anything productive in it.

I am currently working on a couple of personal projects, probably too many really, giving me little time to focus on any one of them long enough to just get it out there and then move on, but that's a me problem. I had planned to deliver this particular project using React, but once I sat down to work on this I decided that maybe this was a project that suits Flutter.

The Dart Language

Flutter isn't actually a language, it is a Software Development Kit with pre-written 'things' that you can build up an application with. This 'use of pre-written things' is why I was able to use it for a PoC without really understanding the product. I will say, from memory at least, understanding where things are placed on the screen was overly complicated, but that might just be a bad memory or the fact that it was new to me.

The actual underlying language is called Dart, a language developed by Google and one that is showing significant growth over the last few years. Dart, itself, is based on C which feels like a pretty ancient language to me, but it is one that is enormously important even today, perhaps, especially today.

In order for me to build the thing I want to build, using Flutter, I first need to understand quite a bit more about the Dart programming language.

Static vs Dynamic

I'd probably say my strongest language is Python, followed by JavaScript, both of which are known as Dynamically typed languages. Things like Kotlin, Swift and Dart are Statically Typed languages.

A Dynamically Typed language is kind of free to do what it wants until Run time - which means that if there is a major fault in a particular line of a particular function (a function that may only be called in exceptionally rare situations, for example), you may not find that fault until you actually need that line in that function.

If we compare this to a Statically Typed language, the freedom ends at Compile time. All of the code is compiled before you can use it, so if there was a fault in a function that may never actually be called, the compiler should still catch that fault at compile time, allowing you to fix the problem (hopefully) long before it comes around to bite your rear-end. That's not to say that a Statically Typed program that successfully compiles is bug free, it just means that it passed it's type checks I suppose.

The Type Checker

Essentially, when the Dart program is compiled, it's variables are checked and locked in place. The Type checker also makes sure that any methods being called against a variable are appropriate.

Let's consider this;

Python

name = OneMoreDavid
print(type(name))   // <class 'str'>

name = 52
print(type(name))   // <class 'int'>

We are able to change the variable type on the fly from string to int.

Dart

void main() {
  String name =
      'OneMoreDavid'; //NB I have declared the variable (name) AND the type (String)
  print(name.runtimeType);

  int name = 1;
  print(name.runtimeType);
}

/*
will produce this error: 

                            Context: Previous declaration of 'name'.
  String name =
         ^^^^
*/

I am unable to compile this code because the name has already been declared, so perhaps I can just have 2 different names, one for an int and one for a string?

void main() {
  String name =
      'OneMoreDavid'; //NB I have declared the variable (name) AND the type (String)
  print(name.runtimeType);

  String newName = 1;
  print(newName.runtimeType);
}

                    Error: A value of type 'int' can't be assigned to a variable of type 'String'.
  String newName = 1;
                 ^

Dart is preventing me from using an integer data value with a String data type.

Advantages of Static Languages?

Static languages help us find type-related bugs at compile time. Code is arguably more readable and easier to maintain.

Type Inference

In my Dart example above, I used String name = ... essentially telling the compiler both the value and type for the variable called name. I didn't need to do that. I think it is good practice to do so as it helps others reading your code understand what the variable should contain, but actually, Dart can infer the type at compile type, both of these would work:

void main() {
  String nameThree = 'OneMoreDavid'; 
  print(nameThree.runtimeType);

  var nameFour = 'OneMore_David';
  print(nameFour.runtimeType);
}

// both of these return String

What about Finals?

A Final is a restricted variable, but if it's a variable, then why would it be restricted?

This may be a one-time variable, something that is not known until the program runs, but once it is running, then we want that value to remain, we want immutability. This helps with integrity by preventing unintended modifications.

An example of a good use of a final might be in a class, we don't know what should be in the variable until the user calls the class, at which point the variable can be set allowing us to move forward without worrying about that value being changed by accident later on.

Const

This is the most restricted of variables. Why would we need a 3rd type of variable, why doesn't final cover any 'one-time' variable needs?

Well this is where it is important to understand that when you compile a program with the final variable, that variable can be declared but also be empty and remains empty until populated through the execution of the program. Perhaps we want the user's license key, we wouldn't want to save that in the program, we'd want the user to provide it later, once provided, they are unable to change it (this may be a weak example).

A const is a value that we know at the time of compilation. Using Constants increases efficiency and performance of a program as they are stored in a single place in memory etc.

Variable order:

It is said that we should prefer constants over finals and finals over var's. That's true, but to consider it a different way, consider:

Freedom to use as and when (order, 1 is best):

  1. var
  2. final
  3. const

Yet when we consider the predictability, efficiency and performance of large applications, knowing what value is where and when is far more important.

Performance (1 is best):

  1. const
  2. final
  3. var

  var   = can be set more than once
  final = can be set only once 
  const = compile-time constants

Dynamic = no-type-safety

There is another keyword, just to mix thing up a little. Dynamic is a keyword that can be used to opt-out of Dart's type safety.

void main() {
  var x = 10;   // inference type = int
  x = true;     // this will fail because you cannot have a bool in an integer type

  dynamic y = 10;
  y = true;     // this will work, this will change the type 
}

So why would you do this?

It's a programmers flex, you are basically saying 'hey Dart, I know what I'm doing, leave me alone'.

Is there a real reason for this? Yes. If you were reading JSON data, you may not always get the data-type you're expecting, so that's one of the few times that it is good to use the dynamic keyword.

I kind of like Dart, but after spending so much time tinkering in Python and even JavaScript, it's taking a minute to get used to some of the differences.