Does Swift Allow Code Blocks Without Conditions/Loops to Reduce Local Variable Scope

Does swift allow code blocks without conditions/loops to reduce local variable scope?

You can use a do statement to create arbitrary scope in Swift. For example:

func foo() {
let x = 5

do {
let x = 10
print(x)
}
}

foo() // prints "10"

As per The Swift Programming Language:

The do statement is used to introduce a new scope and can optionally
contain one or more catch clauses, which contain patterns that match
against defined error conditions. Variables and constants declared in
the scope of a do statement can be accessed only within that scope.

A do statement in Swift is similar to curly braces ({}) in C used to
delimit a code block, and does not incur a performance cost at
runtime.

Ref: The Swift Programming Language - Language Guide - Statements - Do Statement

What does a do statement without catch block mean?

It's a new scope of code: thus you can use many do statements if you want to reuse a variable name. Like in the snippet in your question, the variables mars, sz and r exist in both scopes without errors.

A do statement may be labeled, which gives you the ability to get out of that scope:

scopeLabel: do {
for i in 0..<10 {
for j in 0..<20 {
if i == 2, j == 15 {
break scopeLabel
}
else {
print(i,j)
}
}
}
}

For more details, have a look here.

How to create local scopes in Swift?

Update: In Swift 2.0, you just use the do keyword:

do {
let label = UILabel()
self.addSubview(label)
self.titleLabel = label
}

This was true for Swift pre-2.0:

You can define something similar to this:

func locally(@noescape work: () -> ()) {
work()
}

And then use such a locally block as follows:

locally {
let g = 42
println(g)
}

(Inspired by locally in Scala's Predef object.)

UI: do { } in Swift

It's a labeled statement:

A labeled statement is indicated by placing a label on the same line
as the statement’s introducer keyword, followed by a colon.

and it can be used to break away from outsider scopes. An illustrative example is given here.

If the Swift 'guard' statement must exit scope, what is the definition of scope?

It is totally possible to do what you envision, it just happens to not be what that particular code does. return always exits a method, not the local scope. To do what you wish, you can use a label, and break:

func testGuardControlFlow () {

let x = 2
let y = 2

func embededFunc () {

breakLabel:
if y == 2 {

guard x == 1 else {
print("oops, number is not 1")
break breakLabel
}

print ("from in embededFunc")

}

print ("I still want this to print even if x != 1")
}

embededFunc()
print("Great, return still allows this to be printed.")

}

testGuardControlFlow()

To add on to vadian's answer:

guard forces you to exit the scope using a control transfer statement. There are 4 available to you:

  • return and throw both exit the function/method
  • continue can be used within loops (while/for/repeat-while)
  • break can be used in loops (while/for/repeat-while) to exit the immediate scope. Specifying a label to break to will allow you to exit multiple scopes at once (e.g. breaking out of nested loop structure). When using a label, break can also be used in if scopes.

Additionally, you may exit the scope by calling a function that returns Never, such as fatalError.

with or without [weak self]

The issue is that you’ve made customNetworker, the CustomNetworker, a local variable and you lose your strong reference to it as soon as this local variable falls out of scope. When the dataRequest(input:) method uses a [weak self] reference, it’s saying that you don’t want dataRequest(input:) to keep a strong reference to this CustomNetworker instance, either. As a result, with no strong references, the CustomNetworker will be deallocated.

You have a few alternatives:

  1. If you remove the [weak self] reference in the closure inside dataRequest(input:), then it will retain the CustomNetworker until the closure runs. As long as you don’t save this failureHandler (and other closures) as stored properties, you should be fine. But don’t just throw in a [weak self] because you read somewhere that you should always use weak references. Use weak references where you need to avoid strong reference cycles, which would not appear to be the case here.

  2. The other alternative is to refactor this code, moving this network request routine, dataRequest(input:) to some more long-lived object.

    E.g., we often have a long-lived network manager object that maintains the URLSession and has all these network related methods. Then, assuming you’re keeping a strong reference to this network manager instance elsewhere, you don’t need to worry about the object being deallocated when it falls out of scope. This also saves you from having to pass in the URLSession object for every request. A caller should not be dealing with these URLSession instances, anyway.

    For example, I often use a singleton network layer (kind of equivalent to URLSession.shared pattern):

    final class NetworkManager {
    static let shared = NetworkManager()

    private var session: URLSession = .shared // or create and configure this session as you need; but one session object is all you need

    private init() { }

    @discardableResult
    func performRequest(...) -> URLSessionTask {
    ...
    let task = session.dataTask(...) { [weak self] data, response, error in
    ...
    }
    task.resume()
    return task
    }
    }

    Then you can do things like:

    NetworkManager.shared.performRequest(...) { [weak self] ... in
    ...
    }
  3. The other alternative is to just keep a strong reference to this customNetworker variable (e.g. make it a property rather than a local variable). That will prevent the CustomNetworker object from falling out of scope and becoming nil because there are no more strong references to it.


Somewhat unrelated, but it would appear that you are creating a URLSession object when you instantiate your CustomNetworker object, and subsequently never invalidate it. This will leak. You should create a single URLSession object and use it for all subsequent network requests.

If you do create multiple URLSession objects, you must invalidate each one when you’re done with it (e.g., finishTasksAndInvalidate), or else you will leak. But if you just have one session that you keep alive for all future network requests (which is preferred), then that is not necessary.

Using curly braces to segregate a variable that I want to use multiple times in C++

This is a toy case obviously but this is a good practice and 'stand-alone' blocks are there for that purpose.
I happen to believe they're a better way to structure long functions than breaking it down into members which (in many cases) have no separate purpose.

In such a case you can provide a faster, clearer, safer program particularly if there's a comment (possibly one line) introducing each block.

However in this case you might consider:

    for ( bool cont(false);!cont;)

Which has the same effect. Variables declared in a for(.;.;.) statement are confined to the scope of that statement.

In this case you can dodge the whole variable with:

    for(;;) //<--- Canonical formulation for 'infinite' loop.
{
getline(cin, teststring);

if (teststring.length() >= 10)
{
cout << "Too long, try again: ";
}
else
{
cout << "Thank you.\n\n";
break; //<--- Escapes the loop.
}

}

Footnote (in response to comments):

You should regard a for loop as 'syntactic sugar' on a while loop. That is no different in their performance, etc. and just pick the one that reads best. for(;cond;) just looks funny.

There may be a tiny (tiny) performance benefit to break but I happen to think it's actually simpler and more readable in many cases.

If the code were more complex there might be more 'loop end' code so it becomes:

for(bool cont(false);!cont;) {

//Complex code with multiple 'exit' conditions...

if(!cont) {
//Go round again code that won't fit nicely in last term of for loop...
}
}

Whereas using break just makes a 'swift exit' easier to understand.
They're not (widely) considered to have the 'bad karma' of goto because they 'go to' a very clearly defined point of execution.

Modifying a semaphore stored in an instance variable from within an Objective-C block

The important semantic distinction here is that when you use the ivar directly in the block, the block takes a strong reference to self. By creating a local variable that refers to the semaphore instead, only the semaphore is captured (by reference) by the block, instead of self, reducing the likelihood of a retain cycle.

As for the __block qualifier, you'd normally use that to indicate that a local variable should be mutable within the referencing block. However, since the semaphore variable is not mutated by the call to signal, the qualifier isn't strictly necessary here. It still serves a useful purpose from a style perspective, though, in the sense that it emphasizes the lifetime and purpose of the variable.

On the topic of why an ivar can be qualified with __block,

why would Clang allow this if it shouldn't be done?

Perhaps exactly because capturing an ivar in a block implies strongly capturing self. With or without a __block qualifier, if you use an ivar in a block, you're potentially running the risk of a retain cycle, so having the qualifier there doesn't create additional risk. Better to use a local variable (which, by the way, could be a __weak reference to self just as easily as a __block-qualified reference to an ivar) to be explicit and safe.

Is it a bad practice to use an if-statement without curly braces?

The problem with the first version is that if you go back and add a second statement to the if or else clauses without remembering to add the curly braces, your code will break in unexpected and amusing ways.

Maintainability-wise, it's always smarter to use the second form.

EDIT: Ned points this out in the comments, but it's worth linking to here, too, I think. This is not just some ivory-tower hypothetical bullshit: https://www.imperialviolet.org/2014/02/22/applebug.html



Related Topics



Leave a reply



Submit