Tarnish

Basic values

Tarnish is an experimental programming language styled as a modern "scripting" language, a la Perl, Python or Ruby.

      
        // booleans
        true; false;
        // numbers
        1.23e45; 0xA9F4; 0b11001001;
        // strings 
        "all strings are in double quotes";
        "strings
        can spread over
        multiple lines";
        "strings can have ${interpolated} values"
        // functions
        {|x| x + 1 }
        // plain objects
        { x: 1, y: 2 }
        // lists
        ["foo", "bar", "baz"]
      
    

Objects

      
        let point = {
          // properties
          x: 0,
          y: 1,
          // methods
          manhattan_distance (self, other) {
            (self.x - other.x).abs() + (self.y - other.y).abs()
          },
        }
        
        // accessing object properties & methods
        point.x // => 0
        point.manhattan_distance({ x: 2, y: 2 }) // => 3
                
        // by default, objects are not mutable or extensible
        point.x = 2 // panics
        point.z = 2 // panics
        
        // objects can have mutable properties
        let mut_point = {
          mut x: 0,
          mut y: 0,
        }
        mut_point.x = 2
        mut_point.x // => 2
        
        // immutable objects are compared structurally, but mutable objects are compared by reference
        { x: 0, y: 0 } == { x: 0, y: 0 }
        { mut x: 0, mut y: 0 } != { mut x: 0, mut y: 0 }
        
        // objects can be destructured & pattern_matched
        let { x, y } = point // => x = 0, y = 1    
        match point {
          case { x, y } {
            x + y
          }
          case _ {
            0
          }
        } 
        // => 1 
      
    

Lists & Collections

      
        let list = ["foo", "bar", "baz"]
        // indexing into lists
        list[0] // => "foo"
        list[100] // panics
        // calling list methods
        list.length() // => 3
        // lists are immutable
        list[0] = "xyzzy" // panics
        
        // lists can be destructured & pattern_matched
        let [first, second | rest] = list // => first = "foo", second = "bar", rest = ["baz"] 

        // Array: a mutable list
        let my_array = Array(["foo", "bar", "baz"])
        my_array[2] = "quux" // => array(["foo", "bar", "quux"])
        my_array.push("xyzzy") // => array(["foo", "bar", "quux", "xyzzy"])
        
        let Array([first, second | rest ]) = my_array // => first = "foo", second = "bar", rest = Array(["quux", "xyzzy"])

        // Map: a mutable key-value collection
        let my_map = Map([["foo", 1], ["bar", 2], ["baz", 3]])
        my_map["foo"] // => 1
        my_map["bar"] = 200 // => map([["foo", 1], ["bar", 200], ["baz", 3]])

        // map can insert new values, too
        my_map["quux"] = 4 // => map([["foo", 1], ["bar", 200], ["baz", 3], ["quux", 4]])
        
        let Map([["bar", bar_value]]) = my_map // => bar_value = 200
      
    

Enums

      
        enum Option {
          case None {
            then (fn) {
              Option.None
            }  
          }
          case Some (value) {
            then (value, fn) {
              fn(value)
            }
          }
        }
        
        let value = Option.Some(10)
        value.then({|value| Some(value + 1)}) // => Option.Some(11)
        None.then({|value| Some(value + 1)}) // => Option.None
        
        match value {
          case Option.Some(x) { x }
          case Option.None { 0 }
        } // => 10