5 Programming Techniques to Know

This might come as a shock to younger programmers, but a long time ago, there were a limited number of programming languages out there, and those programming languages had very defined limits. Basic only had arrays as data structures; C was restricted to arrays, pointers, and linked lists. It wasn’t until the emergence of C++, Java, and Python that we were gifted something a bit more modern (and even then, it took the rise of the Web to increase the popularity of these now-ubiquitous platforms).

Now there are all sorts of programming languages with interesting features designed to improve robustness and reliability. If you’re still finding your way as a programmer or developer, here are five techniques to know:

Immutability

Whatever you’ve declared immutable can’t be changed. In Swift, you declare variables with ‘var’ for mutable and ‘let’ for immutable. (There are exceptions; for example, if there are dependencies elsewhere in the code. And declarations can always be changed.)

In this example, the person class declares two immutable properties with ‘let.’ As all the fields are immutable, the object is immutable:

class Person {

    let firstName: String
    let lastName: String

    init(first: String, last: String) {
         firstName = first
         lastName = last
    }
    
   public func toString() -> String {
       return "\(self.firstName) \(self.lastName)";
   }
}

var man = Person(first:"David", last:"Bolton")
print( man.toString() )

(This prints “David Bolton.” Attempts to change man.firstName/man.lastName will fail.)

Immutability of variables is very useful. It gives compilers better optimization. In multi-threaded programming, knowing that a variable is immutable means that locking or guard code isn’t needed, as nothing can change it and the value can be shared between threads. If you are copying an immutable object, you can copy the reference to it, instead.

Safe Calls

Computer scientist Sir Tony Hoare once said that introducing null references was a billion-dollar mistake. Trying to access a variable via a null reference causes a null reference exception and, unless it’s handled, a crash. Languages with exception handling can cope with it, but null pointers are not exactly unknown in C.

Several programming languages have added safety checks to prevent null reference errors. For example, in C# 6.0, the following example avoids three sets of if (variable == null) and else, reducing maybe 10 lines down to one. The ? means that if ‘customers’, ‘customers[0]’, or ‘customers[0].orders’ are null, it returns a null to count; otherwise it calls the Count() method. The count variable has to be declared a nullable int so it can take the null value:

int? count = customers?[0]?.Orders?.Count(); 

Good code should check if count is null. You could use if (count.HasValue) or the value of count ?? 0 (null coalescing operator – returns the specified default value if count is null) to deal with count after this.

Lambdas

Despite the exotic name, a Lambda expression is just a way of defining and calling an anonymous function. (In Swift, it’s also a closure, but we’ll come onto those next.) Lambdas are useful with languages that support first-class functions. You can pass a function as a parameter to another function or return a function from a function.

Lambdas originated with functional languages such as Lisp, and C# has had Lambdas since 2007. The syntax for Lambda expressions is similar in other languages and looks something like this:

()-> {code...}

Languages that support Lambdas include PHP (from 5.3), JavaScript, Swift, Java (from Java 8), JavaScript (though not called Lambda), Python, and others including VB.NET.

Why use Lambdas? Their conciseness makes code shorter and easier to understand. For example, these two lines build a list of odd numbers:

    List list = new List() { 1, 2, 3, 4, 5, 6, 7, 8 };  
    List oddNumbers = list.FindAll(x => (x % 2) != 0);  

After this, oddNumbers contains 1,3, 5 and 7.

Closures

A closure is an anonymous function, or block of code passed outside of the function or block where it was created. It captures any variables from the inner block/function in which it is created that it uses. That sounds complicated, but is easier to show.
Here’s a Swift closure in action (with the example taken from the Swift 3.1 documentation):

func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
let incrementByTen = makeIncrementer(forIncrement: 10)
print("\(incrementByTen())")
print("\(incrementByTen())")
print("\(incrementByTen())")

It outputs 10, then 20, then 30.

The makeIncrementer() function was called with a value of 10, and that was added to the total everytime incrementbyTen() was called. You could just as easily create another incrementer(), say using 3:

let incrementByThree = makeIncrementer(forIncrement: 3)

Three calls to incrementByThree() would output 3,6,9. Behind the scenes, makeIncrementer() creates an instance of a class passing in the value to add. The incrementer() func is a method of this class.
The programming benefits of closures: you can build something powerful with simpler code. Anything that reduces cognitive load makes software easier to understand.

Concurrency

Not to be confused with parallel computing, although the concepts are similar (with parallel computing, code runs on different processors at the same time). With concurrency, you can split your program into lots of different bits that can be executed out of order, even as the program functions correctly.

Multithreading has been around for many years, but doing concurrency via tasks can be easier and a lot less buggy. In C#, for example, the TPL (Task Parallel Library) will use the CLR thread pool if needed. This spares us the overhead of creating threads, which is an expensive operation. Tasks can be chained together one after another and can optionally return results. (Doing this with threads is a lot harder.)

Possibly the greatest benefit of tasks is with asynchronous code (for example, using async/await in C#, JavaScript and Java). Making web service calls asynchronously takes the same length of time as synchronous calls, but doesn’t block the thread. During an asynchronous call, a thread is not blocked from responding to other requests while it waits for the first request to complete. This requires fewer threads overall.

This example shows concurrency using async/await in C#:

public async Task MethodAsync()
{
    Task longRunningTask = LongRunningTaskAsync();
    ... any code here

    int result = await longRunningTask;
    DoSomething(result);
}

public async Task LongRunningTaskAsync() { // returns an int
    await Task.Delay(1000);
    return 1;
}

A web crawler might request several pages at the same time; as each is fetched, it gets processed. The order that the pages are fetched is indeterminate: that’s concurrency.

Image Credit: Iconic Bestiary/Shutterstock.com

Post a Comment

Your email address will not be published.