Object-oriented programming in Engee: structures and methods
Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects" that can contain data (in the form of fields or attributes) and code (in the form of methods). The basic principles of OOP include:
- Encapsulation — combining data and methods for working with them in one structure
- Inheritance — the ability to create new classes based on existing ones
- Polymorphism — the ability of objects of different classes to respond to the same messages
Engee is a programming language that was originally developed for high-performance computing and is not a purely object-oriented language. However, it supports some OOP concepts through:
- Custom types (structures)
- Multiple dispatching (a more powerful alternative to class methods)
- Composition (instead of inheritance)
Engee's approach differs from traditional OOP in languages such as Python or Java, but it allows you to achieve similar results in more flexible ways.
Engee's OOP style is especially useful.:
- When working with complex data structures
- When it is necessary to model a subject area with clear entities
- For organizing code in large projects
- When polymorphic behavior of functions is required
Although Engee is not a purely object-oriented language, it provides powerful tools for organizing OOP-style code. The use of structures combined with multiple dispatching offers a flexible alternative to traditional OOP, which can be more expressive and productive in scientific computing and other areas for which Engee was created.
Code sample analysis
Let's look at the presented example, which demonstrates the basic capabilities of OOP in Engee.:
struct Person # Определяем тип (аналог класса)
name::String
age::Int
end
Here we create a structure Person with two fields: name (string) and age (an integer). In OOP terms, this is similar to creating a class with attributes.
function greet(person::Person) # Метод для типа Person (аналог метода класса)
println("Привет, меня зовут $(person.name), мне $(person.age) лет!")
end
This is a function specialized for working with the type Person. In Engee, methods do not "belong" to objects, as in classical OOP, but thanks to multiple dispatching, we can create specialized versions of functions for different types.
function test_person()
person = Person("Анна", 25)
@assert person.name == "Анна"
@assert person.age == 25
println("Тест метода greet():")
greet(person)
println("Тест пройден успешно!")
end
In the test function, we create an instance of the structure Person, check its fields and call the method greet.
Extended example: employee management system
Let's expand the example to a more practical application. This code is an implementation of a simple employee management system using an object-oriented approach in Engee. The system is based on two user types: Employee (employee) and Manager (manager). Type Employee contains the basic fields: identifier (id), first name (name), department (department) and salary (salary). Type Manager uses a composition that includes an object Employee and by adding manager—specific fields, the size of the team (team_size) and a bonus (bonus).
The code demonstrates the key principles of OOP through several specialized functions. Function annual_salary It has two implementations — for an ordinary employee (simply multiplies the monthly salary by 12) and for a manager (adds a bonus to the annual salary). Function print_info It is also overloaded for different types of employees, providing polymorphic behavior — the output of different information depending on the type of object. Function give_raise! modifies the employee's salary by the specified percentage, demonstrating work with mutable data (the exclamation mark in the function name is the Engee convention for functions with side effects).
Test function test_employee_system creates instances of the employee and manager, demonstrating the operation of all methods. A feature of the implementation is Engee's approach to OOP — instead of classical inheritance, composition is used (the manager contains an employee object), and polymorphism is achieved through multiple dispatching (different function implementations for different types of arguments). The code illustrates how data structures and OOP-style behavior can be organized in Engee, while maintaining the high performance of the language.
mutable struct Employee
id::Int
name::String
department::String
salary::Float64
end
struct Manager
employee::Employee
team_size::Int
bonus::Float64
end
function annual_salary(emp::Employee)
emp.salary * 12
end
function annual_salary(mgr::Manager)
(mgr.employee.salary * 12) + mgr.bonus
end
function print_info(emp::Employee)
println("""
Сотрудник: $(emp.name)
ID: $(emp.id)
Отдел: $(emp.department)
Месячная зарплата: $(emp.salary)
Годовая зарплата: $(annual_salary(emp))
""")
end
function print_info(mgr::Manager)
println("""
Менеджер: $(mgr.employee.name)
ID: $(mgr.employee.id)
Отдел: $(mgr.employee.department)
Размер команды: $(mgr.team_size)
Месячная зарплата: $(mgr.employee.salary)
Бонус: $(mgr.bonus)
Годовая зарплата: $(annual_salary(mgr))
""")
end
function give_raise!(emp::Employee, percent::Float64)
emp.salary *= (1 + percent/100)
println("Зарплата $(emp.name) повышена на $percent%")
end
# Создаем обычного сотрудника
emp1 = Employee(101, "Иван Петров", "IT", 1500.0)
# Создаем менеджера (который содержит сотрудника)
mgr1 = Manager(Employee(201, "Анна Сидорова", "IT", 2500.0), 5, 5000.0)
# Выводим информацию
println("\nИнформация о сотруднике:")
print_info(emp1)
println("\nИнформация о менеджере:")
print_info(mgr1)
# Повышаем зарплату
give_raise!(emp1, 10.0)
give_raise!(mgr1.employee, 8.0) # Обращаемся к вложенному сотруднику
# Проверяем новые зарплаты
println("\nПосле повышения:")
print_info(emp1)
print_info(mgr1)
println("\nТест завершен успешно!")
Conclusions
To summarize, it is worth once again figuring out which analogues and features of functional programming in Engee we can use to implement an object-oriented approach.
Key concepts of OOP in Engee
-
Structures instead of classes: Engee uses structures (
struct) to create custom types that can contain data, but cannot contain methods (functions are defined separately). -
Multiple dispatch: Unlike traditional OOP, where methods "belong" to objects, in Engee functions are defined independently, and a specific implementation is selected based on the types of all arguments.
-
Composition instead of inheritance: Engee does not support classical inheritance. Instead, it is recommended to use composition (including one object in another), as shown in the example with
Manager, containingEmployee. -
Encapsulation: By default, all fields of the structure in Engee are public. Modules or naming conventions can be used for encapsulation (for example, starting private fields with an underscore).
-
Polymorphism: Implemented through multiple dispatch — different methods of the same function can be called depending on the types of arguments.
Advantages of the Engee approach to the PLO
-
Flexibility: Multiple dispatch is more powerful than classical OOP, as it allows you to choose the implementation of a method based on all arguments, not just the first one (as in Python or Java).
-
Performance: The Engee type system and compiler are optimized for working with structures, which ensures high performance.
-
Code Clarity: Separating data (structures) and behavior (methods) can make the code clearer and easier to maintain.