האנטומיה של שליחת הודעה: אלמנטים תחביריים, מקבל ההודעה ו-3 תבניות ההודעה
כיצד מתורגמת כל פעולה בשפת Smalltalk לשליחת הודעה לעצם: הכרת 14 הסימנים התחביריים של השפה, פירוק כל ביטוי למקבל (Receiver), מזהה (Selector) וארגומנטים, ומיפוי שלוש תבניות ההודעה — אונרית, בינרית ומילת-מפתח.
מודל מנטלי ועיקרון מנחה: כל פעולה ב-Smalltalk היא דו-שיח בין מקבל להודעה!
דמיין שאתה שולח מכתב בדואר: על המעטפה תמיד מופיע קודם כל הנמען (מקבל ההודעה – Receiver), ובתוך המכתב מופיעה הבקשה עצמה — שם הפעולה (Selector) והפרטים הנלווים לביצועה (Arguments).
לכל האופרטורים ב-Smalltalk קיימת קדימות זהה! השפה תומכת בהעמסת אופרטורים, אך בניגוד לשפות אחרות לא ניתן כלל לשנות את סדר הקדימות שלהם או את מספר האופרנדים שהם מקבלים.
מקבל ההודעה שנרשם לפני ההודעה אינו חייב להיות משתנה או ליטרל פשוט — הוא יכול להיות גם עצם המוחזר מחישוב של ביטוי קודם, כמו (x + y) בביטוי (x + y) factorial!
1. האלמנטים התחביריים בשפת Smalltalk
כל הלקסיקון התחבירי של השפה על כף יד אחת — 14 סימנים וחוק ברזל אחד על אופרטורים
כדי שנשלוט ב-Smalltalk באופן מוחלט, אנחנו צריכים להפנים רעיון מרכזי אחד שמנחה את כל פעולתה של השפה: כל פעולה שאנחנו מבצעים מתורגמת לשליחת הודעה לעצם (Object). הבנת מבנה ההודעות וסדר הקדימויות שלהן היא המפתח להבנת השפה כולה וליכולת לקרוא ולכתוב קוד שוטף.
לפני שנפרק כל הודעה לגורמים, בוא נכיר את כל 14 האלמנטים התחביריים שמרכיבים תוכנית בשפת Smalltalk לצד פעולות שליחת ההודעות:
:= או _
משמשת לביצוע השמה של ערך למשתנה (ניתן להשתמש גם בחץ שמאלה או בקו תחתון _).
^
חץ הפונה כלפי מעלה משמש להחזרת ערך מתוך מתודה.
.
נקודה בודדת משמשת להפרדה בין משפטים נפרדים.
;
נקודה ופסיק משמשים להפרדה בין הודעות שונות הנשלחות ברצף לאותו עצם (Cascade).
#
סולמית מיועדת להגדרת סימבול (Symbol) מיוחד.
$
סימן דולר משמש לכתיבת תו בודד (Character), כגון $e או $x.
( )
סוגריים עגולים משמשים, בדומה למתמטיקה, להגדרת סדר הקדימות של הפעולות בביטוי.
' '
מרכאות בודדות עוטפות מחרוזת טקסט (String), כגון 'hello'.
#( )
סולמית המלווה בסוגריים עגולים משמשת להגדרת מערך קבוע (סטטי).
{ }
סוגריים מסולסלים משמשים ליצירת מערך דינמי, כאשר נקודה מפרידה בין הביטויים בתוך המערך.
[ | : ]
סוגריים מרובעים תוחמים בלוק קוד. פרמטרים אופציונליים נרשמים בתחילתו עם : לפני כל ארגומנט, וקו אנכי | מפריד בינם לגוף הבלוק.
| |
קווים אנכיים עוטפים שמות של משתנים המוגדרים באופן מקומי (זמני) בלבד.
" "
מרכאות כפולות עוטפות טקסט המשמש כהערה בלבד ואינו מבוצע כקוד.
<primitive: ...>
סוגריים זוויתיים הכוללים את המילה primitive: משמשים להפעלת פעולה בסיסית ישירה של המכונה הווירטואלית (Virtual Machine).
2. סעיף 7.1: זיהוי הודעות (Message Identification)
פירוק כל ביטוי של שליחת הודעה למקבל ההודעה (Receiver), מזהה ההודעה (Selector) והארגומנטים (Arguments)
כל שליחת הודעה ב-Smalltalk היא ביטוי המורכב מצירוף של שני חלקים משלימים: מקבל ההודעה (Receiver) וההודעה עצמה (Message).
📨 מרכיבי ההודעה עצמה (Message)
- מזהה ההודעה (Selector): השם הסימבולי של הפעולה הנשלחת אל העצם.
- ארגומנטים אופציונליים (Arguments): ערכים (עצמים) המועברים לצורך ביצוע הפעולה (רק לחלק מסוגי ההודעות יש ארגומנטים):
- הודעה אונרית: אינה מקבלת ארגומנטים כלל (למשל
3 factorial– המזהה הואfactorialואין ארגומנטים). - הודעה בינרית: מקבלת ארגומנט בודד בדיוק (למשל
3 + 2– המזהה הוא+, והארגומנט הוא2). - הודעת מילת-מפתח: מקבלת ארגומנטים כמספר מילות המפתח המרכיבות אותה (למשל
anArray at: 2 put: 10– המזהה הואat:put:, והארגומנטים הם2ו-10).
- הודעה אונרית: אינה מקבלת ארגומנטים כלל (למשל
🎯 מיהו מקבל ההודעה (Receiver)?
הודעה תמיד, ללא יוצא מן הכלל, נשלחת אל מקבל (Receiver) שנרשם פיזית לפני ההודעה. מקבל ההודעה אינו חייב להיות משתנה פשוט; הוא יכול להיות אחד משלושה:
- ליטרל בודד: כגון המספר
3בביטוי3 + 2או בביטוי3 factorial. - משתנה קיים: כגון
numבביטויnum + 3, אוanArrayבביטויanArray at: 2 put: 10. - תוצאה של הערכת ביטוי קודם: למשל בביטוי
(x + y) factorial, מקבל ההודעהfactorialהוא העצם המוחזר מחישוב הביטוי שבסוגריים(x + y)(אשר מושג לאחר שההודעה+עם הארגומנטyנשלחת אל המשתנהx).
💡 שתי דוגמאות קריטיות להבנת תפקיד הסוגריים והארגומנטים המחושבים:
(x + y) factorialלעומתx + y factorial: ללא הסוגריים, בביטויx + y factorial, מקבל ההודעהfactorialיהיה המשתנהyבלבד (עקב קדימות אונרית על פני בינרית!), והתוצאה שתחזור מ-y factorialתחובר אלx.- ארגומנט שהוא בעצמו תוצאת ביטוי (
anArray at: 2 put: x + 1): בביטוי זה נשלחת אל המקבלanArrayההודעהat:put:, כאשר הארגומנט הראשון הוא2והארגומנט השני שלה הוא העצם שחוזר מחישוב הביטויx + 1(שליחת ההודעה+ 1אל המשתנהx).
3. סעיף 7.2: תבניות ההודעה (Message Patterns)
המבנה התחבירי המדויק של שלושת סוגי ההודעות ב-Smalltalk
בשפת Smalltalk קיימים בדיוק 3 סוגי הודעות. סדר הקדימות לשליחת ההודעות נגזר תמיד מסוג ההודעה (החל באונריות, דרך בינריות ועד מילות-מפתח), ורצף של הודעות באותה רמת עדיפות מבוצע תמיד משמאל לימין:
ללא נקודתיים וללא ארגומנטים
מורכבת מרצף אותיות/תווים (שם) ללא הסימן נקודתיים (:), ומתחילה תמיד באות קטנה. אינה מקבלת ארגומנטים כלל.
תווים מיוחדים וארגומנט יחיד
מורכבת מתו אחד או שניים מתוך קבוצת התווים:
+ , - , * , / , = , > , | , < , & , ~ , @ , % , \ , ? , ,
ומקבלת תמיד ארגומנט יחיד בדיוק.
מילים עם נקודתיים וארגומנטים
מורכבת ממילת מפתח אחת או יותר, כאשר כל מילת מפתח מסתיימת בנקודתיים (:) ומלווה בארגומנט בודד המוצמד אליה.
מיפוי מקבל ההודעה (Receiver), המזהה (Selector) והארגומנטים (Arguments)
מיני-סימולציה 7.1: מילון 14 האלמנטים התחביריים של Smalltalk
מעבדת זיהוי ותבניות הודעה: מנתח המקבל, המזהה והארגומנטים
בחר ביטוי מתוך דוגמאות היסוד שלנו וראה כיצד Smalltalk מפרקת אותו למקבל ההודעה (Receiver), למזהה (Selector) ולארגומנטים (Arguments), ולאיזו תבנית תחבירית הוא שייך:
הגשר הנרטיבי: זיהינו הודעה בודדת – אבל מה קורה כשמחברים כמה הודעות יחד בביטוי אחד?
כשאנחנו כותבים ביטוי מורכב כמו 2 raisedTo: 1 + 3 factorial או אפילו משוואה חשבונית תמימה למראה כמו 3 + 4 * 5 + 2, באיזה סדר Smalltalk מפענחת ומחשבת את ההודעות?
ביחידה הבאה (7.3) נגלה את חוקי הקדימות הקשיחים של השפה ונראה מדוע ב-Smalltalk אין קדימות של כפל על חיבור!
הרכבת הודעות וסדר קדימות: סוגריים, אונרי, בינרי, מילות-מפתח והמלכודת המתמטית
איך מוערך ביטוי המורכב ממספר שליחות של הודעות: סולם הקדימויות הקשיח, אסוציאטיביות משמאל לימין, מדוע אין קדימות לכפל ולחילוק על פני חיבור וחיסור (3 + 4 * 5 + 2), וניתוח רב-שלבי של 2 raisedTo: 1 + 3 factorial.
מודל מנטלי ועיקרון מנחה: ב-Smalltalk אין אופרטורים מתמטיים — יש רק עצמים והודעות בינריות שוות-דרגה!
תחשוב על פס ייצור עם 4 תחנות קבועות מראש: קודם פותחים אריזות סגורות (סוגריים), אחר כך מפעילים פעולות יחידניות (אונריות), אחריהן פעולות זוגיות (בינריות), ולבסוף הרכבות רב-חלקיות (מילות-מפתח).
סדר הקדימות הקשיח הוא תמיד: 1. סוגריים () → 2. אונריות → 3. בינריות → 4. מילות-מפתח, ובתוך כל דרגת קדימות ההערכה מתבצעת אך ורק משמאל לימין!
מאחר ש-+ ו-* הן שתיהן הודעות בינריות באותה דרגת קדימות בדיוק, ב-Smalltalk אין קדימות לכפל על חיבור! הביטוי 3 + 4 * 5 + 2 מחושב משמאל לימין ואינו מחזיר 25!
1. סולם הקדימויות הקשיח של Smalltalk (סעיף 7.3)
איך הופכות תוצאות השלבים המוקדמים למקבלי ההודעות ולארגומנטים של השלבים המאוחרים?
כאשר ביטוי מורכב מהרכבה של מספר שליחות של הודעות מסוגים שונים, Smalltalk מעריכה אותו בצורה מובנית וחד-משמעית. העצמים (הערכים) המוחזרים מההודעות שהוערכו בשלבים המוקדמים יותר, הופכים להיות מקבלי ההודעות (Receivers) או הארגומנטים (Arguments) של ההודעות שיוערכו בשלב מאוחר יותר.
סוגריים עגולים מוערכים תמיד ראשונים
מוערכות שניות (למשל factorial)
מוערכות שלישיות (למשל +, *, @)
מוערכות אחרונות (למשל raisedTo:)
הודעות שוות-דרגה מוערכות משמאל לימין בלבד!
2. המלכודת המתמטית: מדוע 3 + 4 * 5 + 2 אינו שווה ל-25?
ההבדל הקריטי בין אריתמטיקה סטנדרטית לבין הרכבת הודעות בינריות ב-Smalltalk
כאן מסתתרת אחת המלכודות הקלאסיות ביותר למי שמגיע ממתמטיקה או משפות כמו Java ו-C:
מאחר שכל האופרטורים החשבוניים (+, -, *, /) הם למעשה הודעות בינריות שוות-דרגה, ב-Smalltalk אין קדימות לכפל ולחילוק על פני חיבור וחיסור! כל רצף של הודעות בינריות מוערך באופן רציף אך ורק משמאל לימין.
🟣 הערכת הביטוי 3 + 4 * 5 + 2 ב-Smalltalk:
- תחילה נשלחת ההודעה הבינרית השמאלית ביותר:
3 + 4ומחזירה את העצם7. - לעצם
7נשלחת ההודעה הבינרית הבאה:7 * 5ומחזירה את העצם35. - לעצם
35נשלחת ההודעה הבינרית האחרונה:35 + 2ומחזירה37!
(הערת הבהרה: גם כאשר בדוגמאות מסוימות מצוינת התוצאה 31 עבור וריאציית ביטוי דומה, העיקרון הפדגוגי זהה ומוחלט — ההערכה מתבצעת משמאל לימין ולא לפי סדר הקדימויות המקובל במתמטיקה, ולכן התוצאה לעולם אינה 25!).
🔴 לעומת מתמטיקה רגילה (ושפות כמו Java / C):
במתמטיקה רגילה קיימת קדימות של כפל על חיבור, ולכן מחשבים קודם את $4 \times 5 = 20$, ואז $3 + 20 + 2 = 25$.
איך נכפה סדר מתמטי ב-Smalltalk אם נרצה 25? נשתמש מפורשות בסוגריים עגולים (קדימות 1):
3 + (4 * 5) + 2 "--> 25"
3. דוגמאות מפתח להרכבה רב-שלבית: 128 מול 8
איך זוג סוגריים אחד משנה לחלוטין את עץ ההערכה בביטוי המשלב אונרי, בינרי ומילת-מפתח?
- שלב 1 – הודעה אונרית:
3 factorialמוערכת ראשונה ומחזירה6. - שלב 2 – הודעה בינרית:
1 + 6מוערכת שנייה ומחזירה7. - שלב 3 – הודעת מילת-מפתח:
2 raisedTo: 7מוערכת אחרונה ($2^7$) ומחזירה128!
- שלב 1 – סוגריים עגולים:
2 raisedTo: 1מוערכת ראשונה ($2^1$) ומחזירה2. - שלב 2 – הודעה אונרית:
3 factorialמוערכת שנייה ומחזירה6. - שלב 3 – הודעה בינרית:
2 + 6מוערכת אחרונה ומחזירה8!
השוואת הערכת הביטוי 3 + 4 * 5 + 2 ועץ הקדימויות ב-2 raisedTo: 1 + 3 factorial
מיני-סימולציה 7.2: השפעת הסוגריים על מקבל ההודעה ועל התוצאה
מפענח הקדימויות צעד-אחר-צעד (Step-by-Step Evaluation Debugger)
בחר ביטוי מורכב וצעד קדימה ואחורה בשלבי ההערכה של המהדר כדי לראות איזו תת-הודעה מתבצעת בכל שלב, מהו המקבל שלה, ואיזה עצם חוזר ממנה לשלב הבא:
הגשר הנרטיבי: הבנו איך מתנהגות הודעות אונריות ובינריות – אבל מה קורה כשמופיעות כמה מילות-מפתח ברצף?
כשמופיע רצף של מילים שמסתיימות בנקודתיים, כמו st at: st indexOf: $e put: $x, איך Smalltalk יודעת איפה נגמרת הודעת מילת-מפתח אחת ואיפה מתחילה אחרת?
ביחידה הבאה (7.4) נכיר את חוק הרצף הארוך ביותר, נראה מדוע השמטת סוגריים מובילה מיד לשגיאת MessageNotUnderstood, ונבין את ההבדל התהומי שבין סוגריים עגולים () לסוגריים מרובעים []!
חוק הרצף הארוך ביותר במילות-מפתח, שבירה בסוגריים וההבדל בין () ל-[]
כיצד מקבץ המהדר סדרת מילים עם נקודתיים להודעת מילת-מפתח אחת ארוכה ככל האפשר, איך שוברים את הרצף באמצעות סוגריים, מלכודת ה-MessageNotUnderstood בהחלפת תו במחרוזת ('hello' → 'hxllo'), וההבדל המהותי בין סוגריים עגולים () לסוגריים מרובעים [].
מודל מנטלי ועיקרון מנחה: המהדר "חמדן" במילות-מפתח, וסוגריים עגולים אינם בלוק!
תחשוב על מילות-מפתח עם נקודתיים כעל קרונות רכבת עם מגנטים: אם לא תשים ביניהם מחיצת הפרדה של סוגריים עגולים (), המהדר יחבר את כולן לרכבת אחת ארוכה (הודעה אחת) שנשלחת למקבל הראשון!
חוק הרצף הארוך ביותר: Smalltalk מזהה הודעת מילת-מפתח לפי הרצף הארוך ביותר של מילים המלוות בנקודתיים ובארגומנט באותו אזור תיחום. כדי לפצל להודעות נפרדות, חובה להשתמש בסוגריים ()!
סוגריים עגולים () קובעים רק סדר הערכה והביטוי בתוכם מוערך פעם אחת בלבד. סוגריים מרובעים [] יוצרים עצם מסוג בלוק (Block) שיכול להיות מוערך 0 או יותר פעמים!
1. חוק הרצף הארוך ביותר (Greedy Keyword Matching) ושבירתו בסוגריים
איך המהדר מפענח סדרה של מילות-מפתח המסתיימות בנקודתיים?
ראינו שהודעת מילת-מפתח יכולה להיות מורכבת ממילת מפתח אחת או מכמה מילות מפתח המסתיימות בסימן נקודתיים (:) ומלוות בארגומנטים.
אבל מה קורה כאשר אנחנו כותבים ביטוי המורכב מרצף של מילות מפתח?
כלל הזהב של המהדר ב-Smalltalk הוא חוק הרצף הארוך ביותר: כאשר מופיעה סדרת מילים המסתיימות בנקודתיים בליווי ארגומנטים, המהדר יקבץ אותן תמיד להודעת מילת-מפתח אחת ארוכה ככל האפשר!
מפורש כשליחת הודעת מילת-מפתח בודדת וארוכה בשם word1:word2:word3: אל העצם x (עם 3 ארגומנטים).
שולח תחילה את ההודעה word1:word2: לעצם x, ולאחר מכן שולח את ההודעה word3: אל העצם שחזר מההודעה הראשונה!
שולח תחילה את ההודעה word1: לעצם x, ולאחר מכן שולח את ההודעה word2:word3: אל העצם שחזר מההודעה הראשונה!
2. דוגמת מפתח מעשית: החלפת תו במחרוזת ('hello' → 'hxllo')
מדוע השמטת הסוגריים גורמת מיד לקריסה בשגיאת MessageNotUnderstood?
נתבונן בקטע הקוד הבא, שמטרתו להחליף את התו 'e' (הנכתב כ-$e) בתו 'x' (הנכתב כ-$x) בתוך המחרוזת 'hello':
st at: (st indexOf: $e) put: $x.
מה מתרחש כאן? הסוגריים העגולים תוחמים את הביטוי (st indexOf: $e), ששולח למחרוזת st את ההודעה indexOf: ומחזיר את האינדקס 2. לאחר מכן, לעצם st נשלחת ההודעה at:put: עם הארגומנטים 2 ו-$x, ובסיום st מכיל את המחרוזת 'hxllo'!
st at: st indexOf: $e put: $x
מדוע התוכנית קורסת? ללא סוגריים, המהדר מפעיל את חוק הרצף הארוך ביותר ומזהה הודעת מילת-מפתח אחת רציפה, שגויה ולא מוגדרת בשם at:indexOf:put: עם שלושה ארגומנטים (st, $e, $x) הנשלחת אל st. מאחר שהודעה כזו אינה קיימת במחלקת המחרוזות, התוכנית נכשלת מיד בשגיאת MessageNotUnderstood!
3. הבדל מהותי: סוגריים עגולים () מול סוגריים מרובעים []
למה סוגריים עגולים לעולם אינם יכולים להחליף סוגריים מרובעים ב-ifTrue: וב-whileTrue:?
ראינו שהסוגריים העגולים () מאפשרים לתחום אזור בקוד שבו נזהה הודעות מילות-מפתח ונכתיב את סדר ההערכה.
אך חשוב מאוד שנבחין בינם לבין סוגריים מרובעים []:
🔵 סוגריים עגולים ( ... ) – הערכה מיידית ופעם אחת בדיוק!
השימוש בסוגריים עגולים נועד לתיחום אזור לקביעת סדר ההערכה של הודעות בלבד. הם משפיעים רק על סדר הערכת הביטויים, אך לא על מספר הפעמים שהביטוי מוערך — הביטוי בתוכם מוערך בדיוק פעם אחת (מיד כשמגיעים אליו)!
🟣 סוגריים מרובעים [ ... ] – יצירת עצם בלוק (0 או יותר פעמים!)
בניגוד לעגולים, סוגריים מרובעים תוחמים אזור בקוד אך גם יוצרים עצם מסוג בלוק (Block) אשר יכול להיות מוערך 0 או יותר פעמים!
משום כך, ארגומנטים של הודעות תנאי כמו ifTrue: או ifTrue:ifFalse:, וכן מקבל ההודעה והארגומנט של הודעת הלולאה whileTrue:, חייבים תמיד להיות מוגדרים כבלוקים [] — מפני שאי אפשר לדעת מראש אם או כמה פעמים הם יוערכו בזמן ריצה. סוגריים עגולים לעולם אינם מהווים תחליף לסוגריים מרובעים!
() ל-[]שבירת הרצף הארוך ביותר ב-at:put: והשוואת תיחום הערכה () מול עצם בלוק []
מיני-סימולציה 7.3: מפצל רצף מילות-המפתח (word1:word2:word3:)
מעבדת החלפת התו במחרוזת ('hello') ומבחן הסוגריים () מול []
חלק א': ניסוי החלפת תו במחרוזת st := 'hello'
חלק ב': ניסוי סוגריים עגולים () מול בלוק [] ב-ifTrue: / whileTrue:
הגשר הנרטיבי: למדנו לבנות ביטוי בודד מושלם – עכשיו איך מחברים סדרה של משפטים ואיך שולחים מפל של הודעות (Cascade) לאותו עצם?
בתוכנית אמיתית אנחנו כותבים רצף של משפטים המופרדים בנקודה (.) או שולחים מספר הודעות ברצף אל אותו מקבל בדיוק באמצעות סימן הנקודה-פסיק (; – Cascade).
ביחידה הבאה (7.5–7.6) נגלה מה מחזירה סדרת ביטויים, מי הוא המקבל ב-Cascade, ואיך השמטה של נקודה-פסיק אחת משנה שטח מלבן מ-400 ל-0 או הופכת תוצאת isZero מ-false ל-true!
סדרת ביטויים (.) ומפל הודעות Cascade (;): נקודות, מלבנים ומלכודת yourself
הנקודה כמפריד משפטים (Separator), הצהרת משתנים זמניים | ... |, כלל הערך המוחזר, ומנגנון ה-Cascade (;) דרך 3 מקרי בוחן: 10@10 - 10; corner: 30@30; isZero, חישוב שטח מלבן (400 מול 0), ומלכודת הבחינות ב-OrderedCollection (add: מול yourself).
מודל מנטלי ועיקרון מנחה: ב-Cascade המקבל נעול לפני ה-; הראשונה, והתוצאה היא תמיד מההודעה האחרונה!
סדרת ביטויים עם נקודה (.) היא כמו שיחות טלפון נפרדות לאנשים שונים. לעומתה, מפל הודעות (Cascade עם ;) הוא שיחה אחת שבה אתה נותן לאותו נמען מקורי בדיוק שלוש הוראות בזו אחר זו מבלי לנתק!
ב-Cascade שני חוקי יסוד מוחלטים: (1) מיהו המקבל? העצם שלפני הנקודה-פסיק הראשונה מקבל את כל ההודעות ברצף; (2) מהו הערך המוחזר? תמיד הערך שמוחזר מהשליחה של ההודעה האחרונה ברצף!
המתודה add: באוספים מחזירה את האיבר שנוסף ולא את האוסף! לכן ב-Cascade של הוספות ל-OrderedCollection, חובה לסיים בהודעה ; yourself כדי להחזיר את האוסף עצמו (self)!
1. סעיף 7.5: סדרת ביטויים (Sequence of Statements)
הנקודה כמפריד (Separator), הצהרת משתנים מקומיים וכלל הערך המוחזר מהמשפט האחרון
כדי לבצע רצף של פעולות נפרדות בזו אחר זו, אנחנו משתמשים בסדרת ביטויים המורכבת מהשמות ומשליחות של הודעות, על פי שלושת הכללים הבאים:
.)
משפטים עצמאיים מופרדים זה מזה באמצעות נקודה (.). הנקודה משמשת כמפריד (Separator) בין ביטויים קיימים ולא כסוגר (Terminator), ולכן אין צורך בנקודה בסוף המשפט האחרון!
| ... |)
לפני תחילת סדרת הביטויים יכול להופיע קטע התחום בין קווים אנכיים | ... | להצהרת משתנים מקומיים (זמניים). אין צורך בנקודה בין סוגר הקווים האנכיים לבין הביטוי הראשון בסדרה.
הערך המוחזר מביצוע סדרת משפטים הוא תמיד הערך שחוזר מביצוע הביטוי האחרון בלבד! כל שאר הערכים שהוחזרו ממשפטים קודמים נזרקים ואינם נשמרים (אלא אם הושמו למשתנה).
st1 := 'xxyyzz'.
st2 := 'yz'.
st1 includesSubString: st2 "מחזיר true — זהו הביטוי האחרון ולכן זהו הערך המוחזר מהסדרה כולה!"
2. סעיף 7.6: הודעות Cascade (מפל הודעות – ;) ושלושת מקרי הבוחן
איך שולחים סדרת הודעות לאותו מקבל מקורי בדיוק, ואיך השמטת נקודה-פסיק הופכת את התוצאה על פיה?
ישנם מקרים רבים שבהם נרצה לשלוח מספר הודעות ברצף אל אותו עצם בדיוק (מקבל יחיד), מבלי להגדיר אותו או לחשב אותו מחדש. כאן נכנס לשימוש מנגנון ה-Cascade באמצעות סימן נקודה-פסיק (;):
- כלל יסוד 1 – מיהו המקבל?: המקבל נקבע לפי הביטוי שנרשם לפני הנקודה-פסיק הראשונה (ויכול להיות בעצמו עצם שהוחזר משליחת הודעה אחרת). כל ההודעות שלאחר מכן ברצף ה-Cascade נשלחות תמיד אל אותו המקבל המקורי, ללא שום תלות במה שהחזירו ההודעות הקודמות!
- כלל יסוד 2 – מהו הערך המוחזר?: הערך המוחזר מביטוי Cascade שלם הוא תמיד הערך שמוחזר מהשליחה של ההודעה האחרונה ברצף!
🔍 מקרה בוחן 1: פעולות על נקודה ומלבן – false מול true
השפעת ה-; הראשונה על המקבל
- איתור המקבל: המקבל של ה-Cascade (לפני ההודעה הראשונה
- 10שלפני ה-;) הוא הנקודה10@10(שנוצרה מ-10 @ 10). - הודעה 1 (
- 10): נשלחת ל-10@10, מפחיתה 10 מרכיבי x ו-y ומחזירה0@0— אך התוצאה נזרקת ואינה נשמרת! - הודעה 2 (
corner: 30@30): נשלחת שוב ל-10@10ומחזירה מלבן שפינותיו10@10ו-30@30— גם תוצאה זו נזרקת! - הודעה 3 ואחרונה (
isZero): נשלחת שוב לנקודה המקורית10@10. מאחר ש-10@10אינה אפס, מוחזרfalse!
מה קורה כשמשמיטים את הנקודה-פסיק הראשונה?
- ללא
;אחרי- 10, תחילה מתבצע הביטוי הבינרי10@10 - 10במלואו ומחזיר נקודה חדשה:0@0! - כעת, מקבל ה-Cascade הופך להיות הנקודה החדשה
0@0! - אל
0@0נשלחת ההודעהcorner: 30@30(תוצאתה נזרקת), ולאחריה נשלחת אל0@0ההודעה האחרונהisZero. - מאחר שהנקודה המקבלת היא
0@0, ההודעהisZeroמחזירה כעתtrue!
📐 מקרה בוחן 2: תרגיל חישוב שטח מלבן (area) – 400 מול 0
מלבן $20 \times 20$ מול מלבן מנוון $0 \times 0$
- בתוך הסוגריים ישנו Cascade שהמקבל שלו הוא הנקודה המקורית
10@10. - ההודעה הראשונה
+ 20נשלחת ל-10@10(מחזירה30@30, אך תוצאתה נזרקת). - ההודעה השנייה והאחרונה ב-Cascade היא
corner: 30@30. היא נשלחת אל המקבל המקורי10@10, ויוצרת מלבן שפינותיו הן(10@10)ו-(30@30)— רוחבו 20 וגובהו 20. - לסיום, ההודעה האונרית
areaנשלחת למלבן המוחזר מהסוגריים, והתוצאה היא $20 \times 20 =$400!
מה יקרה אם נשמיט את הנקודה-פסיק?
- ללא נקודה-פסיק, הביטוי הבינרי
10@10 + 20מחושב ראשון לחלוטין ומחזיר את הנקודה החדשה30@30. - לנקודה החדשה הזו (
30@30) נשלחת ההודעהcorner: 30@30. - נוצר מלבן מנוון שפינתו השמאלית-עליונה היא
30@30ופינתו הימנית-תחתונה היא30@30(רוחבו 0 וגובהו 0). - שליחת ההודעה
areaלמלבן זה מחזירה: $0 \times 0 =$0!
🏆 מקרה בוחן 3: מלכודת הבחינות בהוספה לאוספים (add: מול yourself)
הודעת yourself במחלקת Object
collection add: 1; add: 2.
המתכנת מצפה שביטוי ה-Cascade יחזיר את האוסף עם האיברים 1 ו-2. בפועל, ביטוי Cascade מחזיר את הערך של ההודעה האחרונה (add: 2). המתודה add: מחזירה לפי המוסכמה את האיבר שנוסף (2) ולא את האוסף!
add: 1; add: 2; yourself.
המתודה האונרית yourself (המוגדרת במחלקת Object) פשוט מחזירה את self (את המקבל המקורי של ה-Cascade), וכך מובטח שהערך החוזר מה-Cascade כולו יהיה האוסף עצמו!
ניתוב הודעות למקבל יחיד ב-Cascade והשוואת המלבן (10@10 + 20; corner: 30@30) area עם ובלי ;
מיני-סימולציה 7.4: בוחן הערך המוחזר – סדרת משפטים (.) ומלכודת yourself
מעבדת ה-Cascade החיה: הדלק וכבה את הנקודה-פסיק (;) ב-3 מקרי הבוחן!
בחר אחד משלושת מקרי הבוחן, ולחץ על מתג הנקודה-פסיק (או מתג ה-yourself) כדי לראות בזמן אמת כיצד משתנה מקבל ההודעה ומה מוחזר מהביטוי כולו:
הגשר הנרטיבי: השלמנו את כל סעיפי פרק 7 – בוא נבחן את השליטה שלנו במילון המושגים האינטראקטיבי!
עברנו דרך כל מנגנון שליחת ההודעות ב-Smalltalk: מ-14 הסימנים התחביריים וזיהוי המקבל, המזהה והארגומנטים (7.1), דרך שלוש תבניות ההודעה (7.2), סדר הקדימויות והמלכודת המתמטית (7.3), זיהוי הודעות מילות-מפתח וההבדל בין () ל-[] (7.4), ועד לסדרת ביטויים (7.5) ומפל הודעות Cascade (7.6).
נעבור כעת ליחידה המסכמת של הפרק כדי לתרגל בכרטיסיות תלת-ממדיות ולהתכונן לפרק 8!
סיכום אינטגרטיבי ומילון מושגים אינטראקטיבי לפרק 7 (שליחת הודעות)
חיבור כל חוקי שליחת ההודעות ב-Smalltalk למפה הנדסית שלמה, בוחן אבחנה מהיר למלכודות הנפוצות, ו-12 כרטיסיות זיכרון תלת-ממדיות (3D Flashcards) עם מצב בחינה ומצב למידה.
מודל מנטלי ועיקרון מנחה: שלוש השאלות שפותרות כל ביטוי ב-Smalltalk!
זהה האם ההודעה היא אונרית (ללא : וללא ארגומנטים), בינרית (תווים מיוחדים וארגומנט יחיד) או מילת-מפתח (מילים עם : המקובצות לפי הרצף הארוך ביותר).
הערך תמיד לפי הסדר הקשיח: סוגריים () → אונריות → בינריות → מילות-מפתח, ובתוך אותה דרגת קדימות הערך אך ורק משמאל לימין (ללא קדימות של כפל על חיבור!).
בסדרת משפטים (.) וגם ב-Cascade (;) מוחזר תמיד ערך ההודעה האחרונה. ב-Cascade כל ההודעות נשלחות למקבל שלפני ה-; הראשונה (ובאוספים מוסיפים yourself)!
מתבניות ההודעה וסדר הקדימות ועד לשבירת מילות-מפתח ומנגנון ה-Cascade
מיני-סימולציה 7.5: בוחן אבחנה מהיר – 4 מלכודות המבחנים של פרק 7
כרטיסיות זיכרון תלת-ממדיות (3D Flashcards) לכל 12 מושגי פרק 7
לחץ על כל כרטיסייה כדי להפוך אותה ולבחון את עצמך על כל אחד מ-12 מושגי המפתח של פרק 7:
נחשפו: 0 / 12סיימנו במלואו את פרק 7 (שליחת הודעות)! מה מחכה לנו בפרק 8?
עכשיו, כשהבנו לעומק איך כל ביטוי ב-Smalltalk מפורק למקבל ולהודעה, איך פועלים חוקי הקדימות, איך מזוהות הודעות מילות-מפתח ואיך פועלים סדרת ביטויים ומנגנון ה-Cascade, אנחנו מוכנים לצלול אל המבנה הפנימי של העצמים והמחלקות עצמם!
• משתני מופע (Instance Variables) מול משתני מחלקה (Class Variables).
• שיטות גישה (Accessors) ומחלקות מופשטות (
subclassResponsibility).