Журнал LinuxFormat - перейти на главную

LXF134:Vala

Материал из Linuxformat
Перейти к: навигация, поиск

Содержание

Vala и Genie Ам­би­ци­оз­ные но­вич­ки

Ува­жае­те C# как язык про­грам­ми­ро­ва­ния, но не до­ве­ряе­те тех­но­ло­ги­ям Microsoft? У Се­мё­на Еси­лев­ско­го есть для вас кое-что.

При напи­сании гра­фи­че­ских при­ло­жений от язы­ка про­грам­ми­ро­вания тре­бу­ет­ся на­ли­чие мно­гих по­ня­тий и кон­ст­рук­ций, ко­то­рые ред­ко ис­поль­зу­ют­ся в кон­соль­ных про­грам­мах. К ним от­но­сят­ся, на­при­мер, сиг­на­лы, лям­бда-функ­ции и воз­мож­ность уз­на­вать тип объ­ек­та во вре­мя вы­полнения про­грам­мы. В той или иной сте­пени эти воз­мож­но­сти реа­ли­зо­ва­ны толь­ко в скрип­то­вых язы­ках, та­ких как Python или Ruby, а так­же в язы­ках, ис­поль­зую­щих вир­ту­аль­ные ма­ши­ны — C# и Java. Од­на­ко ис­поль­зо­вание скрип­то­вых язы­ков оп­рав­да­но да­ле­ко не все­гда, из-за их невы­со­кой про­из­во­ди­тель­но­сти. Язык Java яв­но не при­жил­ся в на­столь­ных при­ло­жениях для Linux, а «тя­же­лое на­сле­дие» Microsoft оп­ре­де­ля­ет пред­взя­тое от­но­шение к язы­ку С# у раз­ра­бот­чи­ков сво­бод­но­го ПО.

Ес­ли же об­ра­тит­ся к ком­пи­ли­руе­мым язы­кам, то в ми­ре Linux без­раз­дель­но ца­рят C и C++. Имен­но на них реа­ли­зо­ва­ны все по­пу­ляр­ные GUI-ин­ст­ру­мен­та­рии, несмот­ря на то, что эти язы­ки пло­хо при­спо­соб­ле­ны для про­грам­ми­ро­вания гра­фи­че­ских при­ло­жений. В ре­зуль­та­те раз­ра­бот­чи­ки биб­лио­тек вы­ну­ж­де­ны тем или иным спо­со­бом об­хо­дить ог­раничения этих язы­ков.

Соз­да­те­ли Qt по­шли по пу­ти мо­ди­фи­ка­ции язы­ка С++, до­полнив его систе­мой сиг­на­лов и сло­тов и ме­та­объ­ект­ной ин­фор­ма­ци­ей. Стро­го го­во­ря, про­грам­мы, ис­поль­зую­щие Qt, напи­са­ны не на С++, а на неко­ем осо­бом язы­ке, ко­то­рый сна­ча­ла транс­ли­ру­ет­ся в С++ с по­мо­щью ме­та­объ­ект­но­го ком­пи­ля­то­ра (MOC).

Биб­лио­те­ка GTK+ напи­са­на на стан­дарт­ном С, ко­то­рый еще ме­нее удо­бен для GUI-при­ло­жений, чем С++. Что­бы внести в GTK+ объ­ект­но-ори­ен­ти­ро­ван­ные аб­ст­рак­ции и ин­фор­ма­цию о ти­пах объ­ек­тов, бы­ла соз­да­на биб­лио­те­ка GObject (http://library.gnome.org/devel/gobject/stable/). Ис­поль­зо­вать GObject в С на­пря­мую слож­но и неудоб­но, од­на­ко эта биб­лио­те­ка по­зво­ля­ет лег­ко соз­да­вать стан­дар­ти­зи­ро­ван­ные объ­ект­но-ори­ен­ти­ро­ван­ные при­вяз­ки [bindings] для дру­гих язы­ков про­грам­ми­ро­вания. Же­лание ис­поль­зо­вать го­то­вую объ­ект­ную систе­му GObject и удоб­ный вы­со­ко­уровневый син­так­сис при­ве­ли к по­яв­лению сра­зу двух но­вых язы­ков – Vala и Genie, о ко­то­рых и пой­дет речь в этой ста­тье.

Идео­ло­гия Vala и Genie

Соз­да­те­ли Vala и Genie до­ве­ли идею, за­ло­жен­ную в Qt, до ло­ги­че­ско­го за­вер­шения. Раз уж нуж­но до­пол­нять ба­зо­вый язык но­вы­ми кон­ст­рук­ция­ми, то луч­ше про­сто соз­дать но­вый язык бо­лее вы­со­ко­го уров­ня с мак­си­маль­но удоб­ным син­так­си­сом. Про­грам­мы, напи­сан­ные на Vala и Genie, сна­ча­ла транс­ли­ру­ют­ся в стан­дарт­ный C, а за­тем ком­пи­ли­ру­ют­ся. Объ­ект­ная мо­дель язы­ков ба­зи­ру­ет­ся на GObject, скры­той в недрах ком­пи­ля­то­ра.

Vala и Genie часто по­зи­циониру­ют­ся как язы­ки, об­лег­чаю­щие напи­сание про­грамм для Gnome. Мо­жет соз­дать­ся впе­чат­ление, что они – су­гу­бо спе­циа­ли­зи­ро­ван­ные. Это со­всем не так! Vala и Genie мо­гут ис­поль­зо­вать­ся в лю­бой систе­ме, ку­да пор­ти­ро­ва­на биб­лио­те­ка Glib (т. е. прак­ти­че­ски вез­де), а гра­фи­че­ский ин­тер­фейс на них мож­но соз­да­вать вез­де, где есть биб­лио­те­ки GTK+. Ком­пи­ля­тор Vala пре­крас­но ра­бо­та­ет в Linux, Mac OS Х и Windows, что де­ла­ет этот язык удоб­ным сред­ством для раз­ра­бот­ки кросс-плат­фор­мен­ных GUI-при­ло­жений с по­мо­щью GTK+. У ком­пи­ля­то­ра име­ет­ся ре­жим POSIX-со­вмести­мо­сти, в ко­то­ром уст­ра­ня­ет­ся да­же за­ви­си­мость от Glib, но це­ной по­те­ри неко­то­рых воз­мож­но­стей язы­ка.

Функ­цио­наль­но оба язы­ка прак­ти­че­ски иден­тич­ны и от­ли­ча­ют­ся толь­ко син­так­си­сом. Vala очень по­хож на C#, тогда как Genie яв­ля­ет­ся свое­об­раз­ной амаль­га­мой Python, D и Delphi. Ком­пи­ля­тор, ути­ли­ты и биб­лио­те­ки яв­ля­ют­ся об­щи­ми для обо­их язы­ков. Ком­пи­ля­тор раз­ли­ча­ет тип син­так­си­са по рас­ши­рению фай­лов – .vala и .gs, со­от­вет­ствен­но.

Про­грам­мы на Vala пре­вра­ща­ют­ся в код на C и по­это­му непо­сред­ствен­но ком­по­ну­ют­ся с внешними биб­лио­те­ка­ми без до­полнитель­ных «обер­ток». Для ис­поль­зо­вания лю­бой биб­лио­те­ки в Vala доста­точ­но соз­дать ин­тер­фейс­ный файл *.vapi с ин­ст­рук­ция­ми для ком­пи­ля­то­ра. Биб­лио­те­ки, напи­сан­ные на Vala и Genie, име­ют ав­то­ма­ти­че­ски сгенери­ро­ван­ные за­го­ло­воч­ные фай­лы и так­же мо­гут сра­зу же ис­поль­зо­вать­ся в С/С++.

В от­ли­чие от C# и Java, Vala – на­стоя­щий ком­пи­ли­руе­мый язык (хо­тя и с пред­ва­ри­тель­ной ста­ди­ей транс­ля­ции ко­да). Про­из­во­ди­тель­ность и рас­хо­ды па­мя­ти у про­грамм на Vala ма­ло от­ли­ча­ют­ся от из­на­чаль­но напи­сан­ных на C.

Vala пре­достав­ля­ет все воз­мож­но­сти со­вре­мен­ных объ­ект­но-ори­ен­ти­ро­ван­ных язы­ков и мно­гие удоб­ные кон­ст­рук­ции: клас­сы и ин­тер­фей­сы, свой­ства, сиг­на­лы, цикл foreach, лям­бда-функ­ции, неяв­ную ти­пи­за­цию [type inference], обоб­щен­ные клас­сы [generics], ав­то­ма­ти­че­ское или «руч­ное» управ­ление па­мя­тью, исклю­чения, кон­тракт­ное про­грам­ми­ро­вание и ре­гу­ляр­ные вы­ра­жения как часть язы­ка.

Биб­лио­те­ки, IDE, про­ек­ты

Язык Vala очень мо­лод, но несмот­ря на это, он уже «об­рос» впе­чат­ляю­щим ин­ст­ру­мен­та­ри­ем и да­же об­за­вел­ся соб­ствен­ной IDE. В стан­дарт­ной ин­стал­ля­ции Vala име­ют­ся при­вяз­ки к де­сят­кам биб­лио­тек (http://live.gnome.org/Vala/BindingsStatus). Сре­ди них – все биб­лио­те­ки GTK+, основ­ные биб­лио­те­ки плат­фор­мы Gnome, а так­же alsa, gsl, webkit, zlib, sqlite, OpenGL и мно­гие дру­гие. В Vala име­ет­ся соб­ствен­ная биб­лио­те­ка обоб­щен­ных кон­тейнеров Gee (http://live.gnome.org/Libgee), на­по­ми­наю­щая STL в C++ (под­робнее о ней ниже).

Под­держ­ка Vala име­ет­ся в несколь­ких по­пу­ляр­ных IDE (MonoDevelop, Anjuta, Eclipse), но са­мой ин­те­рес­ной яв­ля­ет­ся IDE Val(a)ide, напи­сан­ный це­ли­ком на Vala.

Val(a)ide очень про­ста, но со­дер­жит прак­ти­че­ски все необ­хо­ди­мое для ком­форт­ной ра­бо­ты с Vala. Име­ет­ся под­держ­ка про­ек­тов, под­свет­ка син­так­си­са, встро­ен­ная систе­ма сбор­ки на­по­до­бие Make. Очень удоб­но реа­ли­зо­ва­но под­клю­чение к про­ек­ту нуж­ных биб­лио­тек. Един­ствен­ным су­ще­ствен­ным недостат­ком Val(a)ide яв­ля­ет­ся от­сут­ствие ин­тег­ри­ро­ван­но­го от­лад­чи­ка, хо­тя ком­пи­ля­тор Vala под­дер­жи­ва­ет от­лад­ку че­рез стан­дарт­ный Gdb. По­сколь­ку Val(a)ide не достиг­ла да­же вер­сии 1.0, от­лад­чик в ней дол­жен еще поя­вить­ся.


Несмот­ря на мо­ло­дость язы­ка, на Vala напи­са­ны де­сят­ки про­грамм (http://live.gnome.org/Vala/#Projects_Developed_in_Vala). Vala проник и в об­ласть «ди­ст­ри­бу­ти­во­строения» – на нем ба­зи­ру­ет­ся ин­стал­ля­тор Paldo Linus, а на Genie – мно­гие ути­ли­ты для Puppy Linux.

В Ubuntu Vala уста­нав­ли­ва­ет­ся из ppa-ре­по­зи­то­рия. Доста­точ­но вве­сти в кон­со­ли сле­дую­щие коман­ды:

sudo add-apt-repository ppa:vala-team
sudo apt-get update
sudo apt-get install valide-dev libgee-dev

Это уста­но­вит биб­лио­те­ку кон­тейнеров Gee, IDE Val(a)ide, а так­же сам ком­пи­ля­тор и все нуж­ные фай­лы в ка­че­стве за­ви­си­мо­стей.

В дру­гих систе­мах Vala уста­нав­ли­ва­ет­ся из ре­по­зи­то­ри­ев или ис­ход­ных ко­дов, как опи­са­но на офи­ци­аль­ном сай­те (http://live.gnome.org/Vala#Download). Про­цесс сбор­ки ком­пи­ля­то­ра прост, так как един­ствен­ной за­ви­си­мо­стью яв­ля­ет­ся GLib вер­сии 2.14 или вы­ше.

Пер­вая про­грам­ма

Тра­ди­ци­он­но мы на­пи­шем про­стей­шую про­грам­му «Hello world!», но не в со­всем скуч­ном кон­соль­ном ва­ри­ан­те, а с ис­поль­зо­ванием GUI на GTK+ и в двух ва­ри­ан­тах – для Vala и Genie. Офи­ци­аль­наяn до­ку­мен­та­ция по Genie очень скуд­на, по­это­му до­полнитель­но ис­поль­зо­ва­лись сто­ронние ре­сур­сы (http://bkhome.org/genie/index.html). В Genie для струк­ту­ри­ро­вания ко­да ис­поль­зу­ет­ся от­сту­пы (как в Python). Они соз­да­ют­ся та­бу­ля­ция­ми, или про­бе­ла­ми, ес­ли в на­ча­ле фай­ла име­ет­ся ди­рек­ти­ва [indent=чис­ло про­бе­лов]. На­чнем с ва­ри­ан­та на Vala:

 hello.vala:
 using Gtk;
 int main (string[] args) {
    Gtk.init (ref args);
    var window = new Window (WindowType.TOPLEVEL);
    window.title = “First GTK+ Program”;
    window.set_default_size (300, 50);
    window.position = WindowPosition.CENTER;
    window.destroy.connect (Gtk.main_quit);
    var button = new Button.with_label (“Click me!);
    button.clicked.connect ((source) => {
        source.label = “Thank you”;
    });
    window.add (button);
    window.show_all ();
    Gtk.main ();
    return 0;
 }

Ском­пи­ли­ро­вать про­грам­му мож­но ко­ман­дой

valac --pkg gtk+-2.0 hello.vala

Вы­полнение лю­бой про­грам­мы в Vala на­чи­на­ет­ся с функ­ции main(), принимаю­щей мас­сив строк, со­дер­жа­щий па­ра­мет­ры команд­ной стро­ки. Сна­ча­ла, с по­мо­щью Gtk.init(ref args), инициа­ли­зи­ру­ет­ся GTK+. Ди­рек­ти­ва ref ука­зы­ва­ет, что па­ра­метр пе­ре­да­ет­ся по ссыл­ке, а не по зна­чению. Да­лее соз­да­ет­ся объ­ект Window с ис­поль­зо­ванием стан­дарт­ных кон­стант GTK+:

var window = new Window (WindowType.TOPLEVEL);

Возника­ет впе­чат­ление, что пе­ре­мен­ная window соз­да­ет­ся без ука­зания ти­па. На са­мом де­ле здесь сра­ба­ты­ва­ет ме­ханизм неяв­ной ти­пи­за­ции для локаль­ной пе­ре­мен­ной [type inference] по пра­вой части опе­ра­то­ра при­сваи­вания. Мож­но бы­ло бы объ­я­вить тип пе­ре­мен­ной яв­но:

// Яв­ная ти­пи­за­ция в Vala
Window window = new Window (WindowType.TOPLEVEL);

но для слож­ных ти­пов, осо­бен­но обоб­щен­ных, не­яв­ная ти­пи­за­ция ста­но­вит­ся про­сто спа­си­тель­ной. Срав­ни­те, на­при­мер, эти два объ­яв­ле­ния в Vala:

MyFoo<string, MyBar<string, int>> foo = new MyFoo<string, MyBar<string, int>>();
var foo = new MyFoo<string, MyBar<string, int>>();

Пер­вое чи­та­ет­ся с тру­дом, то­гда как вто­рое (с не­яв­ной ти­пи­за­ци­ей) го­раз­до по­нят­нее.

Да­лее за­да­ют­ся свой­ст­ва ок­на и на­зна­ча­ет­ся функ­ция-об­ра­бот­чик для сиг­на­ла ок­на destroy – в дан­ном слу­чае это Gtk.main_quit:

window.destroy.connect (Gtk.main_quit);

Эта ла­конич­ная запись на­мно­го про­ще и по­нятнее жут­ко­ва­то­го ко­да на чистом C в GTK+ и да­же мак­ро­са connect() в Qt.

Да­лее соз­да­ет­ся кноп­ка и на­зна­ча­ет­ся об­ра­бот­чик ее сиг­на­ла clicked. Вме­сто применения от­дель­ной функ­ции-об­ра­бот­чи­ка здесь «на ле­ту» соз­да­ет­ся бе­зы­мян­ная лям­бда-функ­ция. Кон­ст­рук­ция

(source) => { source.label = “Thank you”; }

воз­вра­ща­ет объ­ект, яв­ляю­щий­ся функ­ци­ей од­ной пе­ре­мен­ной (source), а имен­но та­кую сиг­на­ту­ру ожи­да­ет сиг­нал clicked. Тип пе­ре­мен­ной ука­зы­вать не нуж­но: он оп­ре­де­ля­ет­ся ком­пи­ля­то­ром ав­тoма­ти­че­ски и яв­ля­ет­ся ссыл­кой на объ­ект, вы­звав­ший сиг­нал, то есть на­шей кноп­кой.

На­конец, мы до­бав­ля­ем кноп­ку в ок­но, по­ка­зы­ва­ем его со­дер­жи­мое функ­ци­ей show_all() и вхо­дим в цикл об­ра­бот­ки со­бы­тий GTK+ с по­мо­щью Gtk.main(). Вы­ход из это­го цик­ла осу­ще­ств­ля­ет­ся толь­ко по­сле за­кры­тия ок­на про­грам­мы.


Та же про­грам­ма на язы­ке Genie вы­гля­дит еще бо­лее ла­ко­нич­но:

 hello.gs:
 uses
 	 Gtk
 init
 	 Gtk.init (ref args)
 	 var test = new TestWindow ()
 	 test.show_all ()
 	 Gtk.main ();
 class TestWindow : Window
 	 init
 		 title = “Test Window”
 		 set_default_size (300, 50)
 		 window_position = WindowPosition.CENTER
 		 destroy += Gtk.main_quit
 		 var button = new Button.with_label (“Click Me”)
 		 button.clicked += def (btn)
 			 btn.label = “Thank you!”
 		 add (button)

Ком­пи­ли­ру­ет­ся она ана­ло­гич­ным об­ра­зом

valac --pkg gtk+-2.0 hello.gs

Вы­полнение про­грам­мы в Genie на­чи­на­ет­ся с бло­ка init, на­хо­дя­ще­го­ся вне оп­ре­де­лений клас­сов и функ­ций. В от­ли­чие от пре­ды­ду­ще­го при­ме­ра, ис­поль­зу­ет­ся немно­го дру­гой под­ход – мы соз­да­ем класс TestWindow, унас­ле­до­ван­ный от стан­дарт­но­го Window. В кон­ст­рук­то­ре клас­са (блок init) вы­пол­ня­ют­ся те же дей­ствия, что и в пре­ды­ду­щем при­ме­ре. Син­так­сис при­сое­динения функ­ций-об­ра­бот­чи­ков к со­бы­ти­ям в Genie еще бо­лее прост, чем в Vala, и ис­поль­зу­ет опе­ра­тор +=:

destroy += Gtk.main_quit

Объ­яв­ле­ние лям­бда-функ­ции так­же на вид от­ли­ча­ет­ся, но по су­ти – все в точ­но­сти как в Vala:

button.clicked += def (btn)
	 btn.label = “Thank you!”

Яв­ное объ­яв­ле­ние пе­ре­мен­ных в Genie вы­гля­дит по-сво­ему, так как ис­поль­зу­ет­ся син­так­сис Pascal/Delphi с ука­за­ни­ем ти­па по­сле пе­ре­мен­ной:

int_val: int = 10
double_val: double = 12.5
button: Button = new Button.with_label (“Click me!”)

В основ­ном бло­ке init мы соз­да­ем эк­зем­п­ляр но­во­го клас­са, по­ка­зы­ва­ем эле­мен­ты ок­на функ­ци­ей show_all() и вхо­дим в цикл об­ра­бот­ки со­бы­тий.

Еще один нетри­ви­аль­ный мо­мент в обо­их при­ме­рах – это от­сут­ствие опе­ра­то­ров delete по­сле ди­на­ми­че­ско­го соз­дания объ­ек­тов опе­ра­то­ром new. Vala и Genie – язы­ки с ав­то­ма­ти­че­ским управ­лением па­мя­тью, од­на­ко, в от­ли­чие от Java, предусмотрено «руч­ное» управ­ление с по­мо­щью ука­за­те­лей, ес­ли необходимо.

Осо­бен­но­сти язы­ков

Пол­но­стью опи­сать син­так­сис двух язы­ков в ко­рот­кой ста­тье невоз­мож­но, но к сча­стью, это и не нуж­но. Все кон­ст­рук­ции язы­ка Vala бу­дут по­нят­ны лю­бо­му про­грам­ми­сту, зна­ко­мо­му с С++, С# или Java, а син­так­сис Genie от­ли­ча­ет­ся от стан­дарт­но­го Python толь­ко в де­та­лях. В то же вре­мя неко­то­рые осо­бен­но­сти этих язы­ков за­слу­жи­ва­ют упо­ми­нания.

Стро­ки

Все стро­ки в Vala и Genie име­ют фор­мат UTF-8. Тип string за­да­ет стро­ку про­из­воль­ной дли­ны, ко­то­рая яв­ля­ет­ся неиз­ме­няе­мым [immutable] объ­ек­том. Стро­ку мож­но объ­я­вить как стандарт­ным об­ра­зом, так и в сти­ле «стро­ки в трой­ных ка­выч­ках», зна­ко­мом по язы­ку Python:

string text = “Обыч­ная стро­ка”;
string str = “””Стро­ка в трой­ных ка­выч­ках (“verbatim string”).

В та­ких стро­ках не об­ра­ба­ты­ва­ют­ся спе­ци­аль­ные сим­во­лы \n, \t, \\ и т. д. Они мо­гут со­дер­жать ка­выч­ки и занимать несколь­ко строк.”””;

Стро­ки, пред­ва­ряе­мые сим­во­лом @, яв­ля­ют­ся «стро­ко­вы­ми шаб­ло­на­ми». В них мож­но встав­лять пе­ре­мен­ные и вы­ра­жения с по­мо­щью пре­фик­са “$”, как это де­ла­ет­ся во мно­гих скрип­то­вых язы­ках. Зна­чения встро­ен­ных в стро­ку пе­ре­мен­ных и вы­ра­жений ав­то­ма­ти­че­ски пре­об­ра­зу­ют­ся к стро­ко­во­му ти­пу. Удоб­ство та­ко­го спо­со­ба фор­ма­ти­ро­вания строк труд­но пе­ре­оценить:

int a = 10, b = 20;
string str = @”$a * $b = $(a * b)”; // Ре­зуль­ти­рую­щая стро­ка: “10*20 = 200”

По­лу­чить под­стро­ку или от­дель­ный сим­вол мож­но с по­мо­щью «сре­зов». От­ри­ца­тель­ные зна­че­ния ин­дек­сов от­счи­ты­ва­ют­ся от кон­ца стро­ки:

string greeting = “hello, world”;
string s1 = greeting[7:12]; // => “world”
string s2 = greeting[-4:-2]; // => “or”
unichar c = greeting[7]; // => ‘w’

Под­дер­жи­ва­ют­ся так­же мно­гие стан­дарт­ные стро­ко­вые функ­ции биб­лио­те­ки GLib.

Мас­си­вы

Мас­си­вы в Vala мо­гут быть ди­на­ми­че­ски­ми (соз­дан­ны­ми в ку­че) и ста­ти­че­ски­ми (соз­дан­ны­ми в сте­ке).

int[] a = new int[10]; // Ди­на­ми­че­ский мас­сив
int f[10]; // Ста­ти­че­ский мас­сив

Для ди­на­ми­че­ских (но не для ста­ти­че­ских) мас­си­вов под­дер­жи­ва­ет­ся до­бав­ле­ние эле­мен­тов «на ле­ту»:

int[] e = {}
e += 12;
e += 5;
e += 37;

Нуж­но иметь в ви­ду, что та­кая воз­мож­ность рас­смат­ри­ва­ет­ся исклю­чи­тель­но как еще один спо­соб инициа­ли­за­ции – стан­дарт­ные мас­си­вы не пред­на­зна­че­ны для ис­поль­зо­вания в ка­че­стве кон­тейнеров с пе­ре­мен­ным ко­ли­че­ством эле­мен­тов. Для этих це­лей луч­ше ис­поль­зо­вать клас­сы-кол­лек­ции из биб­лио­те­ки Gee (мас­си­вы, спи­ски, хэ­ши и т. п.).

Под­дер­жи­ва­ют­ся так­же мно­го­мер­ные мас­си­вы

int[,] c = new int[3,4];
int[,] d = {{2, 4, 6, 8},
{3, 5, 7, 9},
{1, 3, 5, 7}};
d[2,3] = 42;

Управ­ляю­щие кон­ст­рук­ции

Син­так­сис управ­ляю­щих кон­ст­рук­ций if, for, while, switch в Vala пол­но­стью ана­ло­ги­чен син­так­си­су C/C++, а в Genie очень по­хож на син­так­сис Python. От­дель­но­го внимания за­слу­жи­ва­ет толь­ко кон­ст­рук­ция foreach, по­зво­ляю­щая лег­ко пе­ре­би­рать эле­мен­ты мас­си­вов и кол­лек­ций:

foreach (int a in int_array) { stdout.printf(“%d\n”, a); }

В Genie в ка­че­ст­ве foreach вы­сту­па­ет раз­но­вид­ность цик­ла for:

for s in args do print s

Тип пе­ре­мен­ной s ком­пи­ля­тор оп­ре­де­ля­ет ав­то­ма­ти­че­ски.

Де­ле­га­ты

В Vala и Genie нет ука­за­те­лей на функ­ции. Ес­ли нужно пе­ре­дать од­ну функ­цию в ви­де па­ра­мет­ра дру­гой, ис­поль­зу­ют­ся де­ле­га­ты:

 delegate void DelegateType(int a);
 void f1(int a) {
   stdout.printf(%d\n”, a);
 }
 void f2(DelegateType d, int a) {
   d(a);      // Вызов делегата с переданным параметром
 }
 void main() {
   f2(f1, 5); // Функция f1 передается в параметре-­делегате
 }

Код с де­ле­га­та­ми чи­та­ет­ся ку­да луч­ше, чем с ука­за­те­ля­ми в сти­ле С/С++.

Обоб­щен­ные клас­сы

Vala и Genie под­дер­жи­ва­ют обоб­щен­ные клас­сы, то есть клас­сы, способные ра­бо­тать с раз­ны­ми ти­па­ми дан­ных. Кон­крет­ный тип ука­зы­ва­ет­ся при соз­дании эк­зем­п­ля­ра клас­са. Обоб­щен­ные клас­сы [Generics] не яв­ля­ют­ся пол­ным ана­ло­гом шаб­ло­нов [Templates] в С++; един­ствен­ное их на­зна­чение – из­бе­жать напи­сания од­но­го и то­го же ко­да для несколь­ких ти­пов дан­ных, ко­то­рые об­ра­ба­ты­ва­ют­ся оди­на­ко­вым об­ра­зом. Обоб­щен­ные клас­сы не пред­на­зна­че­ны для шаб­лон­но­го ме­та­про­грам­ми­ро­вания, как в С++. Син­так­сис обоб­щен­ных клас­сов в Vala по­хож на шаб­ло­ны в С++, но бо­лее прост. Имя обоб­щен­но­го ти­па за­да­ет­ся в уг­ло­вых скоб­ках:

 public class Adder<G> : GLib.Object {
   private G data;
   public void do(G a, G b) {
      this.data = a+b;
   }
   public G get_sum() {
      return this.data;
   }
 }
 var v = new Adder<int>();

В Genie имя обоб­щен­но­го ти­па за­да­ет­ся кон­ст­рук­ци­ей «оf имя_ти­па»:

 class Adder of G : Object
    _data : G
    def do(a: G, b: G)
      _data = a+b;
    def get_sum(): G
      return _data
 var v = new Adder of int

Пе­ре­мен­ные, на­чи­наю­щие­ся со зна­ка под­чер­ки­ва­ния, ав­то­ма­ти­че­ски по­лу­ча­ют ат­ри­бут private.

Кон­тракт­ное про­грам­ми­ро­ва­ние

Vala под­дер­жи­ва­ет ба­зо­вые кон­ст­рук­ции кон­тракт­но­го про­грам­ми­ро­ва­ния requires и ensures:

 double method_name(int x, double d)
    requires (x > 0 && x < 10)
    requires (d >= 0.0 && d <= 1.0)
    ensures (result >= 0.0 && result <= 10.0)
 {
  return d * x;
 }

Спе­ци­аль­ная «ма­ги­че­ская» пе­ре­мен­ная result име­ет тип, воз­вра­щае­мый функ­ци­ей.

Биб­лио­те­ка обоб­щен­ных кон­тей­не­ров Gee

Биб­лио­те­ка Gee в Vala вы­пол­ня­ет ту же функ­цию, что и STL в C++. В Gee име­ют­ся струк­ту­ры дан­ных и ите­ра­то­ры, но, в от­ли­чие от STL, нет ал­го­рит­мов. Син­так­сис шаб­лон­ных клас­сов Gee очень по­хож на син­так­сис C++, так что про­грам­ми­сты, при­вык­шие к шаб­лон­ным кон­тейнерам в C++, бу­дут чув­ство­вать се­бя как до­ма. Gee со­дер­жит несколь­ко клас­сов-кол­лек­ций, са­мы­ми час­то ис­поль­зуе­мы­ми из ко­то­рых яв­ля­ют­ся век­тор ArrayList<G>, спи­сок LinkedList<G> и ас­со­циа­тив­ный кон­тейнер HashMap<K,V>. Кон­тейнеры Gee на­мно­го сильнее ин­тег­ри­ро­ва­ны в ба­зо­вый язык, чем кон­тейнеры STL. На­при­мер, лю­бой кон­тейнер мож­но ис­поль­зо­вать в цик­лах foreach:

 var list = new ArrayList<int> ();
 list.add (1); // До­бав­ле­ние эле­мен­тов
 list.add (2);
 list.add (4);
 list.insert (2, 3); // Встав­ка эле­мен­та
 list.remove_at (3); // Удаление элемента
 foreach (int i in list) { // Интеграция в цикл foreach
   stdout.printf (%d\n”, i);
 }
 list[2] = 10; // Дос­туп по ин­дек­су

Про­ве­рить на­ли­чие эле­мен­та в лю­бом кон­тей­не­ре мож­но опе­ра­то­ром in:

if (2 in list) { // Аналогично list.contains(2)
  stdout.printf (“Двой­ка в спи­ске есть!\n”);
}

В ито­ге

По­яв­ление лю­бо­го но­во­го язы­ка про­грам­ми­ро­вания обыч­но вы­зы­ва­ет опа­сения, что он ока­жет­ся оче­ред­ным нежизнеспо­соб­ным курь­е­зом. Vala и Genie бла­го­по­луч­но из­бе­жа­ли этой уча­сти. Эти язы­ки ба­зи­ру­ют­ся на ста­биль­ной и очень популярной биб­лио­те­ке GLib, но по­зво­ля­ют про­грам­ми­сту ра­бо­тать с со­вре­мен­ным ком­пи­ли­руе­мым язы­ком вы­со­ко­го уров­ня, при пол­ной со­вмести­мости с C. Vala и Genie отлич­но при­спо­соб­ле­ны для напи­сания GUI-при­ло­жений с ис­поль­зо­ванием GTK+ и кар­ди­наль­но об­лег­ча­ют ра­бо­ту с этим гра­фи­че­ским ин­ст­ру­мен­та­ри­ем. Мож­но ска­зать, что Vala– это «C# без вир­ту­аль­ной ма­ши­ны», а Genie – «ком­пи­ли­руе­мый Python». Про­из­во­ди­тель­ность этих язы­ков близ­ка к чисто­му C, а удоб­ство син­так­си­са и бо­гат­ство кон­ст­рук­ций – к скрип­то­вым язы­кам. Vala и Genie будут достой­ным до­полнением ар­се­на­ла лю­бо­го про­грам­ми­ста, осо­бен­но ра­бо­таю­ще­го с GTK+.

Персональные инструменты
купить
подписаться
Яндекс.Метрика