In Captain America: Civil War we get to see the ultimate battle between Iron Man and Captain America.
It is a battle of simple gutty defense vs. smart weapons and flashy offense, humility vs. brashness, down in the dirt vs. up in the clouds.
To totally geek it up, the same kind of battle exists in the languages that software engineers use today and I believe this is especially true in the battle of C# vs. Swift.
Don’t worry, this really isn’t a versus type write up. If anything I seek to point out each language’s unique strengths, then show how software engineers can get into the right superhero mindset to really use those strengths, and be aware of the weaknesses, to create great solutions.
C# = Iron Man – Strong Flashy Offense
C# is truly the Iron Man in this comparison. It is amazing how much showy weaponry C# can bring to bear to solve problems.
- Have a problem with your UI freezing up? Bring in Task<T> / async – await, and seamlessly refactor years old code to be fully asynchronous, even within native UIs where thread synchronization is key.
- Have a super large dataset that you need to tame? Bring in IEnumerable<T> / yield return or Lazy<T> from the deferred execution realm.
- Have a need to produce arrays and collections that are the result of super smart functional filtering? Bring in LINQ.
- Need to do smart filtering of XML? Bring XDocument and its magic LINQ over XML powers.
- Need to do JSON processing? Head on over to NuGet, reference Newtonsoft.JSON ,and get stable, powerful JSON serialize / deserialize behavior and be done in no time.
- Need to hit a REST service with super specific HTTP header formatting and authentication? System.Net.Http has you covered.
- Need a cross-platform way to retrieve data from remote sites + Model / View / View Model architecture? Check out ReactiveUI.
- Need async but inline immediate responses to collection changes? Check out Rx.NET.
- C# is strongly typed, but you can also use reflection and loosen that strong typing as needed.
- C# can even be used to generate itself.
There is every gadget and gizmo that you can bring in and bolt on to existing C# code to get your job done. Even the very oldest C# code from 2002 is still supported and easily transformed using Visual Studio, or Resharper tooling into something shiny and modern.
C# has all these weapons, but the lifetime of these weapons are sometimes mere seconds before they are replaced with the next version via NuGet. The masters of C#, just like Tony Stark, have no issue with throwing out just created stuff in favor of the next great thing.
C#’s weaknesses are the dreaded NullReferenceException and the indeterminate mutability of most data structures. C# is great at attacking problems, and hitting at the 90% of the solution in a lightning quick way. However, C# doesn’t play defense very well. If you go too fast too far with C# you can out run your air cover, leaving you vulnerable when attacked from the flanks by null members, timeout errors, weird data changes, unhandled exceptions, or not connected to network scenarios.
C# is a highly flexible, multi-weapon language that you can use to attack any problem.
Swift = Captain America – Strong Defense
Swift is the ultimate boots-on-the-ground and in-the-mud defensive language. In Swift you don’t solve problems by attacking them head on with whole armories of shiny weaponry, you hunker down, put your shield up, and start slogging up that hill one step at a time.
Every line of Swift code written requires the author to think of the worst case:
The inventors of Swift must have looked at the metrics of existing Objective-C iOS applications and realized that the number 1 and 2 problems were:
- Coders not realizing that the data they are changing on one screen leads to changes in data on other screens.
- App crashes due to trying to access the value behind a null pointer.
Defense was needed. The power of Captain America’s vibranium shield was needed, only this time wielded by coders to stop these major in-app issues.
Coding in Swift is highly defensive in nature. To see this in action take a look at Swift Optionals, if .. let syntax, and the class initialization rules. As you use them, Swift optionals will permeate your entire thinking as you rev up your data structures. Every variable you use and/or create needs to be immediately thought of in terms of optional vs. non-optional.
Within Swift the use of specific reference and value types allows you to defend against unwanted mutation to your data structures.
Each line of defensive code is one more brick piled on top of other bricks of defensive code. When done you end up with applications that resemble the Great Wall of China and are truly written for the worst case. This layered defensive code coordination leads to super solid software structure that can take a real beating when attacked by the invaders (or users) of the software.
When done solving the problem in Swift you have a beautiful shiny shield that can repulse almost any mutability or null data attack. Because you play so much defense in Swift, coding up solutions to things seems to take longer. In reality, you have taken all that defense that C# out ran and have incorporated it into the structure of the solution.
The constant nullability slog, coupled with the constant mutability slog, while coding in Swift leads the developer to wanting more weapons to go at problems. Constant defensive coding slog can lead to developer fatigue quite quickly. However, when the problem solution is achieved, the engineer can see that their defensive coding effort has been like using Captain America’s shield as their primary weapon.
With the future potential of Swift existing across platforms, it could mean more solidly crafted software across the board, from server side to mobile applications. The underlying thought process behind Swift is already starting to leak into other languages, especially in the area of nullability.
I know that Swift isn’t without its share of flashy bolt-on weapon systems. Comparing C# to Swift when it comes to third-party library support is like comparing Iron Man’s crazy spin laser and hand repulsors to any weapon Captain America has ever wielded (at least in the movies).
But who wins in the ultimate battle?
If you ask me, I think Captain America and Iron Man are both good guys who should be augmenting each other’s strengths and covering their corresponding weaknesses. I bet the *SPOILER* real big bad *SPOILER* is hiding behind the scenes and making them battle it out.
As with all things in software engineering there is never a clear winner. There are drawbacks and advantages to the structure, approach, and capabilities of all languages and constructs. These drawbacks and advantages tend to fit or not fit for solutions to given problems.
Good ideas tend to bubble to the top (i.e. delayed execution, in-language async, nullability enforcement, mutability enforcement), whereas bad ideas tend to settle to the bottom (i.e. garbage collection in Objective-C).
Swift is so new, the in-language concepts so hardened, the community so outspoken and willing to move quickly, that the verdict is not yet out.
C# has been around so long, has so much weaponry, and is currently so incredibly flexible across even dynamic and functional concepts. There is no way C# doesn’t continue to flex with some of the core concepts surfacing from the Swift and Kotlin worlds.
Who knows, one day you just might see Iron Man wielding Captain America’s shield. Just like C# currently wields dynamic and functional constructs, C# could well start to take on deep nullability constructs as they exist in Swift.
At the end of the day, we all win as these 2 languages battle, take on, and wield the best parts of each other to surface great solutions to real software problems.