Vala — это объектно-ориентированный язык программирования с самостоятельным компилятором , который генерирует код C и использует систему GObject .
Vala синтаксически похож на C# и включает в себя такие примечательные функции, как анонимные функции , сигналы , свойства , обобщения , вспомогательное управление памятью , обработка исключений , вывод типов и операторы foreach . [1] Его разработчики, Юрг Биллетер и Раффаэле Сандрини, хотели перенести эти функции в простую среду выполнения C с небольшими накладными расходами и без специальной поддержки среды выполнения, нацелившись на объектную систему GObject . Вместо того, чтобы компилировать напрямую в машинный код или язык ассемблера, он компилируется в промежуточный язык более низкого уровня . Он компилирует исходный код в исходный код в C, который затем компилируется с помощью компилятора C для заданной платформы, такого как GCC или Clang . [2]
Использование функциональности из собственных библиотек кода требует написания vapi-файлов, определяющих интерфейсы библиотеки . Написание этих определений интерфейсов хорошо документировано для библиотек C. Привязки уже доступны для большого количества библиотек, включая библиотеки, которые не основаны на GObject, такие как мультимедийная библиотека SDL и OpenGL .
Vala — это язык программирования, который сочетает в себе высокоуровневую производительность времени сборки скриптовых языков с производительностью времени выполнения низкоуровневых языков программирования. Он направлен на то, чтобы предоставить современные возможности языка программирования разработчикам GNOME без навязывания дополнительных требований времени выполнения и без использования другого ABI , по сравнению с приложениями и библиотеками, написанными на C. Синтаксис Vala похож на C# , модифицированный для лучшего соответствия системе типов GObject . [3]
Vala была задумана Юргом Биллетером и реализована им и Раффаэле Сандрини, которые хотели получить более высокоуровневую альтернативу для разработки приложений GNOME вместо C. Им нравились синтаксис и семантика C#, но они не хотели использовать Mono , поэтому они закончили компилятор в мае 2006 года. Первоначально он был загружен с использованием C, а год спустя (с выпуском версии 0.1.0 в июле 2007 года) компилятор Vala стал самостоятельным . В 2008 году был создан язык Genie, чтобы предоставить компилятору Vala синтаксис, подобный Python . [4] По состоянию на 2021 год текущей стабильной веткой выпуска с долгосрочной поддержкой является 0.48, и язык находится в стадии активной разработки с целью выпуска стабильной версии 1.0. [5]
Vala использует GLib и ее подмодули ( GObject , GModule, GThread, GIO) в качестве базовой библиотеки, которая доступна для большинства операционных систем и предлагает такие возможности, как платформенно-независимая потоковая передача , ввод/вывод , управление файлами , сетевые сокеты , плагины , регулярные выражения и т. д. В настоящее время синтаксис Vala поддерживает современные языковые возможности следующим образом:
Графические пользовательские интерфейсы можно разрабатывать с помощью набора инструментов GTK GUI и конструктора Glade GUI .
Для управления памятью система GType или GObject обеспечивает подсчет ссылок . В C программист должен вручную управлять добавлением и удалением ссылок, но в Vala управление такими подсчетами ссылок автоматизировано, если программист использует встроенные в язык ссылочные типы, а не простые указатели. Единственная деталь, о которой нужно беспокоиться, — это избегать генерации циклов ссылок , потому что в этом случае эта система управления памятью будет работать неправильно. [7]
Vala также позволяет осуществлять ручное управление памятью с использованием указателей в качестве опции.
Vala предназначена для предоставления доступа во время выполнения к существующим библиотекам C, особенно библиотекам на основе GObject , без необходимости привязок во время выполнения. Для использования библиотеки с Vala, все, что нужно, это файл API (.vapi), содержащий объявления классов и методов в синтаксисе Vala. Однако библиотеки C++ не поддерживаются. В настоящее время файлы vapi для большой части проекта GNU и платформы GNOME включены в каждый выпуск Vala, включая GTK . Существует также библиотека Gee, написанная на Vala, которая предоставляет интерфейсы и классы на основе GObject для часто используемых структур данных . [8]
Также должна быть возможность легко написать генератор привязок для доступа к библиотекам Vala из приложений, написанных на других языках, например, C#, поскольку анализатор Vala написан как библиотека, поэтому вся информация времени компиляции доступна при создании привязки.
Инструментарий для разработки Vala значительно улучшился за последние годы. Ниже приведен список некоторых популярных IDE и текстовых редакторов с плагинами, которые добавляют поддержку программирования в Vala:
В настоящее время активно развиваются два языковых сервера , предлагающих анализ кода для Vala:
В настоящее время существует ряд систем сборки , поддерживающих Vala, включая Automake , CMake , Meson и другие. [14]
Отладка программ Vala может быть выполнена с помощью GDB или LLDB . Для отладки в IDE ,
Простая программа « Привет, мир! » на языке Vala:
void main () { print ( "Привет, мир \n " ); }
Как можно заметить, в отличие от C или C++, в Vala нет заголовочных файлов. Связывание с библиотеками осуществляется указанием --pkg
параметров во время компиляции. Более того, библиотека GLib всегда связана и ее пространство имен может быть опущено ( print
на самом деле есть GLib.print
).
Ниже приведена более сложная версия, которая определяет подкласс, HelloWorld
наследующий от базового класса GLib.Object
, также известного как класс GObject . Она демонстрирует некоторые объектно-ориентированные возможности Vala:
класс HelloWorld : Объект { private uint year = 0 ; public HelloWorld ( ) { } public HelloWorld.with_year ( int year ) { if ( year > 0 ) this.year = year ; } public void greeting () { if ( year == 0 ) print ( "Hello World \n " ); else /* Строки с префиксом '@' являются шаблонами строк. */ print ( @"Hello World, $(this.year) \n " ); } } void main ( string [] args ) { var helloworld = new HelloWorld . with_year ( 2021 ); helloworld . greeting (); }
Как и в случае с библиотекой GObject , Vala не поддерживает множественное наследование , но класс в Vala может реализовать любое количество интерфейсов , которые могут содержать реализации по умолчанию для своих методов. Вот фрагмент кода-образца для демонстрации интерфейса Vala с реализацией по умолчанию (иногда называемого миксином )
с использованием GLib ; интерфейс Printable { public abstract string print (); публичная виртуальная строка pretty_print () { return "Пожалуйста " + print (); } } class NormalPrint : Object , Printable { string print () { return "не забывай обо мне" ; } } class OverridePrint : Object , Printable { string print () { return "Обратите внимание на зазор" ; } публичное переопределение string pretty_print () { return "Переопределить" ; } } void main ( строка [] args ) { вар нормальный = новый NormalPrint (); вар переопределен = новый OverridePrint (); print ( нормальный . pretty_print ()); print ( переопределенный . pretty_print ()); }
Ниже приведен базовый пример, показывающий, как определить сигнал в классе, который не является компактным, который имеет встроенную Vala систему сигналов через GLib. Затем функции обратного вызова регистрируются в сигнале экземпляра класса. Экземпляр может испускать сигнал, и каждая функция обратного вызова (также называемая обработчиком), подключенная к сигналу для экземпляра, будет вызвана в том порядке, в котором они были подключены:
class Foo { public signal void some_event (); // определение сигнала public void method () { some_event (); // отправка сигнала (вызываются обратные вызовы) } } void callback_a () { stdout . printf ( "Обратный вызов A \n " ); } void callback_b () { stdout . printf ( "Обратный вызов B \n " ); } void main () { var foo = new Foo ( ) ; foo.some_event.connect ( callback_a ) ; // подключение функций обратного вызова foo.some_event.connect ( callback_b ) ; foo.method ( ) ; }
Новый поток в Vala — это часть кода, например, функция, которая запрашивается для параллельного выполнения во время выполнения. Создание и синхронизация новых потоков выполняется с использованием класса Thread
в GLib, который принимает функцию в качестве параметра при создании новых потоков, как показано в следующем (очень упрощенном) примере:
int question (){ // Некоторые операции печати for ( var i = 0 ; i < 3 ; i ++ ){ print ( "." ); Thread . usleep ( 800000 ); stdout . flush (); } возврат 42 ; } void main () { if ( ! Thread . supported ()) { stderr . printf ( "Невозможно запустить без поддержки потоков. \n " ); return ; } print ( "Главный вопрос жизни, вселенной и всего такого" ); // Универсальный параметр — это тип возвращаемого значения var thread = new Thread < int > ( "question" , question ); печать ( @" $(thread.join ()) \n " ); }
Ниже приведен пример использования GTK для создания программы с графическим интерфейсом «Hello, World!» (см. также GTK hello world ) в Vala:
с использованием Gtk ; int main ( string [] args ) { Gtk . init ( ref args ); var window = new Window ( ) ; window.title = " Hello , World ! " ; window.border_width = 10 ; window.window_position = WindowPosition.CENTER ; window.set_default_size ( 350 , 70 ) ; window.destroy.connect ( Gtk.main_quit ) ; var label = new Label ( "Привет, мир!" ); окно.добавить ( метка ) ; окно.показать_все ( ) ; Gtk.main ( ) ; return 0 ; }
Оператор Gtk.main ()
создает и запускает основной цикл прослушивания событий, которые передаются через сигналы в функции обратного вызова. Поскольку этот пример использует пакет GTK , для компиляции ему требуется дополнительный --pkg
параметр (который вызывает pkg-config в бэкэнде C ):
valac --pkg gtk+-3.0 hellogtk.vala
Компилятор Vala также поддерживает язык Genie, который почти идентичен Vala, за исключением синтаксиса. Это особенно полезно для определения моделей из-за простого, "Python-подобного" синтаксиса Genie.