להבין את רובי חלק שני

הקדמה

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

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

מה אני רואה ?

אופרטורים

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

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

רווח לבן

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

i = 1 -1

אינו זהה לביטוי הזה:

i = 1 - 1

למרות שלעין לא מאומנת, זה נראה לגמרי זהה. המשפט הראשון אומר משהו לא חוקי. אני מנסה להציב 1 ו-1 לi, ורובי לא ידע מה אני רוצה ממנו. המשפט השני אבל, הוא משפט המחסיר בין המספר אחד למספר השני.
זוכרים כי אין אופרטורים ברובי ? אז כאשר אני כותב 1-, אני בעצם אומר שיצרתי Instance של Fixnum בערך של מינוס אחד. בעוד שהמשפט השני, ובכן הוא אומר שאני משתמש ב Instance של fixnum בערך של 1, ומשתמש במתודה מינוס, ומעביר לה פרמטר עם Instance של Fixnum בערך של 1. כלומר זה שקול לדבר הבא:

1.-(1)

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

ברור או לפי הקשר ?

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

s = 'Hello World'
s[1]

והחלק השני:

s = 'Hello World'
s [1]

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

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

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

Block vs Proc

לרובי יש 2 כלים (למעשה 3) מאוד חזקים, הראשון הוא proc והשני הוא block (השלישי הוא lambda, אבל עליה אני לא אדבר כאן). הכלים האלו מאפשרים לנו להריץ קוד שלנו בחלקים שונים ובתצורות שונות. לרוב הם לא מאוד ברורים ומשתמשים בהם לא נכון. אז קודם בואו נבדיל בין 2 הכלים האלו.
ובכן Proc הם יותר כמו פונקציות בשפות אחרות. אבל זה לא הכל. הן גם סוג של closure של שפות פונקציונאליות. ואפילו זהה לפונקציה אנונימית בשפות שונות. העניין הוא שproc מאוגד למשתנה מסויים או למרחב לקסלי מסויים ולא מעבר.

 double = Proc.new { |x| x * x }
 double.call(2)  # return 4
 double.call(5)  # return 25
 double.call(10) # return 100

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

10.times.each do |i|
   puts i + 1
end

להשאיר תגובה

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

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s