
Swift – Why Annoying Is Good - embwbam
http://seanhess.github.io/2014/09/08/swift-why-annoying-is-good.html
======
munificent
> One new feature is Optional Typing. You can decide whether a variable is
> ever allowed to be null.

Ugh, Swift is really confusing terminology here. Swift has an "option" type,
like "Option" in Haskell and F#. It's a wrapper around an object that may or
may not be present. You can use that to avoid null-everywhere.

This is totally unrelated to "option _al_ typing", which is a style of static
type systems that support mixing typed and untyped code.

Alas, Swift called their option type "Optional" and then talks about "an
optional type".

~~~
ch
This is why I appreciate that Haskell calls this type 'Maybe'.

I think this better captures the types semantics. I mean, an 'Option' or and
'Optional' makes it seem like you are given a choice... but a 'Maybe' implies
more that what you are declaring exists only with some probability!

Q. Will this function give a result? A. Maybe.

Q. Will this function give a result? A. Option.

The choice is obvious.

~~~
eridius
The choice is only obvious because you tailored the question to the Haskell
type name. But that's not the question you're asking. The question is "What
result will this function give me?". The Haskell answer is "Maybe a". It will
give me something that might be an `a`? The Swift answer is "Optional<T>".
That makes a bit more sense than "Maybe".

The name makes even more sense when you talk about function arguments instead
of function result types.

Q. What argument does this take? A. Maybe a.

It takes an argument that might be an `a`?

Q. What argument does this take? A. Optional<T>

Still not natural english, but the interpretation here is a bit cleaner: It
takes an optional value of type `T`.

~~~
ch
I'm not sure I totally agree. Well I do agree that I tailored the question to
suit my point! But to your reply, I think you've changed the semantics of my
meaning.

My questions were more from the perspective of the caller, and even then it
was a bit abstracted from the actual type and implementation ... just more of
a conversational "Does it? Maybe!"

You're rephrasing is still looking at it from the caller, but now takes into
account the language semantics (which mine conveniently didn't :) ).

I would rephrase your questions, and look at them from the callee's
perspective: "Will I get an argument? Maybe!"

And really, shouldn't we be saying that the function takes Just a to ... and
takes Nothing to ... ?

Perhaps this has stretched as far as it might go. Maybe?

------
mikeash
It's been interesting and amusing to watch the reactions to Swift, especially
among those without much exposure beyond ObjC or JavaScript or similar. Many
people encounter difficulties and automatically blame the language, as a sort
of reflexive action to blame whatever changed last. Sort of like the classic,
"You removed that virus last week, and now the computer's on fire, so this is
your fault."

Regarding JSON, it is annoying to work with in Swift, but when you get down to
it, it's a fault of JSON in general and the available parsers in particular.
There ought to be ways to describe and validate the desired structure to the
parser, or failing that, ways to tell the parser to fetch a value of a
particular type and nicely produce an error if it doesn't match.

Pretty much as the article says, it's hard to work with JSON correctly in any
language, Swift just doesn't let you take the easy way out.

In the ideal language, anything that's hard to write is so because the problem
is hard. No language is ideal, but whenever we're working with _any_ new
language and something seems harder than it ought to be, we should at least
stop and wonder if maybe the "easier" languages we're comparing it to are only
easier because they let us do things wrong.

~~~
tel
You're probably already aware of this, but Haskell's JSON parser (named Aeson)
does exactly what you ask for. In particular, it can be operated in two modes:

1\. Untyped mode. Here we parse out values of type, amusingly, Value which
reflect the total, untyped structure of JSON. We can then express queries deep
inside of that structure and see what get's pulled out. For instance, using
the `lens-aeson` package

    
    
        v :: Value
        
        x :: Maybe Integer -- Maybe means it might fail
        x = v ^? key "foo" 
               . key "bar"
               . key "baz"
               . ix  3
               . _Integer  -- looks a bit like XPath, right?
    

2\. Typed mode. Now we suggest to Aeson that some of the types of our program
have direct translation into or from JSON (or both) and let the parser produce
these translations in a type safe way. For instance, should we have a type
like

    
    
        data Point = Point { x :: Double, y :: Double }
    

then we can introduce a translation like

    
    
         instance FromJSON Point where
           parseJSON = withObject "Point" $ \o ->
             Point <$> o .: "x"
                   <*> o .: "y"
    

which indicates that JSON objects of a syntax like `{"x": 1, "y": 1}` can be
parsed into `Point`s. Technically, the parser designed there is minimal in
that JSON objects with more fields can still be properly parsed, although that
can be fixed.

Finally, you can easily anoint your untyped mode XPath-like queries with typed
fragments. This is especially powerful if your typed fragments include untyped
JSON Value fragments _inside_ of them. It means that we can use lenses to dive
into an untyped JSON Value, parse some fragment of it into a Point in a type-
sensitive fashion, then dive further into that Point. If Points contained more
JSON values then that "further dive" could be untyped or typed again.

~~~
thinkpad20
I really wish that Aeson's lookups and fromJSON returned Eithers, and not
Maybes. If you try to parse a deeply nested structure represented in JSON, and
just get a Nothing back, it really doesn't help you very much. Having an
Either is much more helpful.

(If anyone is aware of a canonical library for this, let me know. I wrote my
own JSON library which has this functionality but it's not particularly robust
or performant).

~~~
koomi
Aeson's «fromJSON» returns a «Result» which is basically «Either String». Most
other functions operate on «Parser», which also includes an error message if
things go wrong.

The only functions returning «Maybe» are «decode» and friends, and those have
«Either String» variants.

You can use «modifyFailure» and «typeMismatch» (and the «with» wrappers) to
get more descriptive messages, without a bit of help they are quite useless.

------
georgemcbay
Go also has a set of "annoyances" (some close to the same, some totally
different from Swift) and while I was initially annoyed by some of them, over
time I've grown to really love Go for it because there is a payoff to the
annoyances (at least in Go, I don't have enough experience in Swift to say the
same):

If the code compiles, it _probably_ works. Not 100%, of course, it is always
possible you made some stupid logic error or an off-by-one, but in my
experience compared to any other language I've used (including a lot of C, C++
and Java not to mention dynamic languages), Go code that compiles is SO MUCH
more likely to be functionally correct, and I believe this is because it is
such a nag about code correctness and eliminating any ambiguity as to what the
programmer intended.

~~~
riffraff
what extra correctness does Go guarantee over Java?

I can imagine less concurrency bugs, but ATM I don't recall any particular
language feature that should prevent more bugs than any other statically typed
language of the last decade.

~~~
georgemcbay
With Java vs Go the little bits of forced correctness are more subtle than
they are compared to dynamic languages or some of the less "modern" static
languages (and less to do with types, though I could attempt to start a raging
debate over the merits of interfaces versus traditional OO), but they do still
exist. One example off the top of my head: if bracing.

Java:

    
    
      if (state) 
        doThis();
        doThat();
    

This type of error is not uncommon if you don't enforce really strict code-
style standards or some sort of linting step that isn't part of the language
proper.

Programmer A writes an if statement with one line because that's all that's
needed at the time, programmer B comes in to expand the logic and is either
just having a bad day or is more of a Python programmer dabbling in Java and
so doesn't automatically see the error. Then programmer B dev-tests the code,
but only when state == true, so he still doesn't notice the problem because he
was expecting both doThis and doThat to be called anyway.

In Go this is an explicit compile-time error, all if statements require
opening and closing curly braces. This is exactly the sort of thing, IMO, that
might seem like an annoyance to someone who "knows what they are doing and
just wants the compiler to stfu" (eg. younger, stupider me) but is, in the
long run, actually really helpful for software correctness.

~~~
riffraff
thanks for the example, it makes perfect sense to me.

That would be the same reason that when coding in java I moved from "how do I
disable warnings" to "how do we automate findbugs+checkbugs for all devs" :)

------
jorgeleo
TLDR: I just discover that strict type system are there for a reason

------
mpweiher
With all due respects to Stanley Elkin:

No, annoying is not good. Annoying is annoying.

Computer languages are there for me to get things done, not to get in my way.
Attempts to _force_ good behavior invariably fail. Burn some more midnight oil
to figure out how the language/library can deal with it.

I once saw someone write that the 1st and foremost goal of a language was to
disallow mistakes. That's nonsense. If it were, all we'd have to do is make a
non-functional programming language that can't do anything. So I guess sort of
the next step in functional programming?

~~~
Guvante
> Attempts to force good behavior invariably fail.

Except this isn't forcing good behavior, it is forcing being explicit. Go
ahead and use `!` it will work like you are used to.

> No, annoying is not good. Annoying is annoying.

Different strokes for different folks. I for one think avoiding ambiguity is
good given the ratio of code written to code read that most developers
experience in their day to day lives.

> I once saw someone write that the 1st and foremost goal of a language was to
> disallow mistakes.

You are misinterpreting that requirement. What you are doing is you are
forcing the choice to be made when you write the code. More flexible compilers
make the choice when designing the language.

Many people believe that you know best when writing the code so stopping you
there to correct it makes you avoid problems in the future, that is what
"disallow mistakes" means.

As I said it is perfectly valid to instead say "I think the writers of the
compiler have good enough defaults for these situations" but I for one don't
trust them that much.

~~~
mpweiher
>Except this isn't forcing good behavior, it is forcing being explicit. Go
ahead and use `!` it will work like you are used to.

That's not correct. `!` will _crash_ without recourse where ObjC simply
ignores the message and Java raises a catchable NPE.

~~~
Guvante
If you actually do a null check all of the languages work the same. Since in
all but the prototype cases you will be doing a null check does it really
matter?

> ObjC simply ignores the message

Don't quote this like a benefit please, it is a horrendous design.

> Java raises a catchable NPE

Only difference between this and a crash is in theory you can log. In the
majority of cases a NPE is bringing you down anyway.

~~~
mpweiher
>> ObjC simply ignores the message >Don't quote this like a benefit please, it
is a horrendous design.

Hmm..so the ? operator for optionals should removed from Swift?

