Swift for the Java Guy: Part 2 – The basics
In Part 1 of this series we looked at how to get Swift up and running. In this part we will look the Differences between Java and Swift at a language level by creating the Swift classes and comparing them to Java. For this article we will go over the basic of class construction.
Firstly; Whats the same.
Both languages are fundamentally statically typed class based OO languages with single inheritance and interfaces. Furthermore Swift includes the normal set of features that Java has including:
- Try-Catch style Exception handling
- C-Style syntax
- Generics
- First class and high order functions
Whats different
Swift is very different in a key set of areas including
- Reference based memory management using Automated Reference counting as opposed to a garbage collector.
- Swift classes don’t inherit from a base object class.
- Swift classes do not need to be declared in a file that follows the Namespace and Class name pattern.
- All methods in Swift are functions, Void in Swift is essential a type alias for an empty Tuple.
- Swift only has three access modifiers, private and public which behave similarly to the Java equivalents. It also has
internal
which is Swifts equivalent of default access, Swift however has no protected modifier. - Swift interface (or protocols as they are called in Swift parlance) cannot have default implementations (although you can achieve the same effect with extensions).
- Enums in Swift are “different”. The best way I can describe is that Swift Enums are basically a set named Tuples which are grouped together in a Enum declaration, each one can declare it’s own structure.
What Swift has that Java does not.
Swift has a range of features that Java does not have
- Value Types (Structs)
- Tuples
- Extension types
- Operator overloading
- Type inference
- Language level optional monads and strict null checking
- Properties
- Destructors
- Values and variables as opposed to just variables ala Scala
- Nested functions (AKA functions inside functions)
- Pattern matching
Declaring your first Class in Swift
For this example I create simple class called “Animal” with a single void method makeSound
class Animal { func makeSound() -> Void { print("Roar!!") } } Animal().makeSound()
A few observations:
- Swift methods are explicitly declared with the
func
keyword and have the return type after the “->” operator which is the opposite order of Java approach in terms of declaration. - The last line creates a new instance of
Animal
and calls themakeSound
method. Note that Animal also has an implicitno-args constructor
, also there is nonew
keyword.
Adding a property
So obviously not all animals roar, to fix this we add a property sound
to the class by adding the following
class Animal { var sound:String = "Croak" func makeSound() -> Void { print(sound) } } let animal = Animal() animal.sound = "Roar" animal.makeSound()
By default all variables (denoted by the var
keyword) declared as members are properties. What isn’t visible here is that when you set the sound property it’s actually accessed via accessor methods that are created implicitly. Another point worth mentioning is that the animal
variable is not a variable at all but rather a constant as indicated by the let
keyword, the let
keyword is Swift’s equivalent of Scala’s val
keyword.
Constructors
In the previous example I set roar the default value of “Croak”, It would be better if we could pass this information via a constructor and make the sound property immutable, to do this we change the class as follows:
class Animal { let sound:String init(sound:String) { self.sound = sound } func makeSound() -> Void { print(sound) } } let animal = Animal(sound:"Roar") animal.makeSound()
Constructors in Swift are slightly different to Java in terms of syntax in that they are defined inside inside a block defined with the keyword init
. These blocks can take parameters as you would have in a Java constructor. I also changed the sound property from var
to let
, this means that the sound property cannot be reassigned once it’s been assigned. Its also worth showing here that Swift requires you to use named parameters when you invoke the constructor, this will be familiar to anyone who has ever used Objective-C.
Adding an interface (or Protocol)
Since Animals aren’t the only things that make sound, we can pull this functionality up into a Protocol called Audible
which can be implemented by the Animal
class.
protocol Audible { func makeSound() -> Void } class Animal:Audible { let sound:String init(sound:String) { self.sound = sound } func makeSound() -> Void { print(sound) } } let audible:Audible = Animal(sound:"Roar") audible.makeSound()
Here I added a protocol with a makeSound method, aside from the protocol
keyword, this should look familiar to most Java developers. The only change to the Animal
class is that it implements Audible
. The syntax for extension and implementation is the colon syntax which works the same way as C#. I also explicitly typed my audible value to be of type Audible
just to force an upcast.
Properties on Protocols
With property properties onto Protocols. For this example I created another Protocol called Named
which just has a String property; name
protocol Named { var name:String {get set} } protocol Audible { func makeSound() -> Void } class Animal: Audible, Named { let sound:String var name:String init(sound:String, name:String) { self.sound = sound self.name = name } func makeSound() -> Void { print(sound) } } let animal = Animal(sound:"Roar", name:"Lion") print(animal.name) animal.makeSound()
This example also shows mutability of the name property using the get
and set
keywords. Interestingly I still have to define the actual name variable on the Animal
class. Keeping in mind that a Protocol defines behaviour, a property on a Protocol only indicates how the property is structured not how it’s stored, that is the responsibility of the implementing class.
Inheritance
For our final addition lets create a class called LivingOrganism
which implements Named
and make Animal
extend that. I also add a default constructor which takes the name
property as a parameter
class LivingOrganism:Named { var name:String init(name:String) { self.name = name } } class Animal: LivingOrganism, Audible { let sound:String init(sound:String, name:String) { self.sound = sound super.init(name:name) } func makeSound() -> Void { print(sound) } }
Again note the C# style inheritance syntax. Another interesting thing to note is the use of the super keyword which behaves much like super in Java. In this case I invoked the super class init method inside Animal. One difference to Java is that Swift requires the local variables to be initialised first before invoking the super constructor, hence the call being the last line of Animal’s constructor. This is the reverse of Java.
So there we have it, a basic overview of class construction in Swift. In the next part we will explore Some of the additional features of Swift such as Tuples and Strict Null checking with optional monads.
Reference: | Swift for the Java Guy: Part 2 – The basics from our JCG partner Julian Exenberger at the Dot Neverland blog. |