# Operators

## Arithmethic Operators

### +

```imba
1 + 2 # 3
```

### -

```imba
3 - 1 # 2
```

### /

```imba
6 / 3 # 2
```

### \*

```imba
3 * 2 # 6
```

### %

```imba
5 % 2 # 1
```

### \*\*

```imba
2 ** 3 # 8
```

### -

```imba
-i # Unary negation
```

### +

```imba
+i # Unary plus
```

## Logical Operators

### &&

```imba
null && 10 # null
0 && 10 # 0
1 && 10 # 10
'' && 'str' # ''
```

The logical AND operator is true if all of its operands are true. The operator returns the value of the last truthy operand.

### and

```imba
null and 10 # null
1 and 10 # 10
```

Alias for `&&` operator

### ||

```imba
null || 10 # 10
0 || 10 # 10
1 || 10 # 1
```

The logical OR operator is true if one or more of its operands is true. The operator returns the value of the first truthy operand.

### or

```imba
null or 10 # 10
0 or 10 # 10
1 or 10 # 1
```

Alias for `||` operator

### ??

```imba
null ?? 10 # 10
0 ?? 10 # 0
'' ?? 'str' # ''
```

The nullish coalescing operator `??` is a logical operator that returns its right-hand side operand when its left-hand side operand is `null` or `undefined`, and otherwise returns its left-hand side operand.

### !

```imba
let a = true
!a # false
!10 # false
!0 # true
```

## Comparison Operators

### ==

```imba
x == y # Equality
```

### !=

```imba
x != y # Inequality
```

### ===

```imba
x === y # Strict equality
```

### is

```imba
x is y # Loose equality (==), with support for custom matchers
```

> `is` compiles to `x == y`, with a fallback that lets the right-hand value customize matching by implementing a `Symbol.for('#matcher')` method. Use `===` if you need strict equality.

### !==

```imba
x !== y # Strict inequality
```

### isnt

```imba
x isnt y # Negation of is - loose inequality
```

> `isnt` is the negation of `is`, so it also uses loose equality. Use `!==` if you need strict inequality.

### >

```imba
x > y # Greater than
```

### >=

```imba
x >= y # Greater than or equal
```

### <

```imba
x < y # Less than
```

### <=

```imba
x <= y # Less than or equal
```

### isa

```imba
honda isa Car #
```

The `isa` operator tests whether the prototype property of a constructor appears anywhere in the prototype chain of an object. Alias for the javascript [instanceof](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/instanceof) operator.

If the right hand side is a string, `isa` will check `typeof` instead:

```imba
let s = 'hello'
typeof s is 'string' # true
s isa 'string' # true
```

It can also check against multiple types at once:

```imba
7 isa ('string' or 'number') # true
```

### !isa

```imba
princess !isa Car
```

### typeof

```imba
typeof item
```

## Assignment Operators

### =

```imba
a = b
```

### ||=

```imba
a ||= b # If falsy assignment
```

### &&=

```imba
a &&= b # If truthy assignment
```

### ??=

```imba
a ??= b # If null assignment
```

### +=

```imba
a += b # Addition assignment
```

### -=

```imba
a -= b # Decrement assignment
```

### \*=

```imba
a *= b # Multiplication assignment
```

### /=

```imba
a /= b # Division assignment
```

### %=

```imba
a %= b # Remainder assignment
```

### \*\*=

```imba
a **= b # Exponential assignment
```

### ++

```imba
a++ # Increment assignment, returns original value
```

### --

```imba
a-- # Decrement assignment, returns original value
```

### ++

```imba
++a # Increment assignment, returns incremented value
```

### --

```imba
--a # Decrement assignment, returns decremented value
```

### =?

```imba
let object = {}
let input = 200
if object.value =? input
    yes
```

Regular assignment that returns true or false depending on whether the left-hand was changed or not. More concise way of doing:
```imba
let object = {}
let input = 200
if object.value != input
    object.value = input
    yes
```
The reassignment may seem unnecessary at first, but since memoization is an oft-used pattern in Imba, this is a very convenient addition.

## Bitwise Operators

### &

```imba
a & b # Bitwise AND
```

### !&

```imba
a !& b # Bitwise NOT AND
```

> Essentially the same as `(a & b) == 0`

### |

```imba
a | b # Bitwise OR
```

### ^

```imba
a ^ b # Bitwise XOR
```

### ~

```imba
~ a # Bitwise NOT
```

### <<

```imba
a << b # Left shift
```

### >>

```imba
a >> b # Sign-propagating right shift
```

### >>>

```imba
a >>> b # Zero-fill right shift
```

### <<=

```imba
a <<= 1 # Left shift assignment
```

### >>=

```imba
a >>= 1 # Right shift assignment
```

### >>>=

```imba
a >>>= 1 # Unsigned right shift assignment
```

### &=

```imba
a &= 1 # Bitwise AND assignment
```

### |=

```imba
a |= 1 # Bitwise OR assignment
```

### ~=

```imba
a ~= 1 # Bitwise NOT assignment (unassignment)
```

### ^=

```imba
a ^= 1 # Bitwise XOR assignment
```

### |=?

```imba
const STATES = {LOADED: 2}
let data = {state: 0}

if data.state |=? STATES.LOADED
    yes
```

Bitwise OR assignment that returns true only if the bit(s) was not previously set. Essentially a concise way to do

```imba
const STATES = {LOADED: 2}
let data = {state: 0}

if (data.state & STATES.LOADED) == 0
    data.state |= STATES.LOADED
    # do something here...
```

### ~=?

```imba
const STATES = {LOADED: 2}
let data = {state: 0}

if data.state ~=? STATES.LOADED
    # went from loaded to not loaded
```

Bitwise unassignment that unsets the right-hand bits from left-hand value and returns true / false depending on whether this actually changed the left-side or not.

```imba
const STATES = {LOADED: 2}
let data = {state: 0}

if (data.state & STATES.LOADED) == 0
    data.state |= STATES.LOADED
    # do something here...
```

### ^=?

```imba
a ^=? 1 # Bitwise XOR assignment
```

## Optional chaining

Imba uses `..` for [optional chaining](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining). If the optional reference is nullish it will return undefined.

```imba
let object = {one: {value: 1}}
console.log object..two..value
# undefined
console.log object.two.value
# TypeError: Cannot read property 'value' of undefined
```

## Keywords

### delete

```imba
let object = {one: 1, two: 2}
delete object.one
```

### class

```imba
class Game
	turn
	tiles
	moves
	winner

	def constructor
		moves = []
		tiles = new Array(9)
		turn = 0
```

### switch

```imba
switch status
    when "completed"
        console.log "This project has been completed"
    when "archived"
        console.log "This project has been archived"
    else
        console.log "This project is active"
```

### for

```imba
for num in [1,2,3]
	num * 2
```

```imba
for item in items
	<li> item.name
```

```imba
for item, i in items
	<li> "{i+1}: {item.name}"
```

### get

```imba
class Item
    price = 100
    taxRate = 20

    get totalPrice
        price * (1 + taxRate / 100)

    def render
        <self>
            <input bind=price>
            <input bind=taxRate>
            <p> "Total: {totalPrice}" # 120

```

### set

```imba
class Item
    set name value
        console.log "The name has been set to", value
```

### def

```imba
  def multiply a, b
    a * b

  # default values
  def method name = 'imba'
    console.log param

  # destructuring parameters
  def method name, {title, desc = 'no description'}
    console.log name,title,desc
```

### attr

```imba
<form attr:id="product-form">
```

### tag

```imba
# Define a new global tag component
tag page-header
  ...
```

```imba
# Define a new local tag component
tag Header
  ...
```

### if

```imba
  if condition
	  console.log 'yes!'
```

### elif
```imba
if expr > 10
	console.log 'over 10'
elif expr > 5
	console.log 'over 5'
elif expr
	console.log 'not falsy'
```

### else

```imba
if condition
	console.log 'yes!'
else
	console.log 'no!'
```

### try

```imba
def fetch
    # adding a try without a catch block will silently swallow an erro
    try
      const result = await axios.get('my-api.com')
```

### catch

```imba
  def fetch
    try
      const result = await axios.get('my-api.com')
    catch e
      console.error "There was an error", e
```

### continue

```imba
let res = for num in [1,2,3,4,5]
	continue if num == 3
	num * 2
console.log res # [2,4,8,10]
```

```imba
# continue with an argument acts like early return within Array#map
let res = for num in [1,2,3,4,5]
	continue -1 if num == 3
	num * 2
# res => [2,4,-1,8,10]
```

### break

```imba
let res = for num in [1,2,3,4,5]
	break if num == 3
	num * 2
# res => [2,4]
```

```imba
# When supplying an argument to break
# this value will be added to the resulting array
let res = for num in [1,2,3,4,5]
	break -1 if num == 3
	num * 2
```

### return

```imba
 # In Imba the last statement is returned automatically
 def add a, b
   a + b
```

```imba
# But it can be useful for returning other values or early
def add a, b
  return 0 unless a && b
  a + b
```
