# Ling tutorial Ling is a very simple language, where we take only most important and popular features from other scripts and languages. In particular, we adopt _principle of minimal confusion_[^1]. In other word, the code usually works as expected when you see it. So, nothing unusual. # Expressions and blocks. Everything is an expression in Ling. Even an empty block: { // empty block } >>> void Block returns it last expression as "return value": { 2 + 2 3 + 3 } >>> 6 Same is without block: 3 + 3 >>> 6 If you don't want block to return anything, use `void`: { 3 + 4 void } >>> void Every construction is an expression that returns something (or `void`): val x = 111 // or autotest will fail! val limited = if( x > 100 ) 100 else x limited >>> 100 You can use blocks in if statement, as expected: val x = 200 val limited = if( x > 100 ) { 100 + x * 0.1 } else x limited >>> 120.0 When putting multiple statments in the same line it is convenient and recommended to use `;`: var from; var to; from = 0; to = 100 >>> void Notice: returned value is `void` as assignment operator does not return its value. We might decide to change it. Most often you can omit `;`, but improves readability and prevent some hardly seen bugs. So the principles are: - everything is an expression returning its last calculated value or `void` - expression could be a `{ block }` ## Expression details It is rather simple, like everywhere else: val x = 2.0 // sin(x * π/4) / 2.0 >>> 0.5 See [math](math.md) for more on it. Notice using Greek as identifier, all languages are allowed. # Variables Much like in kotlin, there are _variables_: var name = "Sergey" Variables can be not initialized at declaration, in which case they must be assigned before use, or an exception will be thrown: var foo // WRONG! Exception will be thrown at next line: foo + "bar" Correct pattern is: foo = "foo" // now is OK: foo + bar This is though a rare case when you need uninitialized variables, most often you can use conditional operatorss and even loops to assign results (see below). # Constants Same as in kotlin: val HalfPi = π / 2 Note using greek characters in identifiers! All letters allowed, but remember who might try to read your script, most likely will know some English, the rest is the pure uncertainty. # Defining functions fun check(amount) { if( amount > 100 ) "enough" else "more" } >>> Callable@... Notice how function definition return a value, instance of `Callable`. You can use both `fn` and `fun`. Note that function declaration _is an expression returning callable_. There are default parameters in Ling: fn check(amount, prefix = "answer: ") { prefix + if( amount > 100 ) "enough" else "more" } >>> Callable@... ## Closures Each __block has an isolated context that can be accessed from closures__. For example: var counter = 1 // this is ok: coumter is incremented fun increment(amount=1) { // use counter from a closure: counter = counter + amount } val taskAlias = fun someTask() { // this obscures global outer var with a local one var counter = 0 // ... counter = 1 // ... counter } >>> void As was told, `def` statement return callable for the function, it could be used as a parameter, or elsewhere to call it: // call the callable stored in the var taskAlias() // or directly: someTask() If you need to create _unnamed_ function, use alternative syntax (TBD, like { -> } ?) # Flow control operators ## if-then-else As everywhere else, and as expression: val count = 11 if( count > 10 ) println("too much") else { // do something else println("just "+count) } >>> too much >>> void Notice returned value `void`: it is because of `println` have no return value, e.g., `void`. Or, more neat: var count = 3 println( if( count > 10 ) "too much" else "just " + count ) >>> just 3 >>> void ## while Regular pre-condition while loop, as expression, loop returns it's last line result: var count = 0 while( count < 5 ) { count = count + 1 count * 10 } >>> 50 We can break as usual: var count = 0 while( count < 5 ) { if( count < 5 ) break count = count + 1 count * 10 } >>> void Why `void`? Because `break` drops out without the chute, not providing anything to return. Indeed, we should provide exit value in the case: var count = 0 while( count < 5 ) { if( count > 3 ) break "too much" count = count + 1 count * 10 } >>> too much ### Breaking nested loops If you have several loops and want to exit not the inner one, use labels: var count = 0 // notice the label: outerLoop@ while( count < 5 ) { var innerCount = 0 while( innerCount < 100 ) { innerCount = innerCount + 1 if( innerCount == 5 && count == 2 ) // and here we break the labelled loop: break@outerLoop "5/2 situation" } count = count + 1 count * 10 } >>> 5/2 situation ### and continue We can skip the rest of the loop and restart it, as usual, with `continue` operator. var count = 0 var countEven = 0 while( count < 10 ) { count = count + 1 if( count % 2 == 1) continue countEven = countEven + 1 } "found even numbers: " + countEven >>> found even numbers: 5 `continue` can't "return" anything: it just restarts the loop. It can use labeled loops to restart outer ones: var count = 0 var total = 0 // notice the label: outerLoop@ while( count < 5 ) { count = count + 1 var innerCount = 0 while( innerCount < 10 ) { innerCount = innerCount + 1 if( innerCount == 10 ) continue@outerLoop } // we don't reach it because continue above restarts our loop total = total + 1 } total >>> 0 Notice that `total` remains 0 as the end of the outerLoop@ is not reachable: `continue` is always called and always make Ling to skip it. The label can be any valid identifier, even a keyword, labels exist in their own, isolated world, so no risk of occasional clash. Labels are also scoped to their context and do not exist outside it. # Comments // single line comment var result = null // here we will store the result >>> void # Integral data types | type | description | literal samples | |--------|---------------------------------|---------------------| | Int | 64 bit signed | `1` `-22` `0x1FF` | | Real | 64 bit double | `1.0`, `2e-11` | | Bool | boolean | `true` `false` | | String | unicode string, no limits | "hello" (see below) | | Void | no value could exist, singleton | void | | Null | missing value, singleton | null | | Fn | callable type | | ## String details ### String operations Concatenation is a `+`: `"hello " + name` works as expected. No confusion. ### Literals String literal could be multiline: "Hello World" though multiline literals is yet work in progress.