Swift canceling rest of function - swift

Remember the good old days when End would stop everything and goto would take you somewhere without coming back? Well, "End" is essentially what I am trying to do, is cancel the rest of a function.
ie.
func function () {
x = 5
//code to cancel and stop function
x = 0
}
I want this to readout x = 5. The reason I want to do this is because I have numerous functions called from within functions. To keep it simple, is there anyway for this to happen?

From Apple (search for guard):
Early Exit
A guard statement, like an if statement, executes statements depending
on the Boolean value of an expression. You use a guard statement to
require that a condition must be true in order for the code after the
guard statement to be executed.
That would be:
func function() {
x = 5
guard <yourConditionToContinue> else {
return
}
// Code to be executed if <yourConditionToContinue> is met.
}

Related

Confused about Optional vs Default value -1

We are working in a Swift project. A function was there like,
fun getSleepAmmount() -> Int {
// calculate sleep time
// return value when valid
// else
return -1
}
My team member prefers the above function where caller needs to check with -1 which is not I am comfortable with. My suggestion is to redesign with nil return (although callers still need to check nullability) like,
fun getSleepAmmount() -> Int? {
// calculate sleep time
// return value when valid
// else
return nil
}
But my colleagues do not want to redesign. Which version of the functions is cleaner and why?
Obviously, nil is much cleaner. Because of -1 means nothing. This is just a magic word. It is difficult to support, refactor and handle this case.
Returning nil is a better solution instead of using any garbage or default value.
Returning any default value may in future clash with the actual result.
Also, there might be other developers dealing with the same code. So, using nil will have a better explanation than using -1.
Second is the better as youll do
if let v = getSleepAmmount() {}
But with First
let v = getSleepAmmount()
if v > 0 {}
Returning nil means this isn't a valid return while -1 may mean another thing that will be miss-understood by a new developer that checks the code
If there is code in the caller that should only run if there is a valid sleep amount, then optionals is the better and clearer way to go. This is exactly what guard let and if let are designed for:
guard let sleepAmount = getSleepAmount() { else return }
// do something with sleepAmount
An even better way would be to throw an error inside the function:
func getSleepAmmount() throws -> Int {
// calculate sleep time
// return when valid
// else
throw InvalidSleepAmount
}
Then
do {
let sleepAmount = try getSleepAmount()
// do something with it
} catch InvalidSleepAmount {
// error processing
}
(If you want, your function could throw different errors so the caller gets to know why the sleep amount is invalid, SleepTooShort, SleepTooLong, NoSleep etc)

How to check that a function always return a value (aka "doesn't fall off the end")?

I'm building a didactic compiler, and I'd like to check if the function will always return a value. I intend to do this in the semantic analysis step (as this is not covered by the language grammar).
Out of all the flow control statements, this didactic language only has if, else, and while statements (so no do while, for, switch cases, etc). Note that else if is also possible. The following are all valid example snippets:
a)
if (condition) {
// non-returning commands
}
return value
b)
if (condition) {
return value
}
return anotherValue
c)
if (condition) {
return value1
} else {
return value2
}
// No return value needed here
I've searched a lot about this but couldn't find a pseudoalgorithm that I could comprehend. I've searched for software path testing, the white box testing, and also other related Stack Overflow questions like this and this.
I've heard that this can be solved using graphs, and also using a stack, but I have no idea how to implement those strategies.
Any help with pseudocode would be very helpful!
(and if it matters, I'm implementing my compiler in Swift)
If you have a control flow graph, checking that a function always returns is as easy as checking that the implicit return at the end of the function is unreachable. So since there are plenty of analyses and optimizations where you'll want a CFG, it would not be a bad idea to construct one.
That said, even without a control flow graph, this property is pretty straight forward to check assuming some common restrictions (specifically that you're okay with something like if(cond) return x; if(!cond) return y; being seen as falling of the end even though it's equivalent to if(cond) return x; else return y;, which would be allowed). I also assume there's no goto because you didn't list it in your list of control flow statements (I make no assumptions about break and continue because those only appear within loops and loops don't matter).
We just need to consider the cases of what a legal block (i.e. one that always reaches a return) would look like:
So an empty block would clearly not be allowed because it can't reach a return if it's empty. A block that directly (i.e. not inside an if or loop) contains a return would be allowed (and if it isn't at the end of the block, everything after the return in the block would be unreachable, which you might also want to turn into an error or warning).
Loops don't matter. That is, if your block contains a loop, it still has to have a return outside of the loop even if the loop contains a return because the loop condition may be false, so there's no need for us to even check what's inside the loop. This wouldn't be true for do-while loops, but you don't have those.
If the block directly contains an if with an else and both the then-block and the else-block always reach a return, this block also always reaches a return. In that case, everything after the if-else is unreachable. Otherwise the if doesn't matter just like loops.
So in pseudo code that would be:
alwaysReturns( {} ) = false
alwaysReturns( {return exp; ...rest} ) = true
alwaysReturns( { if(exp) thenBlock else elseBlock; ...rest}) =
(alwaysReturns(thenBlock) && alwaysReturns(elseBlock)) || alwaysReturns(rest)
alwaysReturns( {otherStatement; ...rest} ) = alwaysReturns(rest)
So, after 5 hours thinking how to implement this, I came up with a decent solution (at least I haven't been able to break it so far). I actually spent most of the time browsing the web (with no luck) than actually thinking about the problem and trying to solve it on my own.
Below is my implementation (in Swift 4.2, but the syntax is fairly easy to pick up), using a graph:
final class SemanticAnalyzer {
private var currentNode: Node!
private var rootNode: Node!
final class Node {
var nodes: [Node] = []
var returnsExplicitly = false
let parent: Node?
var elseNode: Node!
var alwaysReturns: Bool { return returnsExplicitly || elseNode?.validate() == true }
init(parent: Node?) {
self.parent = parent
}
func validate() -> Bool {
if alwaysReturns {
return true
} else {
return nodes.isEmpty ? false : nodes.allSatisfy { $0.alwaysReturns }
}
}
}
/// Initializes the components of the semantic analyzer.
func startAnalyzing() {
rootNode = Node(parent: nil)
currentNode = rootNode
}
/// Execute when an `if` statement is found.
func handleIfStatementFound() {
let ifNode = Node(parent: currentNode)
let elseNode = Node(parent: currentNode)
// Assigning is not necessary if the current node returns explicitly.
// But assigning is not allowed if the else node always returns, so we check if the current node always returns.
if !currentNode.alwaysReturns {
currentNode.elseNode = elseNode
}
currentNode.nodes += [ ifNode, elseNode ]
currentNode = ifNode
}
/// Execute when an `else` statement is found.
func handleElseStatementFound() {
currentNode = currentNode.elseNode
}
/// Execute when a branch scope is closed.
func handleBranchClosing() {
currentNode = currentNode.parent! // If we're in a branch, the parent node is never nil
}
/// Execute when a function return statement is found.
func handleReturnStatementFound() {
currentNode.returnsExplicitly = true
}
/// Determine whether the function analyzed always returns a value.
///
/// - Returns: whether the root node validates.
func validate() -> Bool {
return rootNode.validate()
}
}
Basically what it does is:
When it finds an if statement is create 2 new nodes and point the current node to both of them (as in a binary tree node).
When the else statement is found, we just switch the current node to the else node created previously in the if statement.
When a branch is closed (e.g. in an if statement's } character), it switches the current node to the parent node.
When it finds a function return statement, it can assume that the current node will always have a return value.
Finally, to validate a node, either the node has an explicit return value, or all of the nodes must be valid.
This works with nested if/else statements, as well as branches without return values at all.

Swift: How do I wait until a variable has a certain value

I am trying to write code that waits until a variable equals a certain value. Here is the code I have written:
var i = 0
for i in 1...10 {
playtrial()
repeat {
} while (WasItCorrect=="")
WasItCorrect = ""
}
The idea is that the function will call playtrial, wait until the variable WasItCorrect has a value (other than ""), reset WasItCorrect, and then repeat (for a total of 10 times).
The code produces no errors. However, after plastral is done, the program seems to stop responding and does not allow any new input / button pressing.
I assume the problem is that my repeat/while loop goes forever and never gives a chance for anything else to happen and therefore other functions which change the value of WasItCorrect cannot run. As a VisualBasic 6 programmer who is just starting to learn Swift, I would guess I would need the Swift version of DoEvents. Is that true?
Any advice on how to fix this code would be greatly appreciated.
You can use didSet property of the variable. It will be called whenever the value changed.
var i = 0 {
didSet {
print("Hello World.")
if i == certainValue {
// do something
}
}
}

Using guard keyword

I have encountered numerous situations where a coder have used the guard keyword. And then later, in a seemingly almost identical situation the same coder in the same code does not use the guard keyword. I am aware that this may be a stupid question, so please don't bash it. When should I use the guard keyword and where shouldn't I?
Here is an example (there are many more). This is part of a script that is requesting data form an API.
//Here I am using guard
guard let json = json else {
//Now I am not using guard
if let error = error {
completion(.Failure(error))
} else {
//Error handling
}
return
}
Why not use the:
if let var1 = var1 {
//Keep on going
} else {
//Don't crash
}
syntax all the time instead of the guard syntax? At first glance it even seems to have more functionality, but I am certain that does not have to be the case.
One great benefit of the guard statement is that you know that if the condition is not satisfied then the execution flow gets stopped.
This is important for several reasons
Unwrapping
You can define unwrapped values which don't need a new scope { ... } to be available
func next(num:Int?) -> Int? {
guard let num = num else { return nil }
return num + 1
}
Readability
When you read the code you know that if the guard condition is not satisfied then the following lines won't be executed.
Semantics
You know a guard statement is there to check conditions required for the following block of code.
But I can replace every guard with an if
Sure. We could also replace every while and for with a goto in some languages. And we could always replace recursion with iteration (and viceversa).
But this doesn't necessarily means it is always a good idea.
Despite we can implement some behaviours with more then one programming "tool", we should still use the one that better fits that specific scenario.

SpriteKit SKAction.runBlock passing parameter issue

I'm experiencing some weird behavior using SKAction.runBlock. Basically I'm using the following syntax :
AnAction = SKAction.runBlock({ SomeFunction(SomeParameter) })
in a switch statement in which I have 100+ case
IDTargetSprite = FindTargetSprite()
TypeSprite = FindTypeSprite(IDTargetSprite)
switch TypeAction
{
...
case eTypeAction.DropBomb.rawValue:
ActionBuilt = SKAction.runBlock({ DropBomb(IDTargetSprite) })
case eTypeAction.DropStar.rawValue:
dParamsAction = LoadParamsAction()
ActionBuilt = SKAction.runBlock({ DropStar(IDTargetSprite, dParamsAction) })
...
}
This code is included in a loop at the beginning of the program in which I go over an array of TypeAction
for TypeAction in tTypeAction
{
// execute above code
}
then I execute the actions like this in another loop later :
switch TypeSprite
{
case eActionTarget.SpriteA.rawValue:
SpriteA.runAction(ActionBuilt)
case eActionTarget.SpriteB.rawValue:
SpriteB.runAction(ActionBuilt)
}
So far nothing unusual, except that it does not work and when I try to understand why I see that the parameter passed to the block is not good but in a very weird way : some times the parameter passed to the function in the block (IDTargetSprite or dParamsAction) does not have the right value inside the function called, it kept the value he just had in the previous iteration of the loop.
In these cases, if I look at the value of the parameter just before the runBlock lines, the value is right but when the action is executed the value found within the function called is not right anymore and equal to the value of the previous iteration of the loop.
I have founded a way (but not yet extensively tested) by doing this :
case eTypeAction.DropBomb.rawValue:
TempParam = IDTargetSprite
ActionBuilt = SKAction.runBlock({ DropBomb(TempParam) })
where I have to have a specific TempParam for each case...
Am I missing something obvious in the use of SKAction.runBlock or block in general ?
Found a quick way by passing constant instead of variable as parameters. So it works if I do like this :
case eTypeAction.DropStar.rawValue:
let dParamsAction = LoadParamsAction()
ActionBuilt = SKAction.runBlock({ DropStar(IDTargetSprite, dParamsAction) })