Structs

A struct as the name suggests is the definition of a data structure, We can define a structure with the following syntax.

struct Color
  r: number
  g: number
  b: number
  a: number
end

Initialization of a structure happens using the T { values } expression, Where T is the type of our structure and named values of the structure placed between curly brackets.

let color = Color { r: 1, g: 1, b: 1, a: 1 }

If we are initializing the struct using a variable with the same name as it would have as its field, We can omit specifying the field name.

let r = 1
let g = 0.32
let alpha
let color = Color { r, g, b: 0.5, alpha: alpha }

But now if we try to access our values x and y through the dot notion we will get an error saying we don’t have access to the said variable.

assert_eq(color.r, 1) -- this won't compile!

It is because in Fuse all fields inside a struct are private, It happens despite the language not having a keyword for describing being private. If we want our fields to be accessible directly from outside of the struct we can declare them using the pub keyword.

struct Color
  pub r: number
  pub g: number
  pub b: number
  pub a: number
end

let color = Color { r: 1, g: 0.5, b: 0.1, a: 0.9 }

-- now these lines would compile fine.
assert_eq(color.r, 1)
assert_eq(color.g, 0.5)
assert_eq(color.b, 0.1)
assert_eq(color.a, 0.9)

Implementing a struct

Having data by itself is a really powerful tool but in some situations, we need to associate some functionalities to our structure, These associated functions or methods can be implemented for a struct using an impl block.

Methods can optionally receive a self variable as their first parameter, This variable implicitly has the same type of structure it is being implemented for; If a method doesn’t accept a self variable it is considered a static method.

Here is an example of implementing the set_opacity method for our Color structure.

impl Color
  pub fn set_opacity(self, opacity: number) -> ()
      -- clamping alpha between 0 and 1
      self.a = math::min(math::max(opacity, 0), 1)
  end
end

-- ...

color.set_opacity(0.5)

Structures in Fuse don’t have an explicit constructor and new keyword, Instead similar to Lua we can create a static method to our structure called new which can initialize and return a new instance of our struct.

impl Color
  pub fn new(r: number, g: number, b: number, a: number) -> Self
    Self { r, g, b, a }
  end
end

-- ...

let color = Color::new(0.3, 0.3, 0.3, 1)

Note: Type Self is an alias for the type of our target structure.

If we want to have multiple constructors for a type we can add more static methods to do so, There is no rule on naming constructors but as a convention, we name our main constructor new and any constructor that will initialize our structure for a specific scenario will start with new_ for example a constructor for that would initialize a Color with Hexadecimal values could be called with_hex or with_hexadecimal.

impl Color
  pub fn with_hexadecimal(value: string) -> Self
    -- implementation details...
  end
end