Vala Language

Vala. Технологии 101.1


Итак из прошлой статьи вы узнали что такое GLib теперь время узнать что же из себя представляет Vala и чем этот язык так крут.

Зачем же была нужна предыдущая статья про GLib? Да затем что Vala является этакой оберткой в которой уже используется GLib в красивом синтаксисе(в отличии от Си).

Описание от самих разработчиков Vala:

Vala - это новый язык программирования, предназначенный для прикладного и системного программирования на основе библиотек
 GLib Object System (GObject) рабочей среды GNOME/GTK+. Эта платформа предлагает полноценную программную среду, с такими наворотами
 как динамическая типизация и сборщик мусора. До появления Vala единственными способами программирования под GNOME/GTK+ было либо
 использования C API, который предоставлял много лишних деталей, либо использование языков высокого уровня, которые выполняются в
 сопутствующих виртуальных машинах, таких как Python или Mono C#, или используя C++ c библиотеками-обертками.

Vala отличается от всех других методов, так как она транслируется в C код, который может быть собран для запуска без дополнительной поддержки библиотек за пределами платформы GNOME. Это имеет несколько особенности, главные из которых:

  • Программы, написанные на Vala должны иметь хорошую скорость выполнения, близкую к коду написанному на C, а также их легче и быстрее писать и поддерживать.
  • Приложения на Vala не могут делать ничего, чего бы не смогла бы сделать аналогичная программа на C. Несмотря на это Vala предоставляет множество языковых возможностей, которые не доступны в C, хотя они они и транслируются в С конструкции, но на их написание и отладку ушло бы много времени.

Итак Vala был создан относительно недавно, поэтому поддерживает большинство современных технологий, а из-за прямой компиляции в Си это позволяет ему работать со скоростью Си. Лично я заметил в нем присутствие фишек из Python(лямбда функции), Java(сборщик мусора, коллекции), C#(всё есть объект/GLib), Qt (система сигналов и слотов)

Получается прямо таки нечто идеальное, все современные плюшки из других языков, а скорость от Си.

Чтож рассмотрим их по порядку в котором они описаны в википедии.

«Поддерживаются интроспекциявыведение типовсборка мусора основанная на подсчёте ссылоклямбда-функции, концепция сигналов и слотов, подобная используемой в Qt, но реализованная на уровне языка, строковые типыобобщённое программирование, срезы массивов, оператор перечисления элементов коллекции foreachделегатызамыканияинтерфейсысвойства и исключения

Интроспекция

Интроспеция это просто, это возможность языка запросить тип передаваемого в качестве аргумента объекта, используется для реализации ad hoc полиморфизма, или проще говоря перегрузки функций, о которой я помойму уже рассказывал в статье про Qt.

Так а вот тут стапе, исправляю это на следующий день, в Vala нет перегрузки функций(а интроспекция есть), но так как я все уже оч классно объяснил, то я это оставлю.

/////////////Объяснение почему в Vala нет перегрузки от разрабов Vala///////////////

void draw(string text) { }
void draw(Shape shape) { }  // не допускается

Это объясняется тем, что библиотеки, написанные на Vala, должны быть пригодны для использования также и программистами, использующими C. Вместо перегрузки можно прибегнуть приблизительно к такому решению:

void draw_text(string text) { }
void draw_shape(Shape shape) { }

Используя несколько различающиеся наименования, вы можете избежать конфликта имен. В языках, которые поддерживают перегрузку методов, эта возможность нередко используется для создания удобных методов с меньшим числом параметров, соотносящихся с наиболее общим методом:

void f(int x, string s, double z) { }
void f(int x, string s) { f(x, s, 0.5); }  // не допускается
void f(int x) { f(x, "hello"); }           // не допускается

//////////////////////////////////Объяснение закончилось/////////////////////////////////////////

Вкратце напомню, перегрузка функций это когда мы хотим чтобы одна и та же функция работала по разному в зависимости от того какие аргументы она получает. Самый простой пример перегрузка оператора сравнения ==. Например в нашей программе мы зачем то используем расчет площади фигур. Очевидно было бы довольно неудобно писать 3 разные функции для сравнения площади треугольников, квадратов и кругов. circle_compare(круг, круг2); square_compare(квадрат1, квадрат2); и triangle_compare(треуг1, треуг2);

В этом случае можно использовать перегрузку функций, мы перегрузим оператор сравнения == для каждого типа объектов(получается 6 раз аб ас сб бб аа сс), и тогда далее в коде сможем как бы сравнивать их напрямую типа

if(треугольник == круг)

(я подразумевал что компилятор разумеется не знает как сравнить 2 объекта у которого абсолютно разные поля, например они содержат только длину сторон, тогда в этой перегрузке оператора мы бы описали нахождение площади по имеющимся данным и потом уже сравнивали)

Динамическая типизация (вывод типов)

По сути вывод типов предоставляет возможность динамической типизации, то есть мы объявляем переменную, а компилятор сам угадывает какого она типа, достаточно сложно оценить насколько это удобно пока не сталкивался с большими запутанными проектами где объекты передаются между 3-4 классами. Также это позволяет запихивать разные типы данных в одну и туже переменную.

Простой пример который покажется сишнику магией:

var res = "string1";   // выводит 'string1'
res = 1;               // выводит 1
res += 2;              // выводит 3
res += 'string2';      // выводит '3string2'

немного вики

Плюсы

  • Упрощается написание несложных программ, например, скриптов.
  • Облегчается работа прикладного программиста с СУБД, которые принципиально возвращают информацию в «динамически типизированном» виде. Поэтому динамические языки ценны, например, для программирования веб-служб.
  • Иногда требуется работать с данными переменного типа. Например, функция поиска подстроки возвращает позицию найденного символа (число) или маркер «не найдено». В PHP этот маркер — булевое false. В языках со статической типизацией это особая константа (0 в Паскалеstd::string::npos в C++).

Минусы

  • Статическая типизация позволяет уже при компиляции заметить простые ошибки «по недосмотру». Для динамической типизации требуется как минимум выполнить данный участок кода.
  • В объектно-ориентированных языках не действует, либо действует с ограничениями, автодополнение: трудно или невозможно понять, к какому типу относится переменная, и вывести набор её полей и методов.
  • Развитая статическая система типов играет значительную роль в самодокументировании программы; динамическая типизация по определению не проявляет этого свойства, что затрудняет разработку структурно сложных программ.
  • Снижение производительности из-за трат процессорного времени на динамическую проверку типа, и излишние расходы памяти на переменные, которые могут хранить «что угодно». К тому же большинство языков с динамической типизацией интерпретируемые, а не компилируемые.

Сборка мусора

«В программировании сборка мусора[1] (англ. garbage collection) — одна из форм автоматического управления памятью. Специальный процесс, называемый сборщиком мусора (англ. garbage collector), периодически освобождает память, удаляя объекты, которые уже не будут востребованы приложениями.»

На самом деле это невероятно обширная тема, которая уже хорошо вам знакома если вы знаете Java, если нет то крайне советую прочитать про нее отдельно, а тут попробую наглядно объяснить.

Когда мы создаем сложный объект состоящих из нескольких полей, например треугольник с информацией о длине сторон, площади, периметре и тд, под него необходимо выделить память — как бы сообщить другим программам что эта область памяти зарезервирована и ее трогать нельзя (это кстати очень часто встречающаяся в си ошибка SEGFAULT, {я не просто так ссылки оставляю}вероятность которой в Vala ниже по очевидным причинам)

Тк вот память под объект выделена, и теперь как только он нам больше не нужен ее нужно очистить, но в больших программах становиться очень сложно за этим уследить, так получаются утечки памяти, которая кстати недавно была в GNOME 3.26(а он написан на си).

Подсчёт ссылок

Как уже упоминалось выше в Vala сборщик мусора реализован с помощью подсчета ссылок.

«Подсчёт ссы́лок — техника хранения количества ссылокуказателей или дескрипторов на какой-то ресурс, например на объект или на блок памяти.

Подсчёт ссылок также известен как один из алгоритмов сборки мусора, где каждый объект содержит счётчик количества ссылок на него, используемых другими объектами. Когда этот счётчик уменьшается до нуля, это означает, что объект стал недоступным, и он помещается в список объектов на уничтожение.»

Лямбда-функции

А это уже будет хорошо знакомо программистам на Python.

«Лямбда-выражение в программировании — специальный синтаксис для определения функциональных объектов, заимствованный из λ-исчисления. Применяется как правило для объявления анонимных функций по месту их использования, и обычно допускает замыкание на лексический контекст, в котором это выражение использовано. Используя лямбда-выражения можно объявлять функции в любом месте кода.»

Или простым языком, это возможность написать функцию прямо в том месте в котором понадобился ее результат, нигде ее не объявляя и даже не давая ей название, вот очень наглядный пример, где первая строчка это сама лямбда функция, а то как бы она выглядела если бы мы писали ее обычным способом.

помойму крайне наглядно

Вот еще наглядная картинка, действие выполняется на месте

Система сигналов и слотов

«Сигналы и слоты — подход, используемый в некоторых языках программирования и библиотеках (например, Boost и Qt) который позволяет реализовать шаблон «наблюдатель», минимизируя написание повторяющегося кода. Концепция заключается в том, что компонент (часто виджет) может посылать сигналы, содержащие информацию о событии (например: был выделен текст «слово», была открыта вторая вкладка). В свою очередь другие компоненты могут принимать эти сигналы посредством специальных функций — слотов.»

А теперь понятно ^^ . Итак нам нужно выполнить некое действие при соблюдении некого условия. Например ответить на телефонный звонок когда он зазвонил/вынуть еду из микроволновки/отбить мяч битой(щито). Вообщем у нас есть событие, и нам надо на него среагировать. Как бы мы сделали это в обычном языке программирования например Си++ или Delphi. Мы бы написали таймер который раз в определенное время проверял произошло ли событие.

Очевидно что чем чаще меньше был бы интервал таймера чем чаще он бы проверял, с одной стороны чтобы среагировать на событие наиболее быстро нужно проверять чаще, с другой — это тратит больше ресурсов процессора.

Представьте себе ситуацию что вы стоите на воротах и вам нужно отбить мяч, единственное что вы можете это узнать появился ли мяч в поле диаметром 4 метра от вас, если наличие мяча проверять раз в секунду, то мяч пролетит мимо ворот, если раз в миллисекунду — ваш процессор сгорит.

И тут нам на помощь приходит система сигналов и слотов, с помощью которой мы как бы подписываемся(subscribe) на определенное событи и связываем сигнал(событие) с слотом(действием). Теперь нам не нужно раз в 500 мс проверять есть ли мяч, мы просто свяжем действие поймать с сигналом о наличии мяча.

Сейчас я описал концепцию асинхронного программирования которая на самом деле устроена гораздо сложнее, если вы заинтересовались советую почитать про нее отдельно вот тут прям ну очень понятные примеры и пояснения.

Строковый тип

Без инклюда библиотеки string в Си строкового типа нет, извольте создавать массивы чаров(букв). Кто еще не понял строковый тип — строка, дада, даже такая простая вещь не является такой уже простой в программировании.

Основные проблемы в машинном представлении строкового типа:

  • строки могут иметь достаточно существенный размер (до нескольких десятков мегабайтов);
  • изменяющийся со временем размер — возникают трудности с добавлением и удалением символов.

В представлении строк в памяти компьютера существует два принципиально разных подхода.

В виде массива символов, как я и упоминал выше:

Преимущества

  • программа в каждый момент времени содержит сведения о размере строки, поэтому операции добавления символов в конец, копирования строки и собственно получения размера строки выполняются достаточно быстро;
  • строка может содержать любые данные;
  • возможно на программном уровне следить за выходом за границы строки при её обработке;
  • возможно быстрое выполнение операции вида «взятие N-ого символа с конца строки».

Недостатки

  • проблемы с хранением и обработкой символов произвольной длины;
  • увеличение затрат на хранение строк — значение «длина строки» также занимает место и в случае большого количества строк маленького размера может существенно увеличить требования алгоритма к оперативной памяти;
  • ограничение максимального размера строки. В современных языках программирования это ограничение скорее теоретическое, так как обычно размер строки хранится в 32-битовом поле, что даёт максимальный размер строки в 4 294 967 295 байт (4 гигабайта);
  • при использовании алфавита с переменным размером символа (например, UTF-8), в размере хранится не количество символов, а именно размер строки в байтах, поэтому количество символов необходимо считать отдельно.

Второй метод завершающего байта, это когда в строке просто присутствует признак ее окончания:

Преимущества

  • отсутствие дополнительной служебной информации о строке (кроме завершающего байта);
  • возможность представления строки без создания отдельного типа данных;
  • отсутствие ограничения на максимальный размер строки;
  • экономное использование памяти;
  • простота получения суффикса строки;
  • простота передачи строк в функции (передаётся указатель на первый символ);

Недостатки

  • долгое выполнение операций получения длины и конкатенации строк;
  • отсутствие средств контроля за выходом за пределы строки, в случае повреждения завершающего байта возможность повреждения больших областей памяти, что может привести к непредсказуемым последствиям — потере данных, краху программы и даже всей системы;
  • невозможность использовать символ завершающего байта в качестве элемента строки.
  • невозможность использовать некоторые кодировки с размером символа в несколько байт (например, UTF-16), т.к. во многих таких символах, например Ā (0x0100), один из байтов равен нулю (в то же время, кодировка UTF-8 свободна от этого недостатка).

Продолжение здесь!

Войти с помощью: 
avatar
5000