9

How can I transfer control to a specific line in Swift code?

In Objective-C I would do something like the following, using goto

if(a==b)
{
    goto i123;
}
else
{
    goto i456;
}
NSLog(@"the not reachable point");
i123:
NSLog(@"line 123 is here");
int j = 5;
int x = 2+j;
i456:
NSLog(@"line 456 is here");

The only control transfer statements in Swift I could find were continue, break, fallthrough, and return

continue and break only work with loops; return and fallthrough don't transfer control this way.

What can I use?

EDIT:-

Julien__'s answer didn't actually solve my problem but it could be the only available option right now. so i have accepted the answer by Julien__

Pawan Joshi
  • 1,581
  • 3
  • 20
  • 40
  • 14
    OMG. Certainly there are cases where a goto is nice. But generally your code looks like FORTRAN from the 50s. – qwerty_so Feb 08 '15 at 18:34
  • 2
    This can easily cause undefined behavior, e.g. if you use the value of `x` after jumping to `i456:`. One goal of the Swift language was that the *compiler* can check if all variables are initialized before being used. – Martin R Feb 08 '15 at 18:53
  • 3
    I would say "use functions". `goto` was originally a workaround for a program without subroutines. – Sulthan Jan 24 '16 at 19:47
  • they say that using of `goto` is bad practices - in any language you make the code less readable – Vyachaslav Gerchicov Nov 16 '18 at 14:18
  • You can make more money for your family and yourself by coding faster using tricks of the trade like *judicious* use of goto. (says California grandpa in his 50th year of full-time programming) – Doug Null May 07 '21 at 18:34

8 Answers8

9

Perhaps a switch statement ?

switch (a==b){
default:
    NSLog(@"the not reachable point");
    fallthrough­
case true:
    NSLog(@"line 123 is here");
    int j = 5;
    int x = 2+j;
    fallthrough­
case false:
    NSLog(@"line 456 is here");
}

EDIT : Here is how you could go backward.

let START = 0
let STOP  = -1
var label = START

while(label != STOP){
    switch (label){

    default:
        label = START­

    case START:
        NSLog(@"the not reachable point");
        if a==b {
            label = 123
        } else {
            label = 456
        }

    case 123:
        NSLog(@"line 123 is here");
        int j = 5;
        int x = 2+j;
        fallthrough­

    case 456:
        NSLog(@"line 456 is here");
        fallthrough

    case STOP:
        label = STOP
    }
}

Wrap your code in a giant (but well organized) switch statement. You could even create a function named goto in order to modify the value of the label var.

Julien__
  • 1,962
  • 1
  • 15
  • 25
  • 2
    why -1 ? could you at least give a reason ? – Julien__ Feb 08 '15 at 18:39
  • actually my original code in objective is about 1500 lines long in which i am using goto statement very frequently. i have only used code in my question as example. btw, I have already thought about switch. but the problem with this is, it will fail when i will go back and forth using goto statement. – Pawan Joshi Feb 08 '15 at 18:45
  • 5
    @DemonSOCKET: I see your point. But here the problem is not that Swift has not a GOTO equivalent. The problem is that you are trying to use a paradigm (GOTO) that belongs to another era. I understand you have many lines of code that need to be ported to Swift but you should try to rewrite that code with a more modern approach. I would be very surprised if Swift had the GOTO equivalent you are looking for. IMHO. – Luca Angeletti Feb 08 '15 at 18:54
  • 1
    This only allows for forward goto. You can't jump backwards using `switch`. – Nikolai Ruhe Feb 08 '15 at 19:00
  • @NikolaiRuhe: I really don't think Apple inserted a GOTO instruction inside Swift and just renamed it. This paradigm simply is not available in Swift. And IMHO this is a good thing. – Luca Angeletti Feb 08 '15 at 19:05
  • @appzYourLife I totally agree. And that's the correct answer, b.t.w. – Nikolai Ruhe Feb 08 '15 at 19:22
  • @NikolaiRuhe I think you can using while. See my edit. – Julien__ Feb 08 '15 at 20:18
  • @Julien__ : I am starting to have a feeling that i am gonna have to stick with objective c for a while longer. its better if i don't port my code into swift. anyways I really appreciate the help – Pawan Joshi Feb 09 '15 at 08:58
  • Historically, the method you describe was used for the first proof that any program can be written without gotos. Except they didn't use a switch statement but a long chain if label == 1.. else if label == 2 .. else if label == 3... – gnasher729 Feb 25 '15 at 10:58
  • 1
    Switch statements can't run across multiple threads at once. GoTo allows you to manually control position in code while you jump from one thread to the next. (e.g. using GCD for delays in your script). – Albert Renshaw Nov 26 '15 at 04:21
8

Ummm..... Swift actually support label which can be use as goto for control flow but less flexible. The following code is from Swift the programming language :

gameLoop: while square != finalSquare {
    diceRoll += 1
    if diceRoll == 7 { diceRoll = 1 }

    switch square + diceRoll {
    case finalSquare:
    // diceRoll will move us to the final square, so the game is over
        break gameLoop
    case let newSquare where newSquare > finalSquare:
    // diceRoll will move us beyond the final square, so roll again
    continue gameLoop
    default:
    // this is a valid move, so find out its effect
        square += diceRoll
        square += board[square]
    }
}
print("Game over!")
Yuji
  • 156
  • 1
  • 5
  • A full discussion appears in [The Swift Programming Language (Swift 4.2): Labeled Statements](https://docs.swift.org/swift-book/LanguageGuide/ControlFlow.html#ID141) [accessed 13 Sept 2018] – leanne Sep 13 '18 at 18:13
  • `break loopLabel` and/or `continue myLoopLabel`??? That is just a copy of other high-level language's solution for the problem: "how to break outer loop from inner loop." – Top-Master Dec 21 '22 at 14:24
  • But a very optimistic person may consider it a backward-goto ;-) – Top-Master Dec 21 '22 at 14:25
2

It seems as if Swift doesn't want anyone to use goto statements. Probably to avoid spaghetti code that would be too hard to follow in the future.

One possible alternative is to use functions. Functions have names which have meaning and are easier to understand than mere line numbers.

2

For the sake of posterity:

  • The article goto in Swift clearly exemplifies how to implement goto style functionality, including warnings on why not to use them and a rationale for their absence in the language.

  • The article author also made it available as a Swift package called Goto.swift on GitHub.

Hitster GTD
  • 96
  • 1
  • 4
1

What about this?

var j : Int?
var x : Int?

if a == b {
    println("line 123 is here")
    j = 5
    x = 2 + j!
}
println("line 456 is here")
Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    Probably because this does not answer the question (How to transfer control to a specific line?). It's just a workaround for this specific case. – Nikolai Ruhe Feb 08 '15 at 18:44
1

In languages where it is available I don't think GoTo is always a bad thing. I'd never use it to jump up, down and around within a function. That causes no end of confusion. But I do like to use GoTo to give me a common exit point. Here's an example of what I mean (pseudo code) something like this:

func SomeFunction() -> Bool
{
    var iReturnValue = false;

    // Do some processing

    if(SomeCondition == true)
    {
        // return true;
        // No. Instead of having a return statement here.
        // I'd rather goto a common exit point.

        iReturnValue = true;
        goto ExitPoint;
    }

    // Do Some More processing

    if(SomeOtherCondition == SomeResult)
    {
        iReturnValue = false;
        goto ExitPoint;
    }

    //
    // More processing
    //

ExitPoint:
    // By having a common exit point I can do any
    // cleanup here and I've got a single return point
    // which I think makes my code easier to read.

    return iResultValue;
}

I know I could achieve the same thing with a few well placed braces but I just find a well used Goto makes life much simpler.

IanS
  • 141
  • 1
  • 7
0

Here is a closure ({...}()) approach:

let done = false
while !done {
    {
        for formantA in editedFormants {
            for formantB in editedFormants {
                if abs(formantA - formantB) < MIN_DISTANCE {
                    let newFormant = (formantA + formantB) / 2
                    editedFormants.removeAtIndex(editedFormants.indexOf(formantA)!)
                    editedFormants.removeAtIndex(editedFormants.indexOf(formantB)!)
                    editedFormants.append(newFormant)
                    editedFormants = editedFormants.sort()
                    return
                }
            }
        }
        done = true
    }()
}
William Entriken
  • 37,208
  • 23
  • 149
  • 195
0

I am sure your code could be refactored to avoid the use of goto. Alternatively, you can use functions within functions and still have access to outer parameters. For example,

func foobar(a: Int, b: Int) {

    func i123() {
        let j = 5
        let x = 2+j
        print("i123 x=\(x) b=\(b)")
    }

    func i456() {
        print("i456")
    }

    if a == b {
        i123()
    } else {
        i456()
    }
}
Alex Nolasco
  • 18,750
  • 9
  • 86
  • 81