Swiftformat: Add multiline function chains rule

Created on 20 Oct 2019  路  5Comments  路  Source: nicklockwood/SwiftFormat

Hi nicklockwood,

We're currently testing SwiftFormat to see if we can fully replace the current setup we have with Swiftlint right now.

I was looking for a replacement for multiline-function-chains

Chained function calls should be either on the same line or one per line.

I was planning on adding the rule with two options in the following weeks:

  • same line
  • one per line

I just wanted to make sure it makes sense.

Cheers

enhancement

Most helpful comment

@facumenzella sounds like a useful rule, but I would have thought that the most common use would be to prevent a mixture of same-line and multi-line in the same expression, in which case the rule shouldn't require any configuration options at all.

All 5 comments

@facumenzella sounds like a useful rule, but I would have thought that the most common use would be to prevent a mixture of same-line and multi-line in the same expression, in which case the rule shouldn't require any configuration options at all.

@facumenzella I would be interested in this rule as well. I haven't checked how Swiftlint handles it, but I would like to have some special treatment with Rx.

    .rx
    .tap
    .subscribe(onNext: {
         // Code here
     })

This code just looks shit. Perhaps some rule where short links in the chain do not get moved to the 2nd line? 馃

@lordzsolt That is interesting. The way I prefer to write rx, for example, is

button.rx.tap
    .disposed(by: bag)
    .map { /* some optional value */ }
    .skipNil    // <--- What about non functions/methods?
    .do(onNext: { [weak self] in self?.someSideEffect() })
    .subscribe(
        onError: { /*single line is preferable*/},
        onNext: {
            /*multiple lines if needed*/
        }
    )

So two things:
1) Sometimes it might be preferable to have some chained properties on the first line of the chain
2) There can easily be a property accessor in the chain, as in the case of skipNil above.

@lordzsolt That is interesting. The way I prefer to write rx, for example, is

button.rx.tap
    .disposed(by: bag)
    .map { /* some optional value */ }
    .skipNil    // <--- What about non functions/methods?
    .do(onNext: { [weak self] in self?.someSideEffect() })
    .subscribe(
        onError: { /*single line is preferable*/},
        onNext: {
            /*multiple lines if needed*/
        }
    )

So two things:

  1. Sometimes it might be preferable to have some chained properties on the first line of the chain
  2. There can easily be a property accessor in the chain, as in the case of skipNil above.

Yep, exactly :) I prefer writing it like that as well.
So there's quite a bit of nuance required in this rule 馃槃

@nicklockwood agree on not adding those options then.

@ryanmeisters @lordzsolt
I've been playing with your example, and I am being able to go from this:

button.rx.tap.disposed(by: bag).map { /* some optional value */ }.skipNil.skipNil2.do(onNext: { [weak self] in self?.someSideEffect() }).subscribe(
                onError: { },
                onNext: { }
            )

to this:

button
    .rx
    .tap
    .disposed(by: bag)
    .map {  }
    .skipNil
    .skipNil2
    .do(onNext: { [weak self] in self?
    .someSideEffect() })
    .subscribe(
          onError: {  },
          onNext: {  }
    ))

Inside blocks, the rule is applied as well

I also like to format rx code as you do, but I am not finding a way to achieve it. Would it make sense to play with an option like:

  • Allow first N chained and then go multiline

Even if I don't like my current result, I think I can live with it. Anyway, let me know your thoughts.

Was this page helpful?
0 / 5 - 0 ratings