
Go vs. Swift [pdf] - jakerockland
https://github.com/jakerockland/go-vs-swift/blob/master/go-vs-swift.pdf
======
chmike
I don't see any "strength" in the classical object oriented programming model
as found in C++ or Java. Actually, in modern programming composition is
considered superior to inheritance.

The interface concept of Go makes programming with composition much more
flexible and powerful than with the class model. The author skips this Go
specific and original interface typing. This provides a multiple inheritance
equivalent without all the complications on C++ and that most OO oriented
languages forbid because of that complication.

Go is a very original language in this aspect as well as with concurrency.
Understanding and mastering these properties goes beyond simple syntax
analysis.

To me the most remarkable property of Go is its simplicity. As I explained to
a friend who is a strong advocate of D, the difference with other programming
language is the same as dealing with a spoken language of 1000 words instead
of 10,000 words. It's true that the language with 10,000 words is more
expressive and richer. But the effort required to learn, read and write a
language of 1000 words is much lower than a with a language of 10000 words.
I'm beyond 50 years old, and too me this makes a huge difference. The best way
to express it is that _with Go programming is fun again_. I hope that Go will
preserve this simplicity. At the beginning Java was simple too. They later
killed it to the point I don't want to deal with Java code anymore.

~~~
unscaled
> Go is a very original language in this aspect as well as with concurrency

Actually it isn't.

Using object Composition/Aggregation is a very old, and composition as the
recommended paradigm dates back at least to COM (that's just my memory, it's
probably older). Granted, delegation in COM aggregates was based on
conventional interface and not structural typing, and it was implemented using
ugly C macros, but dynamic languages made it easier and far more flexible.
Kotlin even made it part of the language:
[https://kotlinlang.org/docs/reference/delegation.html](https://kotlinlang.org/docs/reference/delegation.html)

What Go has, despite all the hype, is not real composition with delegation
though, but a crippled form of inheritance. With proper composition, your
child objects are named, and you can choose which interfaces you want to
delegate to which object. This doesn't just give you better control over which
functionality you wish to expose, but also avoids conflict when two member
objects implement the same interface. In Go you essentially get the same nasty
diamond problem of multiple inheritance, with none of the benefits. Sure, you
can disambiguate your method calls, but you could do the same in C++ and
Python.

As for Go's approach for concurrency obviously isn't new. The CSP model was
implemented by Rob Pike in at least 3 different languages previous to Go
(Newsqueak, Alef and Limbo) and theory behinds it dates to research by Tony
Hoare in the late 1970s.

I won't argue with you that Go is simple, but it's not revolutionary. As for
the fun, I think that really depends on the individual. I know many people who
think Go is fun, but for others, like me, it's about as fun as fingernails on
chalkboard. There seem to be a strong correlation between people who like
functional programming (especially the ML camp, but also the LISP camp).

For me coding in Go is plain drudgery: error handling boilerplate, noisy
imperative looping (and in general very low SNR) and almost no ways to create
abstractions. Yeah, you can make very useful and down to earth software in
this language and it's currently satisfying much of my microservices needs at
work. But it isn't what I would call fun.

~~~
rakoo
> With proper composition, your child objects are named, and you can choose
> which interfaces you want to delegate to which object. This doesn't just
> give you better control over which functionality you wish to expose, but
> also avoids conflict when two member objects implement the same interface.

Oh but you can avoid that, it's part of the language, see this link:

[https://golang.org/doc/effective_go.html#embedding](https://golang.org/doc/effective_go.html#embedding)

Typically, you can have something like this:

    
    
        type lockedReader struct {
            io.Reader
            sync.Mutex
        }
    
        lr := lockerReader{someReader, sync.Mutex{}}
        lr.Lock()
        lr.Read(...)
        lr.Unlock()
    
    

By default, methods will be delegated to the first field that has the method.
If you want something else, you are free to override this default behavior.

~~~
unscaled
No they're not. io.Reader and sync.Mutex do not embed the same type and do not
have conflicting methods with the same name.

This is how a diamond looks like:

    
    
      type Base struct {
        Foo int32
      }
    
      type Child1 struct {
        Base
      }
    
      type Child2 struct {
        Base
      }
    
      type Diamond struct {
        Child1
        Child2
      }
    
      func (c *Child1) DoSomething() {
        fmt.Println(c.Foo)
      }
    
      func (c *Child2) DoSomething() {
        fmt.Println(c.Foo)
      }
    
      func main() {
        c := Diamond { }
        c.Foo = 42       // Doesn't Compile
        c.Child1.Foo = 10
        c.Child2.Foo = 20
        c.DoSomething()  // Doesn't Compile
      }

------
pawadu
I found the study very shallow and superficial. For example, who cares how
many people have starred a project on github? And why should I care how many
lines "hello world" is in a language [1]?

I would rather see a discussion about performance, platform support,
maintainability, governance and do on.

\---

[1] someone please create a new programming language where the empty file
means "print hello world". Since you can't do any better than that it would
once and for all put an end to this stupid benchmark.

~~~
hardwaresofton
The author notes here (in the HN thread) that it's a very very cursory
overview and there are plans to add more later given time. This could have
been a blog post (or series of blog posts), so maybe the academic-paper feel
was misleading.

While I'm not sure this content should be on the front page, it never was
represented as a very deep comparison. I do admit that when I read it through
I expected much more.

Also, how do you determine what libraries to use and what projects to invest
in these days? Do you always do a full audit of every project? I know I don't
have the time, so I use stars on a Github project just like one might use
word-of-mouth. If a ton of people think a thing is useful, it's probably at
least a little useful. Of course, that kind of thinking can be dangerous (see:
javascript ecosystem), but a lot of the time, it's "good enough".

BTW, the paper does cover a tiny bit of information regarding differences in
platform support when it covers how Swift deals with concurrency.

~~~
pawadu
> I know I don't have the time, so I use stars on a Github project just like
> one might use word-of-mouth.

Up to a certain point, stars can be useful as it helps you discover projects
other people have found of use. But saying project X is better than project Y
because it has more stars? What does it show other than more people using X
are on github or people using X a more prone to push the star button?

For reference, bootstrap has 100K stars, Linux has 40K...

~~~
hardwaresofton
Oh I definitely am not trying to imply you should use a project just because
it has more stars -- maybe the right term was "hype" instead of word-of-mouth

------
seanalltogether
The more I use swift, the more I've grown to appreciate the concept of
Optionals and how the compiler enforces it's usage. I have found that my swift
code is more robust and explicit than my ObjC or Android java code is, as well
as the team members around me.

~~~
wyager
> the more I've grown to appreciate the concept of Optionals

You may also enjoy a language that supports the generalization of Optionals,
which are Algebraic Data Types (ADTs). Optionals are a single, limited
application of ADTs.

Optionals allow you to shift null pointers (and null pointer exceptions) to
the type level. So instead of having to worry about a function returning null,
you just deal with Optionals whenever a function returns one.

There's another ADT, usually called "Either" or "Result", that allows you to
shift exceptions to the type level. You can see from the type of the function
what kind of exception it might return, and you deal with exceptions like any
other value instead of via a special exception handling mechanism.

~~~
ridiculous_fish
One of the things that makes Optional so pleasant in Swift is the syntax
support. This includes optional-chaining, if-let and guard-let unwrapping, and
some convenient operators.

For example, in Haskell, by default you can't compare an Optional with the
value it wraps: `5 == Just 5` fails. But in Swift this works like you would
want.

All that is to say that Options in Swift are a bit nicer than what you could
get with pure ADTs. It's a similar story for Swift's syntax-level error
handling vs type-level monadic error handling. (The downside of course is that
the compiler has to be specially taught about these - but maybe you want that
anyways, e.g. for Rust's null-pointer optimization.)

~~~
wyager
> This includes optional-chaining,

Haskell has bind (>>=) and do-syntax, rust has `and_then`. This is pretty
standard with any ADT-supporting language.

> if-let

Most languages with ADT support have good pattern matching that subsumes if-
let syntax and allows you to do other things as well. Swift's pattern
matching, such as it is, is a bit of a mess.

> guard-let unwrapping

Haskell has `guard` and `MonadFail`, which address the use cases for this in a
more principled way. `guard` for boolean matching (like equality) and
`MonadFail` for structural matching (like pattern matching on a constructor).

Rust has (?) and `try`, which are syntactic sugar around a simple match/return
statement that addresses most use cases of guard-let.

Obviously there are going to be small differences between this
implementations, but Swift doesn't really excel here.

> `5 == Just 5` fails.

As it probably should. Supporting such implicit casting could lead to some
obvious confusion and buggy behavior. Ideally, the fact that "a == b"
typechecks should indicate that "a" and "b" are of the same type.

In Haskell, you would just do `Just 5 == x` if you want to check that
something is, in fact, `Just 5`. If that really wasted a lot of space somehow,
you can define something like `x ==: y = Just x == y`.

~~~
comex
Rust copied 'if let' from Swift (~2 years ago) despite having decent pattern
matching; community consensus today is that it's highly worthwhile as a
feature. There have also been proposals to add 'guard let'. So, while I don't
have enough Swift experience to judge its ADT support overall, I wouldn't cite
those features as evidence that it's wanting. They might not be as natural in
traditional FP languages like Haskell, but they seem to fit pretty well in the
stylistic niche Rust and Swift (among other languages) have carved out.

edit: FWIW, there's some overlap between '?' and 'guard let', but not that
much. Using hypothetical Rust syntax, they'd overlap in this case:

    
    
        guard let Some(x) = foo else {
            return Err(GettingFoo);
        }
    

better expressed as

    
    
        let x = foo.ok_or(GettingFoo)?;
    

…but if you want to return something other than a Result, or the ADT being
matched on is something custom rather than Option/Result, there's no good way
to make '?' do the job.

~~~
Ericson2314
? is bind for Either monad if you squint.

`context(e?)` becomes `e >>= \x -> context(x)`

~~~
majewsky
You mean `e >>= context` ? ;)

~~~
Ericson2314
Hah!

I should have been clear about CPSing things first so I didn't need to eta-
expand :)

------
yvsong
Swift: better OO, syntax, IDE; Go: built-in concurrency;

Swift is a great joy for iOS development, where compatibility with Objective C
makes things smooth, and operation queues are good enough for concurrency.
Xcode is a big productivity booster. Good to break Swift's own backward
compatibility with new releases to keep innovation, while providing a quick
fix tool. Hope it will become a great server language too.

~~~
ajmurmann
I never understand the praise for XCode. I love the iOS specific features like
GUI creator out property explorer. But the text editor part is just awful
compared to anything else I've used (primarily JetBrains IDEs, but also vim,
sublime and some atom). On top of that it also has comparatively poor git
integration.

Edit: one thing I forgot is the very slow feedback at least when editing
Swift. For syntax error notifications to get updated sometimes takes tens of
second which can be very confusing.

~~~
jksmith
Yeah agree. While I've moved on, IMHO xcode was generally crap compared to dev
envs I used back in the friggin 90's, like Delphi or Topspeed. Not many on HN
know much about Delphi, but it set the gold standard for the desktop IDE.

Great thing about Go is you don't need much of an IDE because it's best to
just keep Go in its sweet spot, which is services. LiteIDE works great for Go-
small footprint,debugging, enough project management to get by. Just like with
everything else about Go, you can get a newbie dev going with the Go toolchain
actually producing something that works in hardly any time.

~~~
gurkendoktor
To add some anecdata, I know three people (myself included) who moved from
"playing with Delphi 5 as a student" into iOS dev. And I still feel that ObjC
in Xcode is (sadly) the best replacement for Delphi right now:

\- A stable and pragmatic language that interfaces well with the C world.

\- Nice separation of class interface/implementation; ARC is as easy as COM
was in Delphi; solid reflection/metaprogramming capabilities (e.g. enumerating
properties).

\- Compilation is fast enough on my 5y/o laptop.

\- A standard library that is so good that people never re-invent it.

\- The debugger works really well and is always-on (IntelliJ still has
separate "Run" and "Debug" buttons, facepalm).

\- IBDesignable/IBInspectable makes writing your own components as nice as it
was in Delphi: [http://nshipster.com/ibinspectable-
ibdesignable/](http://nshipster.com/ibinspectable-ibdesignable/)

The points above will probably fall apart with Swift, but right now it's not
actually too bad.

------
solidsnack9000
> Because concurrency is supported through an Apple API rather than being
> explicit in the language’s design, using it is currently very much coupled
> to iOS or macOS development.

I am not sure this is accurate, because libdispatch has been ported to Linux:

[https://github.com/apple/swift-corelibs-
libdispatch](https://github.com/apple/swift-corelibs-libdispatch)

They are "...early in the development of this project..." but server-side
frameworks use it.

~~~
jakerockland
This is one of the things I have marked as an issue to elaborate a bit more
on.

[https://github.com/jakerockland/go-vs-
swift/issues/8](https://github.com/jakerockland/go-vs-swift/issues/8)

Thanks for the link! :)

~~~
solidsnack9000
The two differences that I wonder about:

* What is the cost profile of Dispatch relative to the Go scheduler? It seems that Go programs suffer a slow down just to enable multi-threading, for example -- which is not unlike other systems (GHC at some time in the past) that have a similar model.

* Is Dispatch suitable for "millions of threads" ala Erlang? Hundreds of thousands of threads? Dispatch allows you to decide which queue to put things on; but also kind of requires it of you.

~~~
eridius
AIUI Dispatch is suitable for potentially hundreds of thousands of queues. It
doesn't spin up thousands of actual OS threads, instead it intelligently
manages a pool of OS threads and multiplexes the queues onto them. IIRC each
dispatch queue is around 100-200 bytes in size (while empty).

~~~
solidsnack9000
Yeah but I wonder about is, is the concurrency truly fine-grained and
scalable? For example, you want to do a map over an array of 1 million
elements. Can you dump a million blocks on a queue for a linear speed-up?

~~~
eridius
You could dump a million blocks in the queue, but that's probably too fine-
grained. Each block is an allocation and there's some amount of overhead to
executing blocks (though I've never measured how much). So unless each element
actually takes a long time to process, you probably want to batch it up into
larger segments. Dispatch has an API explicitly meant for this scenario (doing
concurrent work over an array of elements), which is dispatch_apply() in C or
DispatchQueue.concurrentPerform(iterations:execute:) in Swift, though the
block is just given an index and it has to do the legwork of reading the
correct elements from the input.

------
blario
Very basic comparison. Doesn't go into the quality of the generated code,
compiler speed or efficiency, etc.

~~~
melling
I would hope that Go is better in all of the above. It has been available for
much longer, and it's supported by a great team.

I want to know how the languages compare for writing code. Dos one make it
easier to write more succinct and correct code? Swift is missing concurrency
support until at least the next version, for example.

~~~
ridiculous_fish
Go's compiler emits naive code quickly. For example, parameters are always
passed on the stack.

Swift is built atop LLVM, and it emits code more slowly, but supports many
optimizations like hoisting, vectorization, etc. that Go does not currently
perform.

------
scotty79
Semi-related, side-by-side comparison of how common things are done in swift
and go:

[http://rosetta.alhur.es/compare/swift/go/#](http://rosetta.alhur.es/compare/swift/go/#)

------
danielparks
Go feels like a beefed up version of C.

Swift feels like a high level language with static typing.

Interestingly, Swift doesn't feel much like Obj-C.

~~~
SomeHacker44
With C you almost always know what you have, and can always cast it to
anything else you want (safely or otherwise).

With Go, I'm never sure what I have (pointer? reference? something other and
weird?), and can't cast things that should be castable.

Either way, I'd still rather take Haskell or Common Lisp, but I'd gladly take
C over Go after having used Go for a highly multithreaded communications
server.

------
c0ffe
I favored Swift over Go in a small project (developed in my freetime) because
it has template / metaprogramming support, and it calls destructors
inmediately on unreferenced objects.

Some things that can be improved:

* It needs more support / packages for Linux (and Windows maybe?). I was using Manjaro Linux, and around November 2016 (dont remember exactly), the existing packages in the AUR didnt work anymore.

* No built-in weak collections.

* No source subfolders for the same project when using the buit-in package manager (I dont know about Go in this matter).

------
coldcode
I use Swift every day and appreciate it a lot, while I have only cursory
experience in Go, mostly because it didn't have any real debugger support in
the past. But any comparison is rather shallow because at the moment they
don't really address the same target usage, and Swift is only minimally
supported on the server side where Go is generally used. Give it a couple
years and the comparison might be more meaningful.

Once Jetbrains Gogland is up and running I will be playing more with Go.

------
twoquestions
The analysis looked good to me, but I was only able to read it after I
downloaded it. I hate to be "that guy", but the Github pdf viewer brought
Chrome to its knees.

------
tonyedgecombe
I can't believe many people are making that choice, it strikes me the domains
of the two languages don't intersect very much.

------
alvil
It's not true that Go requires import "fmt" to print something.

~~~
jakerockland
I have a note about that:

> Note that Go does support a ‘println’ function that does not require import-
> ing from the standard library; however, this function reports to ‘stderr’,
> rather than ‘stdout’, and is not guaranteed to stay in the language 19.

------
waynecochran
No mention of functional programming and the idiomatic async calls using
closures made popular as of late by JS?

~~~
jakerockland
This paper definitely has a lot of room for elaboration and improvement. There
are some open issues in the repo for things I'd like to add at some point when
I have the time, feel free to open new issues if there are other things you
think are missing--I'm also welcome to contributions if you'd like to make a
PR.

------
zatkin
I'm confused as to why this piece was written using LaTeX.

~~~
jakerockland
Because it's nice to learn how to use new tools? Hadn't used LaTeX before and
saw this as a good learning opportunity for getting started. I'm confused as
to what is wrong with writing this piece with LaTeX?

~~~
anonfunction
I'm not who you're replying to but I was looking for some way to convert it to
an html page. It's unfortunate that the only readable copy is the pdf since it
cuts the code examples and renders poorly on my laptop.

~~~
tnecniv
Interesting, it renders fine on mine (not OP).

