Programming with ooc/Control
Conditionals
editConditional clauses are blocks of code that will only execute if a particular expression (the condition) is true.
if-else
editThe if-else statement is the simplest of the conditional statements. They are also called branches, as when the program arrives at an if statement during its execution, control will "branch" off into one of two or more "directions". An if-else statement is generally in the following form:
if (condition) { statement } else { other statement }
If the original condition is met, then all the code within the first statement is executed. The optional else section specifies an alternative statement that will be executed if the condition is false. Exact syntax will vary between programming languages, but the majority of programming languages (especially procedural and structured languages) will have some form of if-else conditional statement built-in. The if-else statement can usually be extended to the following form:
if (condition) { statement } else if (condition) { other statement } else if (condition) { other statement ... } else { another statement }
Optimizing hints
editWhen this program executes, the computer will check all conditions in order until one of them matches its concept of truth. As soon as this occurs, the program will execute the statement immediately following the condition and continue, without checking any other condition . For this reason, when you are trying to optimize a program, it is a good idea to sort your if-else conditions in descending probability. This will ensure that in the most common scenarios, the computer has to do less work, as it will most likely only have to check one or two "branches" before it finds the statement which it should execute. However, when writing programs for the first time, try not to think about this too much lest you find yourself undertaking premature optimization.
Having said all that, you should be aware that an optimizing compiler might rearrange your if statement at will when the statement in question is free from side effects. Among other techniques optimizing compilers might even apply jump tables and binary searches.
match
editOften it is necessary to compare one specific variable against several constant expressions. For this kind of conditional expression the match statement exists. For example:
match (x) { case 1 => walkTheDog() case 5 => launchNuke() case => selfDestruct() }
The last case here has an empty condition. It's called a catch-all case, which code will be executed in case none of the above cases are matched.
Unlike switch in C or Java, there is no need to break of a case explicitly with the break keyword. Only one case per match is only ever executed. This enforces simple designs, at the cost of some flexibility. For example, Duff's device can't be written in ooc.
However, in some ways, match is more flexible than a switch. For example, you can have a match without an initial condition:
match { case (x < 0) => -1 case (x > 0) => 1 case => 0 }
Here we define custom conditions inside the cases, rather than values to compare. The parenthesis are optional, but included here for the sake of readability. It behaves exactly as if we had written match (true) { on the first line.
Another difference with traditional switch statements is that a match can be used as an expression. In that case, it's evaluated to the value of the last statement in the case executed. It's a good idea to have a catch-all case when you use a match as an expression, so that there are no cases where the value is undetermined.
Finally, values are compared using the equality operator ==, which can — like any ooc operator — be overloaded. This means that match works with strings as well, which have == overloaded in the core sdk:
match (humor) { case "sad" => ohNoes() case "happy" => yay() case => bahHumbug() }
By overloading the == operator, it is possible to use any user-defined type in a match statement.
Unconditionals
editreturn
editreturn exits the current function, optionally passing to the outer scope any value you gave to it
return 42
return doesn't always have a value, it can also only simply be used to exit a function at any point
return
goto
editooc doesn't have a goto keyword. You can control the flow of loops with break and continue, and exit function via return. The ooc language thrives to be simple, and considers that goto doesn't belong to a high-level language. See Edsger Dijkstra's work for further reading [1].
Loops
editLoops allow you to have a set of statements repeated over and over again.
Endless loop
editThe endless loop is a loop which never ends and the statements inside are repeated forever. The term, endless loop, is a relative term; if the running program is forcibly terminated by some means beyond the control of the program, then an endless loop will indeed end.
while (true) { doSomething() }
Loop with condition at the beginning
editThis loop has a condition at the beginning. The statements are repeated as long as the condition is met. If the condition is not met at the very beginning then the statements inside the loop are never executed.
while (x < 5) { x = calculateSomething() }
Loop with condition in the middle
editSometimes you need to first make a calculation and exit the loop when a certain criterion is met. However when the criterion is not met there is something else to be done. Hence you need a loop where the exit condition is in the middle.
while (true) { x = calculateSomething() if (x > 5) { break } doSomething(x) }
Skipping iterations
editThe continue keyword can be used to zap the rest of the loop's body and go directly to the next iteration.
while (true) { x = calculateSomething() if (x == 5) { // skip the 5th step continue } doSomething(x) }
for loop
editQuite often one needs a loop where a specific variable is counted from a given start value up or down to a specific end value. You could use the while loop here — but since this is a very common loop there is an easier syntax available.
for (i in 1..11) { doSomething(i) }
Ranges are delimited by .. — You can store ranges and re-use them later, e.g.:
range := 1..11
// then, later: for (i in range) { doSomething(i) }
This works because 1..11 constructs a new Range, which is a cover type. Covers are explained in later chapters.
for allows to iterate through values of any types, as long as they implement the iterator method, returning an Iterator. For example, you can iterate over ArrayLists:
list := ["moody", "jolly", "bored"] as ArrayList<Int> for (state in list) { println(state) }
See also
editWikibook
editReferences
edit- ↑ Edsger Dijkstra (March 1968). "Go To Statement Considered Harmful" (PDF). Communications of the ACM. 11 (3): 147–148. doi:10.1145/362929.362947.
The unbridled use of the go to statement has as an immediate consequence that it becomes terribly hard to find a meaningful set of coordinates in which to describe the process progress. ... The go to statement as it stands is just too primitive, it is too much an invitation to make a mess of one's program.