Similar concepts

1. Arrow functions

Basically like shorthand syntax, but for functions.

Declaring a function like:

function foo(param) {}

Is equivalent to declaring a function as a constant in ES6:

const arrowFoo = (param) => {}

From what I understand, arrow functions eventuated from the limitation in traditional JavaScript functions that prevented you from accessing the scope of objects via this , known as context, in the callback. Further complicating this is the execution context, which is applicable to scope not context, which prevents the original function that was executed binding to a different execution context.

It’s confusing, and I don’t want to get into any in-depth explanations because it will hijack this blog post when it’s already too long, but this link does a good job of explaining it.

Because Swift is a language on a platform that supports multi-threading, it didn’t have the same problem with execution contexts. But it still maintains thread safety through it’s careful use of the equivalent of this. For Swift’s version of this , self , we still have to use [weak self] in closures to guarantee it can be safely accessed. But this is more to do with safety and less to do with any inability to technically access instance methods & properties.

Additionally, because arrow functions in general return a function (or to better explain it, arrow functions are constants with a function as the value), they’re similar in declaring a constant as a closure in Swift:

let arrowFoo = (param: ParamType) -> ReturnType

2. Mutable & Constant Variables

JS used to have var , but now that is essentially deprecated in favor of let (reassignable) and const (single-assignable).

const setOnce = 101

let setWhenever = 202

There are scope differences between JS’s var and let , and while that’s not worth getting into within the context of Swift comparisons, it’s worth touching slightly. let variables by default are limited to the scope of whatever they’re declared in, be it a function, a for loop, etc.

Swift’s equivalent is the inverse of JS. let is used for constants, while the var keyword is used for reassignable variables:

let setOnce = 101

var setWhenever = 202

This is a minor difference, but one that can be a habit hard to break, similar to driving a car in left-hand drive to right-hand drive.

Regarding the limited scope of JS’s let , in Swift functions var and let are both limited by scope, or in a closure it would be the equivalent of not prepending __block to your variable, or in an object declaring it as private.

3. Object Literals

In JavaScript you’ve never been truly able to create objects, at least in the sense that you can in a strongly typed OOP language where an object is created with a class, constructor, etc. Objects in JS don’t inherit from an object by default, although they can use prototypal inheritance to enable inheritance through a factory pattern such as create() .

All object literals are, essentially are key-value structures. An object is defined inline with a colon separating the key from the value, such as defining a coffee mug:

const CoffeeMug = {

millileters: 300,

artworkPath: "./images/coffee-mug-logo.png",

coffeeType: "espresso",

onRefill: refill()

}

As you’d expect in an object, you can define any type to your properties, including other objects, arrays, or functions.

In Swift, this is equivalent to a couple of things.

Firstly, defining object literals are syntactically and functionally equivalent to declaring a Dictionary. Further, an Enumeration or Struct in Swift could be used to provide greater flexibility that a dictionary, but also with the benefit of not needing explicit constructors, getters, or setters.

Secondly, implicitly setting an object without defining its type through type inference. This has been a feature of JS since the beginning, but in Swift any type that is inferred will maintain that type through its lifecycle. This is perfectly valid in Swift, if we were going to declare it as a dictionary:

let CoffeeMug = [

"millileters": "300",

"artworkPath": "./images/coffee-mug-logo.png",

"coffeeType": "espresso",

"onRefill": "refill"

]

Where you’d have to include type annotation, is if you wanted to retain those values as being of any type. Here’s a modified version with the millileters value set as an int, coffeeType set as an enumerated type, and refill set as a closure:

let refill: () -> () = { /** refill code here… */ }

enum type { case espresso, drip, pourover } let CoffeeMug: [String: Any] = [

"millileters": 300,

"artworkPath": "./images/coffee-mug-logo.png",

"coffeeType": type.espresso,

"onRefill": refill

]

4. Template Literals

String interpolation has recently become possible in JS, removing the redundant need to append string with + to variables.

Template literals are the syntax needed for JavaScript’s string interpolation, achieved by `${...}` . Eg, the following string in reference to a person’s BMI:

const bmi = weight / height const bmiReading = "Your BMI is: `${bmi}`"

The equivalent in Swift is:

let bmi = weight / height let bmiReading = "Your BMI is: \(bmi)"

5. Modules

This is a way that JS encourages modular reuse of code. I’m not sure what predated modules (the script tag kind of seems similar, but different somehow), but to me this seems like a requirement for any modern programming language. Or maybe I’ve been in the world of Swift for too long where this is taken for granted.

For instance, you could declare and define a constant in its own file, with the intention of being an external module.

const ButtonModule = () => { ... } export default ButtonModule

The export keyword is also a way to specify what is private or public to the internal module, or other modules using it. Although this is the kind of encapsulation you get with structs or classes, keep in mind that JS is best served when it’s not moulded into a class-based language. This is why modules serve the job here, it suits JS!

Having said that though, Swift doesn’t quite have the exact equivalent. If we run with the assumption I made earlier, where modules are JavaScript’s way of “encouraging” modular reuse of code, Swift doesn’t quite have something that guides you the same way.

The closest comparison in Swift is frameworks, but this doesn’t quite do justice to what purpose JS modules serve. Although frameworks can be light, they’re usually complete libraries rather than a single abstraction. Frameworks also have to be explicitly imported, although that’s where the comparison ends.

The closest comparison to single abstraction though, would perhaps be protocols. Protocols define what the behaviour or look could entail, without storing state that a struct or a class would. Any protocol you create doesn’t have to be explicitly imported either (unless dealing with Objective-C, which takes its cues from C’s header file imports).

6. Default & Rest Operators

Default parameters do have an equivalent in Swift. They work the same way, in that any parameter with a default value, can be omitted from the caller.

function find(searchTerm, sort=true) {...} //You are able to call this as...

find(“toronto”)

The equivalent in Swift is the same thing:

func find(_ searchTerm: String, _ sort: Bool=true) -> Bool

{...} //You are able to call this as...

find(“toronto”)

Rest allows for an indefinite amount of arguments. When a parameter is prepended by … this implies that a number of arguments have been passed in as an array.

function outputArgLength(...groupedArguments) {

return 'output: ' + groupedArguments.length

} outputArgLength(2, 4, 6)

//output: 3

UPDATE:

In Swift, there is actually an equivalent to this called Variadic parameters (I just don’t tend to use it too much). The syntax is just slightly different with the … appended to the type, rather than prepended to the argument name.

Keep in mind that parameters do need types in Swift, as it’s a strongly typed language. Although this can take the form of a generic instead of a primitive or object, but that’s a topic for outside of this blog post.

func outputArgLength(_ groupedArguments: Int...) -> String {

return "output: \(groupedArguments.count)"

} outputArgLength(2, 4, 6)

//output: 3

7. Promises

The reason for promises existing is pretty much a main reason why I ran away from JS to iOS all of those years ago — to alleviate what would later be called (but was frustratingly originally embraced) callback hell.

Promises are async callbacks conveniently encapsulated for catches or continuing on the flow. Anything that returns a promise, provides you with the ability to use chaining with .then (that passes in the successful result) or .catch (that passes in an error). Define a promise like such:

function refill() {

return new Promise(

function (resolve, reject) {

resolve(result)

reject(error)

}

)

}

What if 2 or more async calls are executed subsequently (the promise equivalent of nesting)? Well, conveniently errors are propagated on until the error is handled:

refill()

.then(refillResult => {

return requestMoreBeans()

})

.then(moreBeansResult => {})

.catch(error => {});

In Swift, closures fill the void of needing to execute a function asynchronously. A closure isn’t asynchronous itself, but this need can be filled with Grand Central Dispatch (GCD). The following is a basic example of how to execute a closure asynchronously:

DispatchQueue.global().async {

refill()

DispatchQueue.main.async {

//Perform UI related code on the main thread...

}

}

While it’s possible to fall victim to callback hell in this implementation too, the habit in calling back to the main thread, as well as following good design patterns and SOLID principles, alleviates this problem.

GCD is FIFO by nature, but if you need more control over the dependencies and states of your queue, and the ability to pause and cancel operations, there’s OperationQueue. Although this might sound counter-intuitive, because OperationQueue technically uses GCD, and GCD is a lower level API, it’s often overkill to use OperationQueue. Because a Promise possesses a range of 3 states (pending, fulfilled, rejected), it’s probably more in line with an OperationQueue in nature, yet more similar to the lower level GCD syntactically.

Operations in OperationQueue are executed on a background thread by default, different to GCD where you have to specify this. Both GCD & OperationQueue provide an abstraction on creating threads directly (the async and sync decision making is left to you in GCD). Thread management is complicated enough with these abstractions, let alone without them, but it’s essential in mobile. If you’re working in Swift, you’re going to be using either or both of these libraries a lot.

8. Function types as return types

This needs an honourable mention, because the pattern of declaring a function that returns a function is very common in React & React Native. A similar objective can be achieved in Swift, and although I haven’t used it a lot, being inspired by React could form the basis of trying a similar approach the next time I dive into Swift.

The only difference in JavaScript, is you can declare a constant as a function without defining the function first (although this can be achieved with closures in Swift, as touched on earlier):

const refillDone = () => {

//do stuff: refill the coffee, then return how long it took...

return 0

} function refillToFull(full) {

return refillDone

}

In Swift, this isn’t to be confused with a closure as a parameter, which in a way allows a function to execute a function passed in as a parameter. The main difference being here that when a function is returned, the caller decides when or if to execute it. A closure however, is executed at the function’s discretion.

Using our refill example again. We will define refill as a function that returns a function. The function it returns will be another one we define, called refillDone , which returns a TimeInterval denoting the time taken to refill the coffee: