6.10.94-stable

Objects

Types are essential units to defines GreyCat data structure. Types define aggregated typed fields into a named type, later instantiated as an Object. It is a very similar concept to Classes used in other Object Oriented programming languages.


Type definition

Here is an example of a type in Greycat:

type Country {
  name: String;
  phoneCode: int;
  location: geo;
}

type City {
  name: String;
  population: int?;
}
  • Type Country has 3 attributes: name, phoneCode, location
  • Type City has 2 attributes: name, population
  • Population is of type int?. The ? stands for nullable (can be null if we don’t know the population of a city)
  • Population is a non-mandatory field
  • In Greycat we can define several types in the same file

Objects

  • An object in Greycat is an instance of a defined type.

Let’s create luxembourg object, an instance of type Country:

fn main() {
    var luxembourg = Country {
        name: "Luxembourg",
        phoneCode: 352,
        location: geo::new(49.8153, 6.1296),
    };
    println(luxembourg);
    println(luxembourg.phoneCode);
}
greycat run
# {"_type":"project.Country","name":"Luxembourg","phoneCode":352,"location":{"_type":"core.geo","lat":49.815300005,"lng":6.129600001}}
# 352
  • Objects in greycat are compatible with JSON format
  • Objects are not persistent => Meaning they exist in RAM only (not stored)

Static attributes

  • Objects can hold static attributes for default values or parameters. Example:
type Country{  
    static unknown_country_name: String = "Unknown Country";  
    name: String;
    phoneCode: int;
    location: geo;
}

fn main() {
    println(Country::unknown_country_name);
}
  • Static attributes are the only attributes that can be given a default value in the type definition
  • Static attributes can be accessed through the type name and the :: operator (Country::unknown_country_name)
  • Normal attributes can be accessed through an instance and the . operator (luxembourg.name)

Functions on types

  • Functions on types can be static, or non static
type Country {
    name: String;
    location: geo;

    fn print() {
        println("Hello from ${this.name}, location is latitude: ${this.location.lat()}, longitude: ${this.location.lng()}");
    }
}
fn main() {
    var luxembourg = Country { name: "luxembourg", location: geo::new(49.815300005, 6.129600001) };
    luxembourg.print();
}
greycat run
# Hello from Luxembourg, location is latitude: 49.815300005, longitude: 6.129600001

Enum

Enums are list of values known at compile-time that cannot be extended dynamically. They are very useful tools when list of options are part of a domain definition. They can be used through the keyword enum and can have or not values.

enum DaysOfTheWeek{
    monday("Monday");
    tuesday("Tuesday");
    wednesday("Wednesday");
    thursday("Thursday");
    friday("Friday");
    saturday("Saturday");
    sunday("Sunday");
}
enum TransactionChannel{
    web(0);
    mobile(1);
    other(2);
}
fn main(){
    var day = DaysOfTheWeek::monday; // same accessor as the static :: 
}

Generic parameters

GreyCat support up to two generic parameters for classes, for instance the map native class from STD library is defined as follow:

native type Map<K,V>{
    native fn get(k: K): V;
}

The generic parameters can be specialized during instance creation such as:

var m = Map<String,float>::new();
m.get("my_key");

Inheritance with abstract types

GreyCat support a simplified model of inheritance using the keyword extends. The child inherits all attributes and functions from it’s parent

Beware that the parent needs to have the keyword abstract such as:

abstract type Animal {
    age: int;
    fn eat() {
        println("Animal is eating");
    }
}
type Dog extends Animal {
    breed: String;
}

fn main(){
    var dog = Dog {
        age: 10,
        breed: "Golden Retriever"
    };
    dog.eat();
}

Greycat does not allow the child to override the parents functions, you can however define abstract functions on the parent, be advised these will become required on all Children

abstract type Animal {
    abstract fn makeSound();
}
type Dog extends Animal {
    fn makeSound() {
        println("Woof");
    }
}

Composition

GreyCat supports type composition such as:

abstract type Job {
  salary: int;
}

type Programmer extends Job {}

type Person {
  job: Job;
}

fn main() {
  var programmer = Programmer {
    salary: 1000
  };
  var person = Person {
    job: programmer
  };
}

Helper functions on types

GreyCat offers functions on types, such as parseNumber:

fn main() {
    println(parseNumber("123")); // 123
    println(parseNumber("12.3")); // 12.3
}

and some type inspection with sameType:

use util; // for Assert

type T {
    a: int;
}

fn main() {

    Assert::isTrue(sameType(1, parseNumber("123")));
    Assert::isTrue(sameType(1 as float, parseNumber("123.45")));

    Assert::isTrue(sameType(12_time, 342_time));
    Assert::isTrue(sameType(12_geo, 342_geo));
    Assert::isTrue(sameType(T{a: 12}, T{a:1234343}));

    var a = nodeTime<String>::new();
    var b = nodeTime<float>::new();
    a.setAt(12_time, "12");
    b.setAt(13_time, 13.4);
    Assert::isTrue(sameType(a, b)); // true!
}