Classes

Silk supports object oriented programming. Classes are the central feature and normally it is called user-defined types.
A class is used to specify the form of an object and it combines data(properties) and functions(methods) which can process data.

Class Definition
A class definition starts with the keyword class followed by the class name; the parameter, the init and functions, enclosed by a pair of curly braces.
Here is a sample:
class class_name( parameter )
{
    init;
    functions;
}

class:keyword class, a class definition starts with class.
class_name:the name of the class, the name must be unique, and it cannot be the same as other classes/functions/variables and keywords.
parameter:when a class object is created, you can pass the value to the parameter to initialize the data of the object.  parameter is optional.
init:initialize the properties of the class object.
functions:The methods of the class, it's the same as normal function which starts with func.

Class object
We need to use the class by creating the class object, creating object is like calling function, and the return of the calling is the created object.  
The properties and methods of the object can be accessed using the direct member access operator (.)
Let's take a look at the following example to make the things clear:
class myClass(a,b)
{
    //initialize the class properties, we need to use keyword self to access the properties
    self.a=a;
    self.b=b;
    self.c=0;
    if(a>b)
        self.c=1;
   
    //define the class methods (functions)
    func test()
    {
        printf("a=%d, b=%d, c=%d\n",self.a,self.b,self.c);
    }
    func test2()
    {
        self.a++;
        self.test();
    }
}

main()
{
    obj=myClass(100,200);
    obj.test2();
    obj.a=300;
    print(obj.a);
}


self
Every object has access to its own properties and methods through an implicit parameter called self.
The self parameter is a reference to the current instance of the class, it's actuall the object itself.
The above class method is like the following function, but the parameter self in method is hidden, and you do not need to pass it when you call the method:
func test(self)
{
    printf("a=%d,b=%d\n",self.a,self.b);
}


Encapsulation
Properties and methods can be accessed without any limitation, the Encapsulation is an Object Oriented Programming concept that binds together the properties and methods that keeps both safe from outside interference and misuse.  we can define the private properties and methods to hide them, this means they can be accessed only within the class, and cannot be accessed from outside.  
To define the private properties and methods, just add __ before the name:
class myClass(a)
{
    self.__a=a;//private property
  
    func __test()//private method
    {
        printf("a=%d\n",self.__a);
    }
    func test2()
    {
        self.__a++;
        self.__test();
    }
}

main()
{
    obj=myClass(100);
    obj.test2();
    print(obj.__a);//cannot access the private property, will get error
}


Inheritance
One of the most important concepts in object-oriented programming is that of inheritance. Inheritance allows us to define a class in terms of another class, which makes it easier to reuse the code functionality. When creating a class, instead of writing completely new data and functions, the programmer can designate that the new class should inherit the members(data and functions) of an existing class. This existing class is called the base class, and the new class is referred to as the derived class. Currently silk does not support multiple base classes.
In Silk, we can assign the base class object to self to inherit the members of base class:
//base class Animal
class Animal(name)
{
    self.name=name;
   
    func description()
    {
        printf("this is %s\n",self.name);
    }
}
//derived class Dog
class Dog(name)
{
    self=Animal(name);//inherit the base class Animal
   
    func SetName(name)
    {
        self.name=name;//update the property in base class
    }
}

main()
{
    dog=Dog("dog");
    dog.description();//call the method in base class
    dog.SetName("pet");//the new method in derived class
    dog.description();
}
Result:
this is dog
this is pet


Overriding
If the method in base class is not what we need, we can override it and rewrite a new one in derived class:
//base class Animal
class Animal(name)
{
    self.name=name;

    func description()
    {
        printf("this is %s\n",self.name);
    }
}
//derived class Dog
class Dog(name)
{
    self=Animal(name);//inherit the base class Animal
  
    func description()//override the method in base class
    {
        printf("I am %s, I can swim\n",self.name);
    }
}
main()
{
    dog=Dog("dog");
    dog.description();
}
Result:
I am dog, I can swim


To access the overridden method of the base class, we can save the base class method before overriding it and call it later:
//base class Animal
class Animal(name)
{
    self.name=name;
  
    func description()
    {
        printf("this is %s\n",self.name);
    }
}
//derived class Dog
class Dog(name)
{
    self=Animal(name);//inherit the base class Animal
    self.super_description=self.description;//save the method in base class
  
    func SetName(name)
    {
        self.name=name;//update the property in base class
    }
    func description()//override the method in base class
    {
        self.super_description();//call the original method in base class
        printf("I can swim\n");
    }
}

main()
{
    dog=Dog("dog");
    dog.description();
}
Result:
this is dog
I can swim


Polymorphism
Polymorphism means having many forms. Typically, polymorphism means that a call to a member function will cause a different method to be executed depending on the type of object that invokes the method.
Silk is a dynamically typed language, and the type is determined at runtime, so Silk supports polymorphism natually:
//base class Animal
class Animal(name)
{
    self.name=name;
  
    func description()
    {
        printf("this is %s\n",self.name);
    }
}
//derived class Dog
class Dog(name)
{
    self=Animal(name);
  
    func description()
    {
        printf("I am dog, I can swim\n");
    }
}
//derived class Bird
class Bird(name)
{
    self=Animal(name);
  
    func description()
    {
        printf("I am bird, I can fly\n");
    }
}

func test_animal(animal)
{
    //will call the method depending on the type of animal
    animal.description();
}

main()
{
    dog=Dog("dog");
    bird=Bird("bird");
    test_animal(dog);
    test_animal(bird);
}
Result:
I am dog, I can swim
I am bird, I can fly