How To Use Lists
Print Hello World
Write Basic Syntax
Use Properties
Make An If Else Ladder
Make A Branch Statement
Declare Inits
Use Lists
Use Arrays
Make A Class Hierarchy
Use Nil And Nilable Types
Use Dynamic Typing
Declare Variable Number Of Args
Read And Write Files
Check Inheritance And Implementation
Customize Object Equality
Pass References To Methods
Translate Pseudo Code To Cobra 1
Translate Pseudo Code To Cobra 2
Implement IEnumerable 1
Implement IEnumerable 2
Iterate Through Recursive Data With Yield
Make A Collection Class
Declare Contracts
Threads
Win Forms
WPF
GTK
Qyoto
Access MySQL
XNA
Open TK
 
class HowToUseLists

    def main
        .basics
        .looping
        .literals
        .stringConversion
        .operators
        .methods

    def basics
        # a list literal starts with [ and ends with ]
        # elements are separated by commas
        ints = [1, 2, 3]
        
        # a list has a number of elements - the .count
        assert ints.count == 3
        
        # lists can be indexed with brackets, starting with 0
        assert ints[0] == 1 and ints[1] == 2 and ints[2] == 3
        
        # .last gives the last element
        assert ints.last == 3
        
        # out bounds is an exception
        expect ArgumentOutOfRangeException, print ints[5]
        
        # .get allows a default value to be returned if the index is out of bounds
        assert ints.get(3, -1) == -1
        
        # .get allows negative indexes where -1 is the last element
        # -2 is the second to last
        assert ints.get(-2) == 2
        
        # a negative index can still be out of bounds
        expect Exception, ints.get(-4)
        assert ints.get(-4, -1) == -1   # ...but you can provide a default value
        
        # lists can be compared
        assert ints == [1, 2, 3]

    def looping
        names = ['foo', 'bar', 'baz']

        # looping is easy
        for name in names
            assert name.length == 3
        
        # loop through a sorted version
        last = ''
        for name in names.sorted
            assert name > last
            last = name
        # the original list is unchanged
        assert names == ['foo', 'bar', 'baz']
        
        # loop through a reversed version
        for name in names.reversed
            assert name.length == 3
        # again the original list is unchanged
        assert names == ['foo', 'bar', 'baz']
        
        # get an index with each element
        order = []
        for i, name in names.numbered
            branch i
                on 0, assert name == 'foo'
                on 1, assert name == 'bar'
                on 2, assert name == 'baz'
            order.add(i)
        assert order == [0, 1, 2]
        
        # get an index with each element, but in reverse
        order = []
        for i, name in names.numberedDown
            branch i
                on 0, assert name == 'foo'
                on 1, assert name == 'bar'
                on 2, assert name == 'baz'
            order.add(i)
        assert order == [2, 1, 0]
        
        # loop through the indexes only because the list will be modified
        for i in names.count
            names[i] = names[i].toUpper
        assert names == ['FOO', 'BAR', 'BAZ']
    
    def literals
        # you've seen these above
        ints = [1, 2, 3]
        for i in ints, assert i > 0
        
        names = ['foo', 'bar', 'baz']
        for name in names, assert name.length == 3
        
        # list literals can span lines
        names = [
            'foo',
            'bar',
            'baz',  # trailing comma is optional
        ]
        
        # lists can be nested
        pairs = [
            [0, 0],
            [-2, -3],
            [5, 2],
        ]
        for pair in pairs
            assert pair.count == 2
        for x, y in pairs
            assert x > -10 and y > -10

        # lists can have other types of collections in them
        sites = [
            {'name': 'Cobra', 'url': 'http://cobra-language.com/'},
            {'name': 'Wikipedia', 'url': 'http://en.wikipedia.org/'},
        ]
        for dict in sites
            assert dict.count == 2
            assert dict['url'].startsWith('http://')
        
        # lists can have object instantiations in them
        points = [Point(0, 0), Point(1, 1), Point(0, 1), Point(1, 0)]
        assert points[0].toString == 'Point(0, 0)'
        
        # lists can be heterogenous
        stuff = ['foo', 5, nil]
        assert stuff.reversed == [nil, 5, 'foo']

        # the inferred type for a list is as narrow as possible
        ints = [1, 2, 3]               # List<of int>
        names = ['foo', 'bar', 'baz']  # List<of String>
        sites = [{'a': 'b'}]           # List<of Dictionary<of String, String>>
        points = [Point(0, 0)]         # List<of Point>
        stuff = ['foo', 5, nil]        # List<of dynamic?>
        stuff = []    # an empty list is List<of dynamic?>
    
    def stringConversion
        ints = [1, 2, 3]
        
        # list to string is ugly in .NET
        assert ints.toString == r'System.Collections.Generic.List`1[System.Int32]'
        # cobra also provides
        assert ints.toPrintString == r'[1, 2, 3]'

        # string substitution
        assert 'the ints are [ints]' == r'the ints are [1, 2, 3]'
        
        # print
        print ints  # prints: [1, 2, 3]
        
        # print each element
        for i in ints
            print i
        for index, i in ints.numbered
            print '[index]. [i]'
        
        # trace
        trace ints  # trace: ints=List<of int>[1, 2, 3]; at x-how-to-list.cobra:163;
                    #        in HowToUseLists.stringConversion

        # joining list elements into a string
        assert ints.join(' ') == '1 2 3'
        assert ints.join('---') == '1---2---3'
        assert ints.join(', ', ' and ') == '1, 2 and 3'

    def operators
        # you can concatenate two lists with +
        # the original lists are not changed
        a = [1, 2]
        b = [3, 4]
        assert a + b == [1, 2, 3, 4]
        assert a == [1, 2] and b == [3, 4]
        
        # the expression `x in items` evaluates to true or false
        # you can also write `x not in items`
        ints = [1, 2, 3]
        assert 1 in ints
        assert 2 in ints and 3 in ints
        assert 0 not in ints
        assert 4 not in ints
    
        # the expression `all items` evaluates to true if every item is true
        # the expression `any items` evaluates to true if any item is true
        ints = [1, 2, 3]
        assert all ints
        assert any ints
        ints = [0, 1, 2, 3]
        assert not all ints
        assert any ints
        ints = [0, 0]
        assert not all ints
        assert not any ints
        
        # the equality operators can be used on lists
        assert [1, 2] == [2, 1].reversed
        assert [1, 2] <> [2, 1]

    def methods
        # add an element to a list
        names = ['foo', 'bar', 'baz']
        names.add('qux')
        assert names == ['foo', 'bar', 'baz', 'qux']
        
        # add multiple elements to a list
        names.addRange(['x', 'y'])
        assert names == ['foo', 'bar', 'baz', 'qux', 'x', 'y']
        
        # insert an element
        names.insert(1, 'fooey')
        assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y']
        names.insert(7, 'z')  # 7 is just past the end of the list
        assert names == ['foo', 'fooey', 'bar', 'baz', 'qux', 'x', 'y', 'z']
        expect ArgumentOutOfRangeException, names.insert(20, 'exception')
        
        # clear a list
        names.clear
        assert names.count == 0
        
        # find an item's index
        names = ['foo', 'bar', 'baz', 'foo']
        assert names.indexOf('foo') == 0
        assert names.indexOf('baz') == 2
        assert names.indexOf('not there') == -1
        assert names.lastIndexOf('foo') == 3
        
        # find an item's index in a subrange of the list
        assert names.indexOf('foo', 1) == 3      # start at 1
        assert names.indexOf('foo', 1, 2) == -1  # start at 1, search 2 items
        
        # TODO: left off on .insertRange
        
        # additional methods. search web for "msdn generic list"
        # .asReadOnly .binarySearch .convertAll .copyTo .exists .find .findAll .findIndex .findLast .findListIndex .forEach
        
        

class Point

    cue init(x as int, y as int)
        base.init
        _x, _y = x, y
    
    def equals(other) as bool is override
        if other is nil, return false
        if other inherits Point, return .x == other.x and .y == other.y
        return false

    def getHashCode as int is override
        return .x ^ .y

    get x from var as int
    
    get y from var as int
    
    def toString as String is override
        return '[.typeOf.name]([.x], [.y])'


# although it's not common to subclass the list type,
# you are certainly free to do so

# a generic subclass

class MyList<of T> inherits List<of T>

    get middle as T
        require .count > 0
        return this[.count // 2]


# a subclass with specific type

class PointList inherits List<of Point>

    test
        pl = PointList()
        pl.add(Point(1, 0))
        pl.add(Point(-2, 3))
        assert pl.count == 2
        assert pl.leftMost == Point(-2, 3)
    
    def leftMost as Point
        require .count > 0
        leftMost = this[0]
        for i in 1 : .count
            if this[i].x < leftMost.x
                leftMost = this[i]
        return leftMost


# a generic subclass with a type constraint is even better,
# because then you can specify a type parameter when using it

class PointList<of TPoint> inherits List<of TPoint>
    where TPoint must be Point  # the type constraint

    test
        pl = PointList<of Point>()
        pl.add(Point(1, 0))
        pl.add(Point(-2, 3))
        assert pl.count == 2
        assert pl.leftMost == Point(-2, 3)
    
    def leftMost as TPoint  # notice the return type is TPoint
        require .count > 0
        leftMost = this[0]
        for i in 1 : .count
            if this[i].x < leftMost.x
                leftMost = this[i]
        return leftMost

        # TODO:

        # slicing
        
        # customers.sort(ref .orderByTotalSpent) 
        # sort with do
        
        # declaring types
        # List vs. IList
        # List methods
        # all extension methods
        # check msdn docs on IList and List
        # any enumerable .toList
        # for expression returns a list