Introducing Second Bridge

Introducing Second Bridge

Introducing Second Bridge

We are pleased to announce the release of our latest iOS open source project - Second Bridge, a new framework for functional programming in Swift.

As the name implies, our goal while developing this framework has been to bridge the two languages we use in our day-to-day development here at 47 Degrees: Swift and Scala. It’s clear that while creating Swift, Apple has taken steps towards a more functional development style (i.e. introduction of Optional types, higher-order functions, and others). But for us it wasn’t enough. And for the community it seems it wasn’t either, as there are really great developers that have done an awesome job paving the way for the rest of us to do functional development in Swift. Before starting the development of Second Bridge we took a look at those projects and we selected Swiftz as a foundation to build it.

Swiftz is an open-source functional development framework for Swift. It supports a lot of great features that we really wanted to create while planning Second Bridge, such as Monads, Monoids, Either, Function Composition, and Futures. It’s a really well-crafted framework! So, why keep going with our plans? Well, here on the 47 Degrees iOS Team, we’re very much in contact with Scala in a daily basis. So, when thinking about bringing functional development to Swift our minds were really set on Scala’s concepts and syntax. In the next section you’ll find a brief description of some of the new features we’ve implemented and some code snippets, so you can see what Second Bridge looks like!

New features

  • Immutable and generic data-types based on Scala’s Traversable collections: singly-linked lists, stacks, maps, arrays, and the first implementation of a bitmapped vector trie (i.e.: Clojure and Scala’s Vector type) in Swift.

      let «list» : ListT<Int> = [1, 2, 3, 4]
      let «head» = list.head()
      let «tail» = list.tail()
    
      let «myMap» : Map = ["MI" : "Michigan", "OH" : "Ohio",
                          "WI" : "Wisconsin", "IA" : "Iowa"]
      let value = «myMap8["MI"]»
      let «smallerMap» = myMap10 -- ["MI", "OH"]
      «smallerMap».contains("MI")
     	»Singly-linked list|You can create immutable singly-linked lists by using Array Literals.«
      »Singly-linked list|And of course you can access to its head: <code>Option(1)</code> (equivalent to Scala's headOption).«
      »Singly-linked list|Or its tail: <code>Option(List(2, 3, 4))</code> (equivalent to Scala's tailOption).«
      »Maps|Maps are immutable dictionaries, very much alike Scala's. There are a lot of ways to create maps, but using Dictionary Literals makes it clearer. Not only you can use Strings for keys, also Ints or Floats if it suits you.«
      »Maps|Accessing a value by key works the same as Swift dictionaries, and it will return an optional with the value or a nil, in our example: <code>Optional(Michigan)</code>.«
      »Maps|There are several ways to remove keys in maps, based on Scala's syntax. In our example we're using the <code>--</code> operator to remove the keys contained in the array.«
      »Maps|There are many convenient methods included in our data-types. i.e.: to check for a specific key in your maps, you don't need to mess with Options. As we removed the <code>MI</code> key before, the result of this call to <code>contains</code> will be <code>false</code>«
    
  • Protocols like Traversable and Iterable will make it easier for you to expand the current data-types available. If you need to create a new data-type, just by implementing three methods your type will have access to the 40-something functions available in Second Bridge, which includes: map, reduce, filter, drop, dropWhile, take, takeWhile, groupBy, zip

      let vector : Vector<Int> = [1, 2, 3, 4, 5]
      let «mappedVector» = vector.mapConserve({$0 * 2})
      let «filteredVector» = vector.filter({$0 > 2})
      let «reducedVector» = vector.reduce(0, combine: {$0 + $1})
    
      let «droppedVector» = vector.drop(2)
      let «takenVector» = vector.take(3)
    
      let «groupByResult» = groupByT(vector,
                               ∫{(item: (Int)) -> HashableAny in
                                  if item % 2 == 0 {
                                      return "Evens"
                                  } else {
                                      return "Odds"
                                  }
      })
      »Traversables|<code>[2, 4, 6, 8, 10]</code>«
      »Traversables|<code>[3, 4, 5]</code>«
      »Traversables|<code>15</code>«
      »Traversables|<code>[3, 4, 5]</code>«
      »Traversables|<code>[1, 2, 3]</code>«
      »Traversables|<code>groupBy</code> takes a **Traversable** collection and a **partial function** to discriminate two sets of elements. In our example, we're asking <code>groupBy</code> to distinguish even and odd numbers in our vector. The result will be a **Map** containing two keys: "Evens" will contain a new vector with all the even items, and "Odds" will contain another one with all the odd items. It's really powerful!«
    
  • Partial functions are easily created with the |-> operator. We’ve also implemented operators for the orElse (|||>) and andThen (>>>) operations. By combining functions with these three operators, it’s really easy to create small blocks of computation.

      let «doubleEvens» = { $0 % 2 == 0 } |-> { $0 * 2 }
      let «tripleOdds» = { $0 % 2 != 0 } |-> { $0 * 3 }
      let «addFive» = ∫(+5)
    
      let «opOrElseOp» = doubleEvens |||> tripleOdds
      let «opOrElseAndThenOp» = doubleEvens |||> tripleOdds >>> addFive
    
      let «resultEven» = opOrElseOp.apply(3)
      let «resultOdd» = opOrElseOp.apply(4)
    
      let «resultAndThenOdd» = opOrElseAndThenOp.apply(3)
      let «resultAndThenEven» = opOrElseAndThenOp.apply(4)
      »Partial functions|<code>doubleEvens</code> is a partial function that multiplies a number by two if it's an even number (i.e.: it's not supported for odd numbers).«
      »Partial functions|<code>tripleOdds</code> multiplies all odd numbers by three.«
      »Partial functions|<code>addFive</code> is a regular function that adds 5 to every number.«
      »Partial functions|<code>opOrElseOp</code> describes the following block of computation: <code>if it receives an even number it doubles it and, if not, it triples it</code>; by using the <code>orElse</code> operator.«
      »Partial functions|<code>opOrElseAndThenOp</code> describes a more complex block of computation. Not only it describes the same operation as the previous block, but it also adds five to the result of it by using the <code>andThen</code> operator.«
      »Partial functions|<code>9</code>«
      »Partial functions|<code>8</code>«
      »Partial functions|<code>14</code>«
      »Partial functions|<code>13</code>«
    
  • Pattern matching more similar to Scala’s, based in partial functions. Now you’ll be able to receive values directly from a pattern matching block:

      let «matchTest» = match(
      {(item: Int) -> Bool in item == 0 } |-> {(Int) -> String in return "Zero"},
      {(item: Int) -> Bool in item == 1 } |-> {(Int) -> String in return "One"},
      {(item: Int) -> Bool in item == 2 } |-> {(Int) -> String in return "Two"},
      {(item: Int) -> Bool in item > 2 } |-> {(Int) -> String in return "More!"})
    
      «matchTest».apply(0)
      «matchTest».apply(1)
      «matchTest».apply(2)
      «matchTest».apply(666)
      »Pattern matching|Pattern matching in Swift is really powerful, but we were missing the ability of receiving a value from the pattern computation. In this case, we're matching integers to these four partial functions that describe our conditions, and each one of them returns a value. The final result will be the return value of the pattern that gets matched first. As in Scala's pattern matching you have to be careful to cover all possible patterns or include a final case for the rest of the values.«
      »Pattern matching|<code>Zero</code>«
      »Pattern matching|<code>One</code>«
      »Pattern matching|<code>Two</code>«
      »Pattern matching|<code>More!</code>«
    
  • We’ve included several Playgrounds in our first release to cover these and other uses of our new functions. We think that Playgrounds are a really great tool for both documenting and learning and we wanted users of Second Bridge to be able to get their hands dirty as soon as possible. Playing with and modifying the examples included in our framework is a great way to learn to use the included features.

How to use SecondBridge

You might be thinking, “This is the greatest thing ever!” Well, probably you’re not so enthusiastic… but maybe you’re interested on using Second Bridge to make your projects more functional. We’re supporting the CocoaPods dependency manager to make it really easy to implement. You can find detailed instructions for the install process in the README file in the project. Second Bridge is available for iOS 8.0 and higher.

Besides using CocoaPods we highly recommend to download the source code of the framework. It includes lots of useful information both in the Playground files and the unit tests for you to see how to use all the available features.

How to contribute

Although we’ve tried to pack our new framework with many useful features from Scala for its first release, we’re sure there’s a lot of useful stuff we’re missing. That’s why 47 Degrees wants YOU! Second Bridge is completely open-source, and it’s going to be awesome to see what the community can contribute. So, if you’re interested in Second Bridge and think that you’ve come up with a great feature to add, don’t hesitate and send us a PR. We’ll review and incorporate it to our code-base as soon as possible, and we’ll treat you to a pint of beer! (Well, in most cases probably just the former for logistic reasons…)

We’ve learned a lot during the development of this framework about both Scala and functional development in general in one side, and Swift on the other. We’re really looking forward to learning more by implementing new features and seeing what you and the community can contribute! If you’re interested in functional development on iOS and our take on it, give Second Bridge a try: download the source code to check the included Playgrounds and tests, incorporate it into your projects with CocoaPods, and throw a big party with all your friends and toast for our new framework! If you need further information, feel free to contact us on Facebook, Twitter, or in the comments section below.

blog comments powered by Disqus

Ensure the success of your project

47 Degrees can work with you to help manage the risks of technology evolution, develop a team of top-tier engaged developers, improve productivity, lower maintenance cost, increase hardware utilization, and improve product quality; all while using the best technologies.