מדריך ל־Vala

הקדמה

הצהרה: Vala הוא מיזם מתמשך ותכונותיו עשויות להשתנות, אך אשתדל לשמור על מדריך זה מעודכן. כמו כן, לא מובטח כי השיטות המוצעות הן הטובות ביותר, אך אשתדל להגיע לכך.

מהי Vala ?

Vala היא שפת תכנות חדשה המאפשרת שיטות תכנות חדישות לכתיבת יישומים הרצים על גבי ספריות זמן הריצה של GNOME, במיוחד GLib ו־GObject. פלטפורמה זו מספקת זה מכבר סביבת תכנות מלאה, עם תכונות דוגמת מערכת טיפוסים דינמית וסיוע בניהול הזיכרון. לפני Vala, הדרכים היחידות לתכנות עבור הפלטפורמה היו עם שפות דמויות C, החושפות לעתים קרובות פרטים לא רצויים, עם שפות תכנות עילית המטופלות באמצעות מכונה וירטואלית כמו Python או Mono C#‎, או לחלופין, עם C++‎ דרך ספריות מעטפת.

Vala שונה מכל השיטות הללו, בכך שהיא מהודרת לקוד בשפת C, אשר ניתן להדר ולהריץ אותו ללא תמיכה בספריות נוספות מעבר לפלטפורמת GNOME. יש לכך כמה השלכות, החשובות שבהן:

  • ביצועי תכניות שנכתבו ב־Vala צריכים להיות דומים לאלה שנכתבו ישירות ב־C, בעוד קל ומהיר יותר לכתוב ולתחזק אותן.
  • יישום Vala יכול לעשות כל דבר שניתן לעשות ב־C. בעוד Vala מציגה תכונות רבות שאינן זמינות ב־C, הן ממופות ל־C, על אף שלעתים קרובות כתיבתן ישירות קשה או אורכת זמן רב.

ככזו, בעוד Vala היא שפה חדישה עם כל התכונות שהיית מצפה להן, היא צוברת את כוחה מהפלטפורמה הקיימת, ולכן יש לעמוד בכמה מהכללים שנקבעו על ידהּ.

למי מדריך זה מיועד ?

מדריך זה לא יכנס לעומק שיטות התכנות הבסיסיות. הוא יסביר בקצרה את עקרונות התכנות מונחה העצמים ויתמקד באופן יישום המושגים ב־Vala. ככזה, יועיל ניסיון במגוון רחב של שפות תכנות, אם כי ידע מעמיק בכל שפה אינו נדרש.

Vala חולקת הרבה מתחביר Mono C#‎, אך אנסה להימנע מתיאור תכונות כמושגים או הבדלים עם C#‎ או Java, במטרה להפוך את המדריך לנגיש יותר.

מה שיהיה שימושי זה הבנה סבירה של C. בעוד אין צורך בכך להבנת Vala עצמה, חשוב להבין כי תכניות Vala מבוצעות כמו C, ולעתים קרובות יש הידוד עם ספריות C. הבנת C תהפוך את הבנת Vala לעומק להרבה יותר קלה להשגה.

תכנית ראשונה

למרבה הצער זה צפוי, ובכל זאת:

class Demo.HelloWorld : GLib.Object {

    public static int main(string[] args) {

        stdout.printf("Hello, World\n");

        return 0;
    }
}

כמובן, זוהי תכנית שלום עולם ב־Vala. אני מצפה שחלקים מתכנית זו מוכרים לך היטב, אך כדי להיות יסודי אעבור על התכנית צעד אחר צעד.

class Demo.HelloWorld : GLib.Object {

שורה זו מזהה את תחילת הגדרת המחלקה. מחלקה ב־Vala דומה מאוד ברעיון לשפות אחרות. מחלקה היא למעשה סוג של עצם, אשר ניתן ליצור ממנו מופעים, אשר לכולם אותן התכונות. יישום סוג זה של מחלקה מטופל על ידי הספרייה GObject, אך אין בכך חשיבות לשימוש כללי.

חשוב לציין כי המחלקה הוגדרה במיוחד כתת מחלקה של GLib.Object. הסיבה לכך היא ש־Vala מאפשרת סוגים אחרים של מחלקה, אך ברוב המקרים זה הסוג שתרצה. למעשה, חלק מתכונות Vala קיימות רק במחלקות הנגזרות מ־Object של Glib.

חלקים אחרים של שורה זו מציגים את השימוש במרחבי שם ובשמות מלאים, אם כי אלה יוסברו בהמשך.

public static int main(string[] args) {

זו תחילת הגדרת שיטה. שיטה היא פונקציה הקשורה לסוג של עצם ויכולה להתבצע על עצם מסוג זה. משמעותה של שיטה סטטית היא שניתן לקרוא לה ללא מופע של הסוג. משמעות העובדה שהשיטה נקראת main ושיש לה חתימה היא ש־Vala תזהה אותה כנקודת כניסה לתכנית.

השיטה main אינה חייבת להיות מוגדרת בתוך מחלקה. אולם, אם היא מוגדרת בתוך מחלקה היא חייב להיות static. לא משנה אם היא public או private. הערך המוחזר יכול להיות int או void. עם void כערך מוחזר התכנית תסיים במרומז עם קוד יציאה 0. פרמטר מערך המחרוזות מכיל פרמטרי שורת פקודה ואינו בגדר חובה.

stdout.printf("Hello, World\n");

stdout הוא עצם במרחב השם GLib אשר Vala מבטיחה שניתן לגשת אליו. השורה מורה ל־Vala לבצע את השיטה הנקראת printf של העצם stdout, עם המחרוזת "Hello World" כפרמטר. ב־Vala, תחביר זה תמיד ישמש לקריאה לשיטה על עצם, או לגישה לנתוני עצמים. ‎\n הם רצף תווים לשורה חדשה.

return 0;

return מחזיר ערך למתקשר ומסיים ביצוע השיטה main, אשר גם מסיים את ביצוע התכנית. הערך המוחזר מהשיטה main נלקח לקוד היציאה של התכנית.

השורות האחרונות פשוט מסיימות הגדרות השיטה והמחלקה.

הידור והרצה

בהנחה ש־Vala מותקנת, כל שנדרש כדי להדר ולהריץ את התכנית זה:

$ valac hello.vala
$ ./hello

valac הוא מהדר Vala, אשר מהדר קוד Vala לתוך קובץ בינארי. שם הקובץ הבינארי יהיה זהה לשם קובץ המקור, ולאחר מכן ניתן להריצו ישירות על המכונה. ניתן לנחש את הפלט.

בסיס

קבצי מקור והידור

קוד Vala נכתב בקבצים עם סיומת ‎.vala ‏Vala אינה מחייבת מבניות כמו בשפות דמויות Java – אין מושגים של חבילות או קבצי מחלקות באותה הצורה. במקום זאת, מבנים מוגדרים על ידי טקסט בכל אחד מן הקבצים, המתארים את המיקום הלוגי של הקוד עם מבנים כמו מרחבים. כאשר מהדרים קוד Vala, נותנים למהדר רשימה של הקבצים הדרושים, ו־Vala אחראית להבין איך הם מתאימים יחד.

כתוצאה מכך ניתן לשים הרבה מחלקות או פונקציות בתוך קובץ כפי שנרצה, אפילו שילוב חלקים של מרחבי שם שונים יחד. זה לא בהכרח רעיון טוב. ישנן מוסכמות מסוימות שנרצה לעקוב אחריהן. דוגמה טובה כיצד בנוי מיזם ב־Vala הוא מיזם Vala עצמו.

כל קבצי המקור עבור אותה החבילה מסופקים כפרמטרי שורת פקודה למהדר Vala, ‏valac, יחד עם דגלי מהדר. זה פועל בצורה דומה לדרך בה קוד המקור של Java מהודר, לדוגמה:

$ valac compiler.vala --pkg libvala

יּווצר קובץ בינארי בשם compiler שמקושר עם החבילה libvala. למעשה, כך נוצר המהדר valac !

אם נרצה לתת שם שונה לקובץ הבינארי או אם מספר קבצים הועבר למהדר, ניתן לציין במפורש את שם הקובץ הבינארי עם האפשרות ‎-o:

$ valac source1.vala source2.vala -o myprogram
$ ./myprogram

העברת האפשרות ‎-C ל־valac תורה שלא להדר את התכנית לקובץ בינארי. במקום זאת, הפלט יהיה קוד ביניים בשפת C עבור כל אחד מקבצי המקור ב־Vala בקובץ מקור C מקביל, במקרה זה source1.c ו־source2.c. אם נביט בתוכן הקבצים נראה כי תִכנות מחלקה ב־Vala שווה ערך לאותה המשימה ב־C, אך קצר בהרבה. כמו כן ניתן להבחין כי המחלקה כתובה בצורה דינמית במערכת ההפעלה. זוהי דוגמה טובה לכוחה של פלטפורמת GNOME, אך כפי שצוין קודם, אין צורך בפרטים אלה כדי להשתמש ב־Vala.

לקבלת קובץ כותר C של המיזם יש להשתמש באפשרות ‎-H:

$ valac hello.vala -C -H hello.h

סקירת התחביר

תחביר Vala הוא תערובת המבוססת במידה רבה על C#‎. כתוצאה מכך, רוב סעיף זה יהיה מוכר למתכנתי שפות דמויות C, לכן אקצר כאן בתיאור.

מרחבים מוגדרים באמצעות סוגריים. עצמים או הפניות תקפים רק בין { ו־‎}. מפרידים אלה משמשים גם להגדרת מחלקות, שיטות, בלוקים של קוד וכו', לכן באופן אוטומטי יש להם טווח. Vala אינה מקפידה על מיקום הצהרת המשתנים.

מזהה מוגדר על ידי סוג ושם, למשל int c משמעותו שלם הנקרא c. במקרה של טיפוסי ערך זה גם יוצר מופע של הטיפוס. לטיפוסי הפניה זה רק מגדיר הפניה חדשה, שבתחילה אינה מצביעה לשום דבר.

לשמות המזהים אותם הכללים החלים על מזהי C: התו הראשון חייב להיות אחד מהתווים [a–z], [A–Z] או קו תחתון, התווים שלאחר מכן יכולים להיות גם אחת מהספרות [0–9]. שאר תווי יוניקוד אסורים. ניתן להשתמש במילה שמורה כשם מזהה על ידי הוספת התו '@' כקידומת. תו זה אינו חלק מהשם. לדוגמה, ניתן לתת לפונקציה את השם foreach על ידי כתיבת ‎@foreach, על אף שזו מילה שמורה ב־Vala.

טיפוסי הפניה נוצרים באמצעות סימן הפעולה new ושם של שיטה בנאית, שבדרך כלל זה רק שם הטיפוס, למשל Object o = new Object()‎ יוצר Object חדש ו־o מפנה אליו.

הערות

Vala מאפשרת הערות בקוד בדרכים שונות.

// Comment continues until end of line

/* Comment lasts between delimiters */

/**
 * Documentation comment
 */

הן מטופלות כמו ברוב השפות האחרות, לכן נדרש הסבר קצר. הערות תיעוד למעשה אינן מיוחדות ל־Vala, אך כלי יצירת תיעוד כמו Valadoc יזהה אותן.

טיפוסי נתונים

באופן כללי יש שני סוגי נתונים ב־Vala: טיפוסי הפניה וטיפוסי ערך. שמות אלה מתארים איך מופעים מטיפוסים אלה פועלים במערכת – טיפוסי ערך מועתקים בכל פעם שמוקצה מזהה חדש, טיפוסי הפניה אינם מועתקים, במקום זה מזהה חדש הוא פשוט הפניה חדשה לאותו עצם.

קבוע מוגדר על ידי הצבת המילה השמורה const לפני הטיפוס. מוסכמת השמות לקבועים הוא ALL_UPPER_CASE.

טיפוסי ערך

Vala תומכת בקבוצה של טיפוסים פשוטים, כפי שעושות רוב השפות האחרות.

  • בית, char, uchat; השמות הם char מסיבות היסטוריות.

  • תו, unichar; תו יוניקוד 32 סיביות.

  • שלם, int, uint.

  • שלם גדול, long, ulong.

  • שלם קטן, short, ushort.

  • שלם בגודל מובטח, int8, int16, int32, int64 וגרסות שאינן חתומות uint8, uint16, uint32, uint64. המספרים מציינים את האורך בסיביות.

  • מספר נקודה צפה, float, double.

  • בוליאני, bool; ערכים אפשריים הם true ו־false.

  • מבנה, struct.

  • רשומה, enum; מיוצגת על ידי ערכים שלמים, לא כמחלקות כמו רשומות Java.

להלן כמה דוגמות.

/* atomic types */
unichar c = 'u';
float percentile = 0.75f;
const double MU_BOHR = 927.400915E-26;
bool the_box_has_crashed = false;

/* defining a struct */
struct Vector {
    public double x;
    public double y;
    public double z;
}

/* defining an enum */
enum WindowType {
    TOPLEVEL,
    POPUP
}

יתכן ולרוב הטיפוסים הללו גדלים שונים בפלטפורמות שונות, להוציא טיפוסי השלמים בגודל מובטח. סימן הפעולה sizeof מחזיר את הגודל בבתים שמשתנה מטיפוס מסוים תופס בבתים:

ulong nbytes = sizeof(int32);    // nbytes will be 4 (= 32 bits)

ניתן לקבוע הערכים את המזעריים והמרביים של טיפוסים מספריים עם ‎.MIN ו־‎.MAX, למשל int.MIN ו־int.MAX.

מחרוזות

טיפוס הנתונים עבור מחרוזות הוא string. מחרוזות Vala הן בקידוד UTF-8 ואינן ניתנות לשינוי.

string text = "A string literal";

Vala מציעה תכונה הנקראת מחרוזת מילה במילה. אלה מחרוזות שבהן תווים מיוחדים (כמו ‎\n) לא יפורשו, מעברי שורה יִּשמרו, ומרכאות אינן צריכות להיות מוסוות. הן מוקפות במרכאות משולשות. הזחה לאחר שבירת שורה היא חלק מהמחרוזת.

string verbatim = """This is a so-called "verbatim string".
Verbatim strings don't process escape sequences, such as \n, \t, \\, etc.
They may contain quotes and may span multiple lines.""";

מחרוזות המתחילות בתו '@' הן מחרוזות תבניות. הן יכולות להעריך משתנים וביטויים המוטבעים לאחר התו '$':

int a = 6, b = 7;
string s = @"$a * $b = $(a * b)";  // => "6 * 7 = 42"

סימני פעולת ההשואה == ו־=! משווים תוכן של שתי מחרוזות, בניגוד להתנהגות Java אשר במקרה זה היתה בודקת שוויון הפניה.

ניתן לחתוך מחרוזת עם [start:end]. ערכים שליליים מייצגים עמודות ביחס לסוף המחרוזת:

string greeting = "hello, world";
string s1 = greeting[7:12];        // => "world"
string s2 = greeting[-4:-2];       // => "or"

יש לשים לב שמפתח ב־Vala מתחיל מ־0 כמו ברוב השפות. החל מ־Vala גרסה 0.11 ניתן לגשת לבית אחד של המחרוזת עם [index]:

uint8 b = greeting[7];             // => 0x77

אולם, לא ניתן להקצות ערך חדש בגודל בית לעמודה זו, מאחר ומחרוזות Vala אינן ניתנות לשינוי.

לרבים מהטיפוסים הבסיסיים יש שיטות לניתוח ולהמרה למחרוזות, לדוגמה:

bool b = bool.parse("false");           // => false
int i = int.parse("-52");               // => -52
double d = double.parse("6.67428E-11"); // => 6.67428E-11
string s1 = true.to_string();           // => "true"
string s2 = 21.to_string();             // => "21"

שתי שיטות שימושיות לכתיבת ולקריאת מחרוזות למסוף ומהמסוף, בהתאמה (ולבדיקות ראשונות עם Vala), הן stdout.printf()‎ ו־stdin.read_line()‎:

stdout.printf("Hello, world\n");
stdout.printf("%d %g %s\n", 42, 3.1415, "Vala");
string input = stdin.read_line();
int number = int.parse(stdin.read_line());

אנו כבר מכירים את stdout.printf()‎ מהדוגמה שלום עולם. למעשה, שיטה זו יכולה לקבל מספר שרירותי של פרמטרים מטיפוסים שונים, בעוד הפרמטר הראשון הוא תבנית מחרוזת, עם אותם הכללים של תבנית מחרוזות C. עבור פלט שגיאה יש להשתמש ב־stderr.printf()‎ במקום stdout.printf()‎.

בנוסף, ניתן להשתמש בסימן הפעולה in כדי לבדוק אם מחרוזת אחת מכילה אחרת, למשל:

if ("ere" in "Able was I ere I saw Elba.") ...

למידע נוסף, ראה סקירה מלאה של מחלקת המחרוזות.

כמו כן זמינה תכנית דוגמה המציגה שימוש במחרוזות.

מערכים

מערך מוצהר על ידי מתן שם של טיפוס ואחריו [], ונוצר על ידי שימוש בסימן הפעולה new. למשל, int[] a = new int[10]‎ ליצירת מערך של שלמים. ניתן להשיג את אורך המערך על ידי המשתנה החבר length. למשל int count = a.length‎. יש לשים לב כי כתיבת Object[] a = new Object[10]‎ אינה יוצרת עצמים, אלא רק מערך לאחסן אותם.

int[] a = new int[10];
int[] b = { 2, 4, 6, 8 };

ניתן לחתוך מערך עם [start:end]:

int[] c = b[1:3];     // => { 4, 6 }

חתיכת מערך מחזירה הפניה למידע הדרוש, לא העתק. אולם, הקצאת החתיכה לבעלות משתנה (כפי שנעשה לעיל) תיצור עותק. בכדי להימנע מיצירת עותק, יש להקצות את החתיכה למערך unowned או להעבירו ישירות לפרמטר (פרמט מוגדר בברירת מחדל unowned):

unowned int[] c = b[1:3];     // => { 4, 6 }

מערך רב ממדי מוגדר עם [,] או [,,] וכן הלאה:

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

סוג זה של מערך מיוצג על ידי בלוק אחד רצוף בזיכרון. מערכים רב ממדיים מורכבים ([][], נקראים גם "מערכים מוערמים" או "מערכים של מערכים"), בהם כל שורה בעלת אורך שונה, עדיין אינם נתמכים.

למציאת ארכו של כל ממד במערך רב ממדי, החבר length הופך למערך, המאחסן את ארכו של כל ממד בהתאמה.

int[,] arr = new int[4,5];
int r = arr.length[0];
int c = arr.length[1];

יש לשים לב כי לא ניתן לקבל מערך חד ממדי ממערך רב ממדי, או אף לחתוך מערך רב ממדי:

int[,] arr = {{1,2},
                {3,4}};
int[] b = arr[0];  // won't work
int[] c = arr[0,];  // won't work
int[] d = arr[:,0];  // won't work
int[] e = arr[0:1,0];  // won't work
int[,] f = arr[0:1,0:1];  // won't work

ניתן לצרף איברים למערך באופן דינמי באמצעות סימן הפעולה ‎=+. אולם, זה עובד רק עבור הגדרות מקומיות או מערכים פרטיים. אם צריך, המערך מוקצה מחדש באופן אוטומטי. באופן פנימי, הקצאה מחדש זו מתבצעת בגדלים הגדלים בחזקה 2, מסיבות יעילות זמן הריצה. אולם, ‎.length מכיל את מספר האיברים המעשי, לא את הגודל הפנימי.

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

ניתן לשנות גודל של מערך על ידי קריאה ל־resize()‎ עליו. התוכן המקורי יישמר (ככל האפשר).

int[] a = new int[5];
a.resize(12);

ניתן להציב סוגריים מרובעים לאחר המזהה יחד עם ציון גודל, כך שיתקבל מערך בגודל קבוע. מערכים בגודל קבוע מוקצים על הערימה (אם משמשים כמשתנים מקומיים) או מוקצים בשורה (אם משמשים כשדות), ולא ניתנים להקצאה מחדש מאוחר יותר.

int f[10];     // no 'new ...'

Vala לא מבצעת בדיקת גבולות לגישה למערכים בזמן ריצה. אם יש צורך ביותר בטיחות, יש להשתמש במבנה נתונים מתוחכם יותר כמו ArrayList. נלמד על כך יותר בפסקה על אוספים.

טיפוסי הפניה

טיפוסי הפניה הם כל הטיפוסים המוגדרים כמחלקה, ללא קשר אם הם צאצאים של Object מ־Glib או לא. Vala תבטיח שכאשר יועבר עצם על ידי הפניה, המערכת תעקוב אחר מספר ההפניות הקיימות כרגע, על מנת לנהל את הזיכרון בשבילך. ערך של הפניה שלא מצביעה לשום מקום הוא null. עוד על מחלקות ותכונותיהן, בפסקה אודות תכנות מונחה עצמים.

/* defining a class */
class Track : GLib.Object {             /* subclassing 'GLib.Object' */
    public double mass;                 /* a public field */
    public double name { get; set; }    /* a public property */
    private bool terminated = false;    /* a private field */
    public void terminate() {           /* a public method */
        terminated = true;
    }
}

המרת טיפוס סטטית

ב־Vala, ניתן להמיר משתנה מטיפוס אחד לאחר. להמרת טיפוס סטטית, משתנה מומר על ידי שם הטיפוס הרצוי בסוגריים. המרה סטטית לא כופה אף בדיקת בטיחות הטיפוס בזמן ריצה. זה עובד עבור כל טיפוסי Vala. לדוגמה:

int i = 10;
float j = (float) i;

Vala תומכת במנגנון המרה נוסף הנקרא המרה דינמית, המבצע בדיקת טיפוס בזמן ריצה, ויתואר בפסקה אודות תכנות מונחה עצמים.

הסק טיפוס

ל־Vala מנגנון הנקרא הסק טיפוס, באמצעותו ניתן להגדיר משתנה מקומי באמצעות var במקום טיפוס נתון, כל עוד חד משמעי באיזה טיפוס מדובר. הטיפוס מוסק מהצד הימני של ההוראה. זה עוזר להפחית עודף מיותר בקוד שלך מבלי להקריב הקלדה סטטית.

var p = new Person();     // same as: Person p = new Person();
var s = "hello";          // same as: string s = "hello";
var l = new List<int>();  // same as: List<int> l = new List<int>();
var i = 10;               // same as: int i = 10;

זה עובד רק עבור משתנים מקומיים. הסק טיפוס שימושי במיוחד בטיפוסים עם פרמטרי טיפוס כללי (עוד על כך מאוחר יותר). נשווה

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

ל־

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

הגדרת טיפוס חדש מאחר

הגדרת טיפוס חדש היא עניין לגזור מהאחד שצריך. להלן דוגמה:

/* Define a new type from a container like GLib.List with elements type GLib.Value */
public class ValueList : GLib.List<GLib.Value> {
        [CCode (has_construct_function = false)]
        protected ValueList ();
        public static GLib.Type get_type ();
}

סימני פעולה

=

השמה. הפרמטר השמאלי חייב להיות מזהה, וזה הימני חייב להיות ערך או הפניה מתאימה.

+, -, /, *, %

פעולה חשבונית בסיסית, חלה על פרמטרים שמשאלהּ ומימינהּ. סימן הפעולה + יכול לשרשר מחרוזות.

+=, -=, /=, *=, %=

סימן פעולה חשבונית בין שני פרמטרים, כאשר זה השמאלי חייב להיות מזהה, אליו תוקצה התוצאה.

++, --

סימני פעולת תוספת ופיחות עם השמה מפורשת. אלה מקבלים פרמטר אחד, אשר חייב להיות מזהה של טיפוס נתונים פשוט. הערך ישתנה ויוקצה בחזרה למזהה. ניתן להציב סימני פעולה אלה או כתחילית או כסופית - עם הראשון אמדן הערך של ההצהרה יהיה הערך המחושב החדש, עם האחרון הערך המקורי יוחזר.

|, ^, &, ~, |=, &=, ^=

סימני פעולה על סיביות: או, או מוציא, וגם, שלילה (משמאל לימין: or, xor, and, not). הקבוצה השנייה כוללת השמה ומקבילה לגרסות הפעולות החשבוניות. ניתן להחיל את הללו על כל אחד מטיפוסי הנתונים הפשוטים (אין סימן פעולת השמה מצורף ל־~ כיוון שזו פעולה הפועלת על איבר יחיד. הפעולה שוות הערך היא a = ~a).

<<, >>

סימני פעולת הסטת סיביות, הסטת הפרמטר השמאלי מספר סיביות בהתאם לפרמטר הימני.

<<=, >>=

סימני פעולת הסטת סיביות, הסטת הפרמטר השמאלי מספר סיביות בהתאם לפרמטר הימני. הפרמטר השמאלי חייב להיות מזהה, אליו תוקצה התוצאה.

==

בדיקת שוויון. מעריך לערך bool תלוי שוויון הפרמטרים השמאלי והימני. במקרה של טיפוסי ערך המשמעות היא שהערכים שלהם שווים, במקרה של טיפוסי הפניה שהעצמים הם אותם המופעים. יוצא מן הכלל לכלל זה הוא הטיפוס string אשר נבדק לשוויון לפי ערך.

<, >, >=, <=, !=

בדיקת אי שוויון. מעריך לערך bool תלוי אי שוויון הפרמטרים השמאלי והימני באופן המתואר. אלה תקפים עבור טיפוסי נתונים פשוטים והטיפוס string. עבור מחרוזות, סימני פעולה אלה משווים את הסדר המילוני.

!, &&, ||

סימני פעולות היגיון: שלילה, וגם, או (משמאל לימין: not, and, or). ניתן להחיל את הללו על ערכים בוליאניים – הראשון מקבל רק ערך אחד והאחרים שניים.

? :

סימן פעולת תנאי משולש. מעריך תנאי, ומחזיר או את הערך השמאלי או הימני של תת הביטוי, בהתבסס אם התנאי הוא אמת או שקר. condition ? value if true : value if false.

??

סימן פעולת מיזוג null: הביטוי ‏a ?? b שווה ערך לביטוי a != null ? a : b. סימן פעולה זה שימושי לדוגמה כדי לספק ערך ברירת מחדל במקרה של הפניה שהיא null:

stdout.printf("Hello, %s!\n", name ?? "unknown person");

in

בודק אם הפרמטר הימני מכיל את זה השמאלי. סימן פעולה זה פועל על מערכים, מחרוזות, אוספים, או כל טיפוס אחר שיש לו שיטה contains()‎ מתאימה. עבור מחרוזות זה מבצע חיפוש תת מחרוזת.

סימני פעולה לא ניתנים להעמסה ב־Vala. ישנם סימני פעולה נוספים התקפים בהקשר של הצהרות למדא ומשימות מסוימות אחרות – אלה יוסברו בהקשר בו הם חלים.

משפטי בקרה

while (a > b) { a--; }

a יופחת שוב ושוב, עם בדיקה לפני כל הישנות כי a גדול מ־b.

do { a--; } while (a > b);

a יופחת שוב ושוב, עם בדיקה לאחר כל הישנות כי a גדול מ־b.

for (int a = 0; a < 10; a++) { stdout.printf("%d\n", a); }

a יאותחל ל־0, לאחר מכן a יודפס שוב ושוב עד אשר a לא יהיה קטן מ־10, עם הגדלת a לאחר כל הישנות.

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

יודפס כל שלם במערך, או אוסף אחר הניתן להישנות. משמעות „ניתן להישנות” תתואר מאוחר יותר.

כל ארבעת סוגי הלולאות הקודמים ניתנים לשליטה עם מילות המפתח break ו־continue. הוראת break תגרום לסיום מיידי של הלולאה, בעוד continue תקפוץ ישר למקטע הבדיקה של הלולאה.

if (a > 0) { stdout.printf("a is greater than 0\n"); }
else if (a < 0) { stdout.printf("a is less than 0\n"); }
else { stdout.printf("a is equal to 0\n"); }

ביצוע קטע מסוים של קוד בהתבסס על סדרה של תנאים. התנאי הראשון בכדי להחליט איזה קוד יבוצע, אם a גדול מ־0 לא תתבצע בדיקה אם הוא קטן מ־0. כל מספר של בלוקי else if מותרים, וכן אפס או בלוק אחד של else.

switch (a) {
case 1:
    stdout.printf("one\n");
    break;
case 2:
case 3:
    stdout.printf("two or three\n");
    break;
default:
    stdout.printf("unknown\n");
    break;
}

הצהרת switch תריץ בדיוק מקטע קוד אחד או אפס בהתבסס על הערך שהועבר לה. ב־Vala אין נפילה בין המקרים, להוציא מקרים ריקים. על מנת להבטיח זאת, כל מקרה לא ריק חייב להסתיים עם הצהרת break, ‏return או throw.

הערה למתכנתי C: תנאים תמיד מוערכים לערכים בוליאניים. המשמעות היא כי על מנת לבדוק משתנה עבור null או 0, חובה לעשות זאת באופן מפורש: if (object != null) { }‎ או if (number != 0) { }‎.

רכיבי שפה

שיטות

פונקציות נקראות שיטות ב־Vala, ללא קשר אם הן מוגדרות בתוך מחלקה או לא. מכאן והלאה אנו נדבֹק במונח שיטה.

int method_name(int arg1, Object arg2) {
    return 1;
}

קוד זה מגדיר שיטה, בעלת השם method_name, הלוקחת שני פרמטרים, אחד שלם והשני Object (הראשון מועבר על ידי ערך והשני מועבר כהפניה כפי שתואר). השיטה תחזיר שלם, במקרה זה 1.

כל שיטות Vala הן פונקציות C, ולכן לוקחות מספר שרירותי של פרמטרים ומחזירות ערך אחד (או אף לא אחד אם השיטה הוכרזה void).

Projects/Vala/Tutorial/he (last edited 2015-03-11 02:26:19 by YosefOrBoczko)