Swift vs C# - My take
Inspired by this comparison of Swift and C# I’ve put together my own list of my favourite features of each language.
My day job is a .NET developer, and I know C# and its pitfalls quite well. I’ve been playing with Swift as soon as it was released.
Throughout these examples I’ll be concentrating on the syntax, I may leave some details unimplemented.
Nulls / Nils
In Swift nil-valued objects are opt-in. You cannot pass a nil unless the function or property allows it.
C# - you’ll get an error at run time
public void DoImportantThings(string cannotBeNull)
{
if (cannotBeNull == null)
{
throw new InvalidArgumentException(...)
}
}
public void SillyMethod()
{
DoImportantThings(null);
}
Swift - you’ll get an error at compile time
func doImportantThings(string : cannotBeNull) { ... }
func sillyMethod() { doImportantThings(nil) }
This is fantastic! So many errors are caused by unexpected nulls, and that whole set has been eliminated! Next I can hope for a language with built in data validation.
Closures
Lets pick list sorting as an example
C#
myList.Sort((a, b) => a.CompareTo(b))
Swift
myList.Sort { $0 < $1 }
Personally I’m uncertain about Swift’s implicit argument names, but I think it’ll stick for small functions.
Now say we want to reuse that sorter. Idiomatic C# would break it out in to a method call
private int MySort(int a, int b)
{
a.CompareTo(b);
}
...
myList.Sort(MySort)
or you could use a function variable, but that breaks type inference
Func<int, int, int> mySort = (a, b) => { a.CompareTo(b) }
Swift does a bit better on the second count
let mySort = { (a : Int, b:Int) in a < b }
the return type is inferred, but since Swift lacks utomatic generalisation (F#‘s reference) it requires type annotations. Given the rest of the functional suite I hope auto generalisation comes to Swift
Data types
C# follows other C-based languages in data types. There are primitive types, functions, classes, structs and enumerations. Functions and closures are first class, which is great, but we’re still stuck with the old C/C++/Java ways of grouping things. I won’t go in to these here
Swift has a much richer set of types, and coupled with the pattern matching system this leads to better interaction
Tuples
While C# has tuples they’re just another class. This makes them somewhat hard to work with, for example C# to return multiple values:
public Tuple<int, int> GetTwoInts()
{
return Tuple.Create(1, 2);
}
...
var items = GetTwoInts();
var item1 = items.Item1;
var item2 = items.Item2;
with Swift:
func getTwoInts() -> (int, int) { return (1, 2) }
...
let (item1, item2) = getTwoInts()
Enumerations
In C# enumerations are simply names for integers. They always have a numeric value you can cast from.
Swift’s enumerations are really algebraic data types, also known as a tagged union. The values of an enumeration are not an alias for an integer, but a value in their own right. You can assign a number to an enumeration value you can also assign a string or any other value.
For even more power you can assign variable values to enumeration values. For example:
enum socketState {
Reading(string : buffer)
Writing(string : buffer)
Waiting(int : timeout)
}
switch (s : socketState) {
case socketState.Reading(let buffer):
return .Reading(buffer + readMore())
case socketState.Writing(let buffer):
return .Writing(write(buffer))
...
}
You can attach any sort of type to an enumeration value. This example also shows off enumeration decomposition to extract values out of the enum - you can also do this with tuples.
Switch statement
While C# lets you switch on constant strings as well as enumerations, Swift lets you match pretty much anything, acting like an if…else if chain, but including decomposition of tuples.
func getHttp(url : string) -> (int : status, string : statusMessage, string : body) {}
switch (getHttp("…")) {
case (404, let message, _) :
notFound(message)
case (403, _, _) :
doAuth()
case (200, _, let body) :
processBody(body)
}
While there are other ways of accomplishing this it is easier to manage state machine dispatches like this.
Also instead of C#’s infuriating compulsory break; on each statement and complete inability to fallthrough after doing some work, Swift takes a more pragmatic approach and breaks automatically unless you use the fallthrough keyword.
LINQ
One thing I love about .NET is LINQ, not just the nice operations on lists - which can easily be implemented in Swift - but also the ability to construct expression trees and interpret them at runtime. This allows a fantastic degree of expressiveness, especially when interacting with external systems.
Alas Swift doesn’t have anything like this so far, but with the algebraic data type as a first class member it’s easier to implement a DSL with an alright syntax. Hopefully this will be improved in the future.
Personally I’d like a fully metaprogramming model, macros rather than runtime interpretation.
Extensions
In C# we have extension methods - methods that behave like they’re part of a class, but really are static methods that take an instance as the first parameter.
Swift takes this one step further, extensions can add protocols (similar to a C# interface) to an extant type even without access to the implementation. You can also add computed properties and arbitrary functions. This makes it easy to add other types to your own protocols, and to hide internal mucking around from outside influence.
Visibility
Most languages have a concept of visibility for items - public, protected and private at least. So far Swift doesn’t have these, but it’s early days and I expect them to be implemented in the future.