Hacker News new | past | comments | ask | show | jobs | submit login

It’s wise for a language to be parsimonious with syntactic constructs at first, and then gradually introduce concepts which seem like they should obviously be there.

Multiple trailing closures fit a common use case and seem like a natural extension of the language.




> wise for a language to be parsimonious with syntactic constructs at first

Absolutely.

But Swift wasn't parsimonious at first. Not even close. It unwisely rejected the parsimonious case and chose tremendous complexity.

Keywords? Or parens? Both! And we'll throw in a bunch of other stuff as well. And the weird case of having two keywords, one with a colon and one without, because we decided to make the keywords the names of the parameters. Sometimes.

And then afterwards they noticed that the parsimonious choice that they had initially rejected in favor of their much more complex choice was needed in addition to all that initial complexity.


Have you worked with Swift at all? Because the features you're complaining about aren't really difficult to understand in practice, and they're a major part of what makes Swift really clear and nice to work with.

> Keywords? Or parens? Both!

Why should they be mutually exclusive?

Swift's named parameters are great! For instance they allow for default parameters, which is something I really miss in Rust for instance where I have to use the builder pattern everywhere.

> And the weird case of having two keywords, one with a colon and one without, because we decided to make the keywords the names of the parameters. Sometimes.

Swift's rules for parameter naming are very simple, consistent, and easy to understand. Given the signature:

    func foo(first second: Type)
`first` is the name used outside of the function, or the keyword for this argument, and `second` is the name used inside the function, or the parameter name. If the two names are the same, the second name can simply be elided. So for instance this signature:

    func foo(x: Int)
Is just syntactic sugar for this:

    func foo(x x: Int)
It's super simple and something which every swift developer can pick up within minutes of starting their first tutorial. I don't really understand why you seem to getting so agitated over this non-issue.


> Have you worked with Swift at all?

Yes, regretfully.

>> Keywords? Or parens? Both!

> Why should they be mutually exclusive?

Because of parsimony. The comment I was replying to made the claim that the original Swift design war parsimonious. It wasn't.

> Swift's named parameters are great!

Named parameters are great. Swift's implementation of named parameters is deficient, and not parsimonious. Yes, even that design is better than not having named parameters, but once you have named parameters, you don't need the parens.


> once you have named parameters, you don't need the parens.

Can you share an example of what this would look like in practice? I'm having trouble thinking of how this syntax would work.


You can look at Smalltalk, which is a great example where names parameters without parens works great. But that doesn't mean that named parameters with parens are bad, yet that's what GP is suggesting. (For context, he's the designer/implementor of Obj-Smalltalk that runs on the Obj-C runtime.)


Thanks, here's an example I found:

    var a, b, c;

    ...
    a = b.fooBar(1, 2);
    c = a.fooBarBaz(1, 2, a);
vs

    |a b c|
    ...
    a := b foo:1 bar:2.
    c := a foo:1 bar:2 baz:a.
    ...
From: https://live.exept.de/doc/online/english/programming/stForJa...

The Smalltalk syntax is hard for me to parse, but it's probably just a familiarity thing. I remember when I first learned Swift I wasn't fond of not ending lines with semicolons. Now I dislike having to type them in languages where they're required.


Familiarity and, since it is based on words, not parens, the actual names matter. You're going to have a hard time parsing with foo bar baz, just like you are going to have a hard time parsing a sentence with made up words.

   1 to: 20 do:[ :i | Transcript show:i. ]  
or in Obj-S

   1 to: 20 do:{ stdout println:$0. }
The keyword syntax makes a LOT of other syntax unnecessary, and allows you to create APIs that read like DSLs.

https://youtu.be/Ao9W93OxQ7U?t=628


How do you chain function calls in smalltalk syntax? I think delineating the argument set for a single function is the main job parens fulfill.


You've nailed one of the few issues with keyword message syntax in Smalltalk-80.

While binary and unary messages chain w/o problems, it's not possible to disentangle two keyword messages:

     receiver msg1:arg1 msg2:arg1
is indistinguishable from

     receiver msg1:arg1 msg1:arg2
So ST-80 chooses the latter. If you mean the former, you have to parenthesize.

But not always, it turns out. If you actually chain messages to the same receiver, you can use the semicolon to chain those messages:

   myRect x:20;
          y:10;
          width:100;
          height:100.
This looks like the single message x:y:width:height: but is actually four separate messages, all sent to myRect. It makes additional compound messages, particularly setters, less necessary.

In Objective-S[1], you can use the pipe ("|") to chain message-sends that go to the result of the previous message, rather than its receiver. For example:

   self dictionariesForQuery: "select {column} from {table}" | collect | at:column.
Since Objective-S also supports dataflow, the similarity to Unix pipes is intentional, and it pretty much works semantically as well: the result of the previous expression gets piped into the next expression. Very intention-revealing. In fact, I've found it to be so useful in communicating the structure of expressions that I use it even when it's not strictly necessary, for example the second instance in the example above.

> delineating the argument set for a single function is the main job parens fulfill.

Right. Which is one of the many reasons why the case of Swift is so mind-boggling: there some of the parameters go inside the parens, some outside. I think you can make a good case for either all in or all out (better for all-out, IMHO, but whatever). But partly in and partly out?

[1] http://objective.st/


> It unwisely rejected the parsimonious case and chose tremendous complexity.

Swift's keyword syntax isn't complex at all.

> Keywords? Or parens? Both!

I know you like Smalltalk, but keywords and parens are used together in a lot of languages (e.g. Python) so it's a tested idea.

> And the weird case of having two keywords, one with a colon and one without, because we decided to make the keywords the names of the parameters. Sometimes.

You don't have two keywords, you have an optional variable name. It's intuitive at the first time you see it - you're phrasing makes it seem much more complex than it really is.

I think you're trying to imply that Swift isn't an elegant language with it's syntax fitting in a postcard, but that doesn't mean it's 'tremendous complexity'. This whole comment is a bit too harsh to Swift, calling the legitimate differences between Swift and Smalltalk as 'complexity'.


>> It unwisely rejected the parsimonious case and chose tremendous complexity.

> Swift's keyword syntax isn't complex at all.

Yes it is, particularly compared to the parsimonious options. Either parens or Smalltalk-style keywords can do the job, so you absolutely, positively do not need both.

Particularly, if you are going to have keywords, you just don't need parens. So it's already more complex than it needs to be (not parsimonious). Just explaining the various omitted or extra keywords takes 4 pages in the Swift book, the entire Smalltalk syntax fits on a Postcard.

What is complex or not obviously depends on what your baseline is. If it's C++, Swift might seem simple (though many disagree).

> (e.g. Python) so it's a tested idea.

The question was not whether it was tested, but whether it was a parsimonious design, which it is not. It was also not a good design, because it led to a number of follow-on problems that they had to incrementally fix while adding even more complexity.

Python is not a good comparison because they didn't really have a choice: they already had the paren syntax, which they could hardly deprecate.

However, choosing that design without a backwards compatibility restriction is unconscionable, IMHO, particularly if you already have a different keyword design all over your code-base. That's cutting off your nose to spite your face.

Anyway, even the baseline keywords-in-parens is complex and more complex than it needs to be (because it isn't parsimonious), but then you get follow-on problems: blocks inside parens are really ugly, so you add trailing closure syntax. Yet another special case, which is very different from arguments inside the parens. But then you discover that sometimes you need more than one trailing closure, and then you need yet another special case, the open-keyword-trailing-block syntax, which is different yet again.

Of course, instead of having 3-4 different syntactic mechanisms, you could have chosen just the one and not needed any of the others.

> You don't have two keywords, you have an optional variable name. It's intuitive at the first time you see it

No, it's absolutely positively not the least bit intuitive. And it makes no sense, because internal variable names have no business leaking to the interface. If you want to rename the names of your variables inside your method, it changes the signature! Not even C does this.

> that doesn't mean it's 'tremendous complexity'

Although the argument could be made, I wouldn't, not by itself, no. However, this is just one example of countless others, see for example Rob Rix, whom I quoted before:

Swift is a crescendo of special cases stopping just short of the general; the result is complexity in the semantics, complexity in the behaviour (i.e. bugs), and complexity in use (i.e. workarounds).

I also talk more about it here:

https://blog.metaobject.com/2015/05/i-am-jealous-of-swift.ht...

> is a bit too harsh to Swift,

Nope. The comment I replied to made the indefensible claim that Swift was parsimonious. Which it's not. Not even close.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: