פרק 7: שליחת הודעות • סעיפים 7.1–7.2 האלמנטים התחביריים, זיהוי הודעות ותבניות ההודעה

האנטומיה של שליחת הודעה: אלמנטים תחביריים, מקבל ההודעה ו-3 תבניות ההודעה

כיצד מתורגמת כל פעולה בשפת Smalltalk לשליחת הודעה לעצם: הכרת 14 הסימנים התחביריים של השפה, פירוק כל ביטוי למקבל (Receiver), מזהה (Selector) וארגומנטים, ומיפוי שלוש תבניות ההודעה — אונרית, בינרית ומילת-מפתח.

📨
🧠

מודל מנטלי ועיקרון מנחה: כל פעולה ב-Smalltalk היא דו-שיח בין מקבל להודעה!

💡 האנלוגיה המוחשית

דמיין שאתה שולח מכתב בדואר: על המעטפה תמיד מופיע קודם כל הנמען (מקבל ההודעה – Receiver), ובתוך המכתב מופיעה הבקשה עצמה — שם הפעולה (Selector) והפרטים הנלווים לביצועה (Arguments).

⚖️ חוק הברזל הפדגוגי

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

🎯 תובנת המפתח

מקבל ההודעה שנרשם לפני ההודעה אינו חייב להיות משתנה או ליטרל פשוט — הוא יכול להיות גם עצם המוחזר מחישוב של ביטוי קודם, כמו (x + y) בביטוי (x + y) factorial!

1. האלמנטים התחביריים בשפת Smalltalk

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

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

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

1. השמה := או _

משמשת לביצוע השמה של ערך למשתנה (ניתן להשתמש גם בחץ שמאלה או בקו תחתון _).

2. החזרת ערך ^

חץ הפונה כלפי מעלה משמש להחזרת ערך מתוך מתודה.

3. הפרדת משפטים .

נקודה בודדת משמשת להפרדה בין משפטים נפרדים.

4. הפרדה ב-Cascade ;

נקודה ופסיק משמשים להפרדה בין הודעות שונות הנשלחות ברצף לאותו עצם (Cascade).

5. הגדרת סימבול #

סולמית מיועדת להגדרת סימבול (Symbol) מיוחד.

6. כתיבת תו $

סימן דולר משמש לכתיבת תו בודד (Character), כגון $e או $x.

7. סדר עדיפות ( )

סוגריים עגולים משמשים, בדומה למתמטיקה, להגדרת סדר הקדימות של הפעולות בביטוי.

8. כתיבת מחרוזת ' '

מרכאות בודדות עוטפות מחרוזת טקסט (String), כגון 'hello'.

9. מערך סטטי #( )

סולמית המלווה בסוגריים עגולים משמשת להגדרת מערך קבוע (סטטי).

10. מערך דינמי { }

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

11. הגדרת בלוק [ | : ]

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

12. משתנים מקומיים | |

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

13. הערה " "

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

14. הפעלת פעולה בסיסית (Primitive) <primitive: ...>

סוגריים זוויתיים הכוללים את המילה primitive: משמשים להפעלת פעולה בסיסית ישירה של המכונה הווירטואלית (Virtual Machine).

⚠️ הערה קריטית להבנת המנגנון (העמסת אופרטורים ב-Smalltalk): בניגוד לשפות אחרות, ב-Smalltalk לכל האופרטורים קיימת קדימות זהה. אף על פי שהשפה תומכת ב"העמסת אופרטורים" (Operator Overloading), לא ניתן כלל לשנות את סדר הקדימות שלהם או את מספר האופרנדים שהם מקבלים!

2. סעיף 7.1: זיהוי הודעות (Message Identification)

פירוק כל ביטוי של שליחת הודעה למקבל ההודעה (Receiver), מזהה ההודעה (Selector) והארגומנטים (Arguments)

כל שליחת הודעה ב-Smalltalk היא ביטוי המורכב מצירוף של שני חלקים משלימים: מקבל ההודעה (Receiver) וההודעה עצמה (Message).

📨 מרכיבי ההודעה עצמה (Message)

  1. מזהה ההודעה (Selector): השם הסימבולי של הפעולה הנשלחת אל העצם.
  2. ארגומנטים אופציונליים (Arguments): ערכים (עצמים) המועברים לצורך ביצוע הפעולה (רק לחלק מסוגי ההודעות יש ארגומנטים):
    • הודעה אונרית: אינה מקבלת ארגומנטים כלל (למשל 3 factorial – המזהה הוא factorial ואין ארגומנטים).
    • הודעה בינרית: מקבלת ארגומנט בודד בדיוק (למשל 3 + 2 – המזהה הוא +, והארגומנט הוא 2).
    • הודעת מילת-מפתח: מקבלת ארגומנטים כמספר מילות המפתח המרכיבות אותה (למשל anArray at: 2 put: 10 – המזהה הוא at:put:, והארגומנטים הם 2 ו-10).

🎯 מיהו מקבל ההודעה (Receiver)?

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

  1. ליטרל בודד: כגון המספר 3 בביטוי 3 + 2 או בביטוי 3 factorial.
  2. משתנה קיים: כגון num בביטוי num + 3, או anArray בביטוי anArray at: 2 put: 10.
  3. תוצאה של הערכת ביטוי קודם: למשל בביטוי (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 סוגי הודעות. סדר הקדימות לשליחת ההודעות נגזר תמיד מסוג ההודעה (החל באונריות, דרך בינריות ועד מילות-מפתח), ורצף של הודעות באותה רמת עדיפות מבוצע תמיד משמאל לימין:

1. הודעה אונרית (Unary)

ללא נקודתיים וללא ארגומנטים

מורכבת מרצף אותיות/תווים (שם) ללא הסימן נקודתיים (:), ומתחילה תמיד באות קטנה. אינה מקבלת ארגומנטים כלל.

receiver selector
3 factorial
2. הודעה בינרית (Binary)

תווים מיוחדים וארגומנט יחיד

מורכבת מתו אחד או שניים מתוך קבוצת התווים:
+ , - , * , / , = , > , | , < , & , ~ , @ , % , \ , ? , ,
ומקבלת תמיד ארגומנט יחיד בדיוק.

receiver selector argument
3 + 2  |  num + 3
3. מילת-מפתח (Keyword)

מילים עם נקודתיים וארגומנטים

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

receiver word1: arg1 word2: arg2
anArray at: 2 put: 10
עזר גרפי 7.1 • אנטומיה ויזואלית של 3 תבניות ההודעה ב-Smalltalk

מיפוי מקבל ההודעה (Receiver), המזהה (Selector) והארגומנטים (Arguments)

Unary · Binary · Keyword
1. הודעה אונרית (Unary): ללא נקודתיים (:), מתחילה באות קטנה, 0 ארגומנטים 3 Receiver (מקבל) factorial Selector (מזהה) ארגומנטים: אין (0) 2. הודעה בינרית (Binary): 1–2 תווים מיוחדים (+ - * / = > | < & ~ @ % \ ? ,), ארגומנט 1 3 Receiver + Selector 2 Argument 3. הודעת מילת-מפתח (Keyword): מסתיימת בנקודתיים (:), המזהה מורכב מכל המילים יחד (at:put:) anArray Receiver at: חלק 1 במזהה 2 Arg 1 put: חלק 2 במזהה 10 Arg 2
🔍

מיני-סימולציה 7.1: מילון 14 האלמנטים התחביריים של Smalltalk

לחץ על כל סימן תחבירי כדי לראות דוגמת קוד חיה והסבר
🔬
סימולציה אינטראקטיבית גדולה 7.1

מעבדת זיהוי ותבניות הודעה: מנתח המקבל, המזהה והארגומנטים

בחר ביטוי מתוך דוגמאות היסוד שלנו וראה כיצד Smalltalk מפרקת אותו למקבל ההודעה (Receiver), למזהה (Selector) ולארגומנטים (Arguments), ולאיזו תבנית תחבירית הוא שייך:

⚡

הגשר הנרטיבי: זיהינו הודעה בודדת – אבל מה קורה כשמחברים כמה הודעות יחד בביטוי אחד?

כשאנחנו כותבים ביטוי מורכב כמו 2 raisedTo: 1 + 3 factorial או אפילו משוואה חשבונית תמימה למראה כמו 3 + 4 * 5 + 2, באיזה סדר Smalltalk מפענחת ומחשבת את ההודעות? ביחידה הבאה (7.3) נגלה את חוקי הקדימות הקשיחים של השפה ונראה מדוע ב-Smalltalk אין קדימות של כפל על חיבור!

סוף יחידה 7.1–7.2 • אלמנטים תחביריים, זיהוי ותבניות הודעה
פרק 7: שליחת הודעות • סעיף 7.3 הרכבת הודעות וסדר הערכה (Message Composition)

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

איך מוערך ביטוי המורכב ממספר שליחות של הודעות: סולם הקדימויות הקשיח, אסוציאטיביות משמאל לימין, מדוע אין קדימות לכפל ולחילוק על פני חיבור וחיסור (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) של ההודעות שיוערכו בשלב מאוחר יותר.

קדימות 1 (הגבוהה ביותר)
( ... )

סוגריים עגולים מוערכים תמיד ראשונים

קדימות 2
הודעות אונריות

מוערכות שניות (למשל factorial)

קדימות 3
הודעות בינריות

מוערכות שלישיות (למשל +, *, @)

קדימות 4 (הנמוכה ביותר)
מילות-מפתח

מוערכות אחרונות (למשל raisedTo:)

חוק התיקו (5)
משמאל לימין ➔

הודעות שוות-דרגה מוערכות משמאל לימין בלבד!

2. המלכודת המתמטית: מדוע 3 + 4 * 5 + 2 אינו שווה ל-25?

ההבדל הקריטי בין אריתמטיקה סטנדרטית לבין הרכבת הודעות בינריות ב-Smalltalk

כאן מסתתרת אחת המלכודות הקלאסיות ביותר למי שמגיע ממתמטיקה או משפות כמו Java ו-C: מאחר שכל האופרטורים החשבוניים (+, -, *, /) הם למעשה הודעות בינריות שוות-דרגה, ב-Smalltalk אין קדימות לכפל ולחילוק על פני חיבור וחיסור! כל רצף של הודעות בינריות מוערך באופן רציף אך ורק משמאל לימין.

🟣 הערכת הביטוי 3 + 4 * 5 + 2 ב-Smalltalk:

  1. תחילה נשלחת ההודעה הבינרית השמאלית ביותר: 3 + 4 ומחזירה את העצם 7.
  2. לעצם 7 נשלחת ההודעה הבינרית הבאה: 7 * 5 ומחזירה את העצם 35.
  3. לעצם 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

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

דוגמה א' · ללא סוגריים תוצאה: 128
2 raisedTo: 1 + 3 factorial
  1. שלב 1 – הודעה אונרית: 3 factorial מוערכת ראשונה ומחזירה 6.
  2. שלב 2 – הודעה בינרית: 1 + 6 מוערכת שנייה ומחזירה 7.
  3. שלב 3 – הודעת מילת-מפתח: 2 raisedTo: 7 מוערכת אחרונה ($2^7$) ומחזירה 128!
דוגמה ב' · עם סוגריים תוצאה: 8
(2 raisedTo: 1) + 3 factorial
  1. שלב 1 – סוגריים עגולים: 2 raisedTo: 1 מוערכת ראשונה ($2^1$) ומחזירה 2.
  2. שלב 2 – הודעה אונרית: 3 factorial מוערכת שנייה ומחזירה 6.
  3. שלב 3 – הודעה בינרית: 2 + 6 מוערכת אחרונה ומחזירה 8!
עזר גרפי 7.2 • עץ סדר הערכה: Smalltalk מול אריתמטיקה סטנדרטית

השוואת הערכת הביטוי 3 + 4 * 5 + 2 ועץ הקדימויות ב-2 raisedTo: 1 + 3 factorial

Precedence Trees
🟣 ב-Smalltalk (הודעות בינריות משמאל לימין): 3 + 4 * 5 + 2 1) 3 + 4 ➔ 7 2) 7 * 5 ➔ 35 3) 35 + 2 ➔ 37 ! (במתמטיקה/Java: 4*5=20 ואז 3+20+2 = 25) 🔵 הרכבה רב-שלבית לפי סולם הקדימויות: 2 raisedTo: 1 + 3 factorial 1. אונרי: 3 factorial ➔ 6 2. בינרי: 1 + 6 ➔ 7 3. מילת-מפתח: 2 raisedTo: 7 ➔ 128 עם סוגריים (2 raisedTo: 1) + 3 factorial ➔ 8
⚡

מיני-סימולציה 7.2: השפעת הסוגריים על מקבל ההודעה ועל התוצאה

השווה בין זוגות הביטויים בלחיצה
🕹️
סימולציה אינטראקטיבית גדולה 7.2

מפענח הקדימויות צעד-אחר-צעד (Step-by-Step Evaluation Debugger)

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

שלב 1 מתוך 3
⚡

הגשר הנרטיבי: הבנו איך מתנהגות הודעות אונריות ובינריות – אבל מה קורה כשמופיעות כמה מילות-מפתח ברצף?

כשמופיע רצף של מילים שמסתיימות בנקודתיים, כמו st at: st indexOf: $e put: $x, איך Smalltalk יודעת איפה נגמרת הודעת מילת-מפתח אחת ואיפה מתחילה אחרת? ביחידה הבאה (7.4) נכיר את חוק הרצף הארוך ביותר, נראה מדוע השמטת סוגריים מובילה מיד לשגיאת MessageNotUnderstood, ונבין את ההבדל התהומי שבין סוגריים עגולים () לסוגריים מרובעים []!

פרק 7: שליחת הודעות • סעיף 7.4 זיהוי הודעות מילות-מפתח (Identifying Keyword Messages)

חוק הרצף הארוך ביותר במילות-מפתח, שבירה בסוגריים וההבדל בין () ל-[]

כיצד מקבץ המהדר סדרת מילים עם נקודתיים להודעת מילת-מפתח אחת ארוכה ככל האפשר, איך שוברים את הרצף באמצעות סוגריים, מלכודת ה-MessageNotUnderstood בהחלפת תו במחרוזת ('hello' → 'hxllo'), וההבדל המהותי בין סוגריים עגולים () לסוגריים מרובעים [].

🎯
🧠

מודל מנטלי ועיקרון מנחה: המהדר "חמדן" במילות-מפתח, וסוגריים עגולים אינם בלוק!

💡 האנלוגיה המוחשית

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

⚖️ חוק הברזל הפדגוגי

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

🎯 תובנת המפתח

סוגריים עגולים () קובעים רק סדר הערכה והביטוי בתוכם מוערך פעם אחת בלבד. סוגריים מרובעים [] יוצרים עצם מסוג בלוק (Block) שיכול להיות מוערך 0 או יותר פעמים!

1. חוק הרצף הארוך ביותר (Greedy Keyword Matching) ושבירתו בסוגריים

איך המהדר מפענח סדרה של מילות-מפתח המסתיימות בנקודתיים?

ראינו שהודעת מילת-מפתח יכולה להיות מורכבת ממילת מפתח אחת או מכמה מילות מפתח המסתיימות בסימן נקודתיים (:) ומלוות בארגומנטים. אבל מה קורה כאשר אנחנו כותבים ביטוי המורכב מרצף של מילות מפתח? כלל הזהב של המהדר ב-Smalltalk הוא חוק הרצף הארוך ביותר: כאשר מופיעה סדרת מילים המסתיימות בנקודתיים בליווי ארגומנטים, המהדר יקבץ אותן תמיד להודעת מילת-מפתח אחת ארוכה ככל האפשר!

1. ללא סוגריים (רצף מלא)
x word1: arg1 word2: arg2 word3: arg3

מפורש כשליחת הודעת מילת-מפתח בודדת וארוכה בשם word1:word2:word3: אל העצם x (עם 3 ארגומנטים).

2. שבירה אחרי word2:
(x word1: arg1 word2: arg2) word3: arg3

שולח תחילה את ההודעה word1:word2: לעצם x, ולאחר מכן שולח את ההודעה word3: אל העצם שחזר מההודעה הראשונה!

3. שבירה אחרי word1:
(x word1: arg1) word2: arg2 word3: arg3

שולח תחילה את ההודעה word1: לעצם x, ולאחר מכן שולח את ההודעה word2:word3: אל העצם שחזר מההודעה הראשונה!

2. דוגמת מפתח מעשית: החלפת תו במחרוזת ('hello' → 'hxllo')

מדוע השמטת הסוגריים גורמת מיד לקריסה בשגיאת MessageNotUnderstood?

נתבונן בקטע הקוד הבא, שמטרתו להחליף את התו 'e' (הנכתב כ-$e) בתו 'x' (הנכתב כ-$x) בתוך המחרוזת 'hello':

✅ הכתיבה הנכונה (עם סוגריים) תוצאה: 'hxllo'
st := 'hello'.
st at: (st indexOf: $e) put: $x.

מה מתרחש כאן? הסוגריים העגולים תוחמים את הביטוי (st indexOf: $e), ששולח למחרוזת st את ההודעה indexOf: ומחזיר את האינדקס 2. לאחר מכן, לעצם st נשלחת ההודעה at:put: עם הארגומנטים 2 ו-$x, ובסיום st מכיל את המחרוזת 'hxllo'!

❌ המלכודת ללא סוגריים MessageNotUnderstood!
st := 'hello'.
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:, חייבים תמיד להיות מוגדרים כבלוקים [] — מפני שאי אפשר לדעת מראש אם או כמה פעמים הם יוערכו בזמן ריצה. סוגריים עגולים לעולם אינם מהווים תחליף לסוגריים מרובעים!

עזר גרפי 7.3 • קיבוץ מילות-מפתח וההבדל בין () ל-[]

שבירת הרצף הארוך ביותר ב-at:put: והשוואת תיחום הערכה () מול עצם בלוק []

Greedy Keywords & Blocks
1. חוק הרצף הארוך ביותר במילות-מפתח (7.4) ❌ ללא סוגריים: st at: st indexOf: $e put: $x מזהה יחיד שגוי: at:indexOf:put: 💥 קריסה: MessageNotUnderstood! ✅ עם סוגריים: st at: (st indexOf: $e) put: $x 1) בסוגריים: st indexOf: $e מחזיר אינדקס 2 2) בחוץ: st at: 2 put: $x ➔ 'hxllo' 2. סוגריים עגולים ( ) מול סוגריים מרובעים [ ] סוגריים עגולים ( ... ) קובעים סדר הערכה ושוברים רצף מילות-מפתח. מוערכים בדיוק פעם אחת (1x) באופן מיידי! סוגריים מרובעים [ ... ] יוצרים עצם מסוג בלוק (Block) לעיכוב הערכה. מוערכים 0 או יותר פעמים (חובה ב-ifTrue: / whileTrue:!)
✂️

מיני-סימולציה 7.3: מפצל רצף מילות-המפתח (word1:word2:word3:)

לחץ כדי לשים סוגריים במקומות שונים ולראות אילו הודעות נשלחות
🧪
סימולציה אינטראקטיבית גדולה 7.3

מעבדת החלפת התו במחרוזת ('hello') ומבחן הסוגריים () מול []

חלק א': ניסוי החלפת תו במחרוזת st := 'hello'
חלק ב': ניסוי סוגריים עגולים () מול בלוק [] ב-ifTrue: / whileTrue:
⚡

הגשר הנרטיבי: למדנו לבנות ביטוי בודד מושלם – עכשיו איך מחברים סדרה של משפטים ואיך שולחים מפל של הודעות (Cascade) לאותו עצם?

בתוכנית אמיתית אנחנו כותבים רצף של משפטים המופרדים בנקודה (.) או שולחים מספר הודעות ברצף אל אותו מקבל בדיוק באמצעות סימן הנקודה-פסיק (; – Cascade). ביחידה הבאה (7.5–7.6) נגלה מה מחזירה סדרת ביטויים, מי הוא המקבל ב-Cascade, ואיך השמטה של נקודה-פסיק אחת משנה שטח מלבן מ-400 ל-0 או הופכת תוצאת isZero מ-false ל-true!

פרק 7: שליחת הודעות • סעיפים 7.5–7.6 סדרת ביטויים (Sequence of Statements) והודעות Cascade

סדרת ביטויים (.) ומפל הודעות 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), הצהרת משתנים מקומיים וכלל הערך המוחזר מהמשפט האחרון

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

1. נקודה כמפריד משפטים בלבד (.)

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

2. הצהרת משתנים מקומיים (| ... |)

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

3. כלל הערך המוחזר מהסדרה

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

| st1 st2 |
st1 := 'xxyyzz'.
st2 := 'yz'.
st1 includesSubString: st2   "מחזיר true — זהו הביטוי האחרון ולכן זהו הערך המוחזר מהסדרה כולה!"

2. סעיף 7.6: הודעות Cascade (מפל הודעות – ;) ושלושת מקרי הבוחן

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

ישנם מקרים רבים שבהם נרצה לשלוח מספר הודעות ברצף אל אותו עצם בדיוק (מקבל יחיד), מבלי להגדיר אותו או לחשב אותו מחדש. כאן נכנס לשימוש מנגנון ה-Cascade באמצעות סימן נקודה-פסיק (;):

  • כלל יסוד 1 – מיהו המקבל?: המקבל נקבע לפי הביטוי שנרשם לפני הנקודה-פסיק הראשונה (ויכול להיות בעצמו עצם שהוחזר משליחת הודעה אחרת). כל ההודעות שלאחר מכן ברצף ה-Cascade נשלחות תמיד אל אותו המקבל המקורי, ללא שום תלות במה שהחזירו ההודעות הקודמות!
  • כלל יסוד 2 – מהו הערך המוחזר?: הערך המוחזר מביטוי Cascade שלם הוא תמיד הערך שמוחזר מהשליחה של ההודעה האחרונה ברצף!

🔍 מקרה בוחן 1: פעולות על נקודה ומלבן – false מול true

השפעת ה-; הראשונה על המקבל
10@10 - 10; corner: 30@30; isZero
  1. איתור המקבל: המקבל של ה-Cascade (לפני ההודעה הראשונה - 10 שלפני ה-;) הוא הנקודה 10@10 (שנוצרה מ-10 @ 10).
  2. הודעה 1 (- 10): נשלחת ל-10@10, מפחיתה 10 מרכיבי x ו-y ומחזירה 0@0 — אך התוצאה נזרקת ואינה נשמרת!
  3. הודעה 2 (corner: 30@30): נשלחת שוב ל-10@10 ומחזירה מלבן שפינותיו 10@10 ו-30@30 — גם תוצאה זו נזרקת!
  4. הודעה 3 ואחרונה (isZero): נשלחת שוב לנקודה המקורית 10@10. מאחר ש-10@10 אינה אפס, מוחזר false!
10@10 - 10 corner: 30@30; isZero

מה קורה כשמשמיטים את הנקודה-פסיק הראשונה?

  1. ללא ; אחרי - 10, תחילה מתבצע הביטוי הבינרי 10@10 - 10 במלואו ומחזיר נקודה חדשה: 0@0!
  2. כעת, מקבל ה-Cascade הופך להיות הנקודה החדשה 0@0!
  3. אל 0@0 נשלחת ההודעה corner: 30@30 (תוצאתה נזרקת), ולאחריה נשלחת אל 0@0 ההודעה האחרונה isZero.
  4. מאחר שהנקודה המקבלת היא 0@0, ההודעה isZero מחזירה כעת true!

📐 מקרה בוחן 2: תרגיל חישוב שטח מלבן (area) – 400 מול 0

מלבן $20 \times 20$ מול מלבן מנוון $0 \times 0$
(10@10 + 20; corner: 30@30) area
  • בתוך הסוגריים ישנו 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 corner: 30@30) area

מה יקרה אם נשמיט את הנקודה-פסיק?

  1. ללא נקודה-פסיק, הביטוי הבינרי 10@10 + 20 מחושב ראשון לחלוטין ומחזיר את הנקודה החדשה 30@30.
  2. לנקודה החדשה הזו (30@30) נשלחת ההודעה corner: 30@30.
  3. נוצר מלבן מנוון שפינתו השמאלית-עליונה היא 30@30 ופינתו הימנית-תחתונה היא 30@30 (רוחבו 0 וגובהו 0).
  4. שליחת ההודעה area למלבן זה מחזירה: $0 \times 0 =$ 0!

🏆 מקרה בוחן 3: מלכודת הבחינות בהוספה לאוספים (add: מול yourself)

הודעת yourself במחלקת Object
❌ המלכודת הנפוצה (ללא yourself):
collection := OrderedCollection new.
collection add: 1; add: 2.

המתכנת מצפה שביטוי ה-Cascade יחזיר את האוסף עם האיברים 1 ו-2. בפועל, ביטוי Cascade מחזיר את הערך של ההודעה האחרונה (add: 2). המתודה add: מחזירה לפי המוסכמה את האיבר שנוסף (2) ולא את האוסף!

✅ הפתרון התקני – שליחת הודעת yourself:
collection := OrderedCollection new
    add: 1; add: 2; yourself.

המתודה האונרית yourself (המוגדרת במחלקת Object) פשוט מחזירה את self (את המקבל המקורי של ה-Cascade), וכך מובטח שהערך החוזר מה-Cascade כולו יהיה האוסף עצמו!

עזר גרפי 7.4 • מנגנון ה-Cascade והמחשה גיאומטרית של מלבני הניסוי

ניתוב הודעות למקבל יחיד ב-Cascade והשוואת המלבן (10@10 + 20; corner: 30@30) area עם ובלי ;

Cascade & Area Geometry
1. ניתוב הודעות ב-Cascade לאותו מקבל מקורי 10@10 המקבל המקורי 1) - 10 ; מחזיר 0@0 (נזרק!) 2) corner: 30@30 ; מחזיר מלבן (נזרק!) 3) isZero ✓ מחזיר false (התוצאה!) 2. גיאומטריית המלבן: עם נקודה-פסיק מול בלי נקודה-פסיק עם ; (המקבל הוא 10@10) 10@10 30@30 20 × 20 = 400 area = 400 ! בלי ; (המקבל הפך ל-30@30) 30@30 corner: 30@30 מלבן מנוון (0 × 0) area = 0 !
🧪

מיני-סימולציה 7.4: בוחן הערך המוחזר – סדרת משפטים (.) ומלכודת yourself

לחץ על כל קטע קוד כדי לראות מה באמת מוחזר ממנו
🌊
סימולציה אינטראקטיבית גדולה 7.4

מעבדת ה-Cascade החיה: הדלק וכבה את הנקודה-פסיק (;) ב-3 מקרי הבוחן!

בחר אחד משלושת מקרי הבוחן, ולחץ על מתג הנקודה-פסיק (או מתג ה-yourself) כדי לראות בזמן אמת כיצד משתנה מקבל ההודעה ומה מוחזר מהביטוי כולו:

⚡

הגשר הנרטיבי: השלמנו את כל סעיפי פרק 7 – בוא נבחן את השליטה שלנו במילון המושגים האינטראקטיבי!

עברנו דרך כל מנגנון שליחת ההודעות ב-Smalltalk: מ-14 הסימנים התחביריים וזיהוי המקבל, המזהה והארגומנטים (7.1), דרך שלוש תבניות ההודעה (7.2), סדר הקדימויות והמלכודת המתמטית (7.3), זיהוי הודעות מילות-מפתח וההבדל בין () ל-[] (7.4), ועד לסדרת ביטויים (7.5) ומפל הודעות Cascade (7.6). נעבור כעת ליחידה המסכמת של הפרק כדי לתרגל בכרטיסיות תלת-ממדיות ולהתכונן לפרק 8!

פרק 7: שליחת הודעות • יחידה 7.7 סיכום אינטגרטיבי ומילון מושגים

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

חיבור כל חוקי שליחת ההודעות ב-Smalltalk למפה הנדסית שלמה, בוחן אבחנה מהיר למלכודות הנפוצות, ו-12 כרטיסיות זיכרון תלת-ממדיות (3D Flashcards) עם מצב בחינה ומצב למידה.

🏆
🧠

מודל מנטלי ועיקרון מנחה: שלוש השאלות שפותרות כל ביטוי ב-Smalltalk!

💡 שאלה 1: מהי תבנית ההודעה?

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

⚖️ שאלה 2: מהו סדר ההערכה?

הערך תמיד לפי הסדר הקשיח: סוגריים () → אונריות → בינריות → מילות-מפתח, ובתוך אותה דרגת קדימות הערך אך ורק משמאל לימין (ללא קדימות של כפל על חיבור!).

🎯 שאלה 3: מיהו המקבל ומה מוחזר?

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

עזר גרפי 7.5 • מפת השליטה השלמה בפרק 7

מתבניות ההודעה וסדר הקדימות ועד לשבירת מילות-מפתח ומנגנון ה-Cascade

Chapter 7 Master Map
1. זיהוי ותבניות (7.1–7.2) • Receiver + Selector + Args • אונרית: 3 factorial (0 ארג') • בינרית: 3 + 2 (1 ארג') • מילת-מפתח: at: 2 put: 10 לכל האופרטורים קדימות זהה! 2. קדימות והערכה (7.3) 1) סוגריים עגולים ( ... ) 2) הודעות אונריות 3) הודעות בינריות 4) הודעות מילת-מפתח משמאל לימין: 3+4*5+2 = 37 3. מילות-מפתח ו-[] (7.4) • קיבוץ הרצף הארוך ביותר • שבירה בסוגריים: (indexOf:) • ( ) מוערך פעם אחת בלבד • [ ] יוצר עצם Block (0..N) ללא () ➔ MessageNotUnderstood 4. משפטים ו-Cascade (7.5–7.6) • נקודה (.) היא מפריד בלבד • מוחזר ערך הביטוי האחרון • ב-Cascade - נקודה-פסיק המקבל קבוע • השמטת ; משנה את המקבל! באוספים: add: 1; add: 2; yourself
⚡

מיני-סימולציה 7.5: בוחן אבחנה מהיר – 4 מלכודות המבחנים של פרק 7

לחץ על כל מלכודת כדי לראות את הפתרון המדויק
🃏
סימולציה אינטראקטיבית גדולה 7.5

כרטיסיות זיכרון תלת-ממדיות (3D Flashcards) לכל 12 מושגי פרק 7

לחץ על כל כרטיסייה כדי להפוך אותה ולבחון את עצמך על כל אחד מ-12 מושגי המפתח של פרק 7:

נחשפו: 0 / 12
🚀

סיימנו במלואו את פרק 7 (שליחת הודעות)! מה מחכה לנו בפרק 8?

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

🎯 בפרק 8 (מודל התכנות בשפת Smalltalk ומודל העצם) נחקור יחד: • מבנה מודל העצמים ב-Smalltalk וכמוסות (Encapsulation).
• משתני מופע (Instance Variables) מול משתני מחלקה (Class Variables).
• שיטות גישה (Accessors) ומחלקות מופשטות (subclassResponsibility).
🕹️

מעבדת חקר אינטראקטיבית

❓

5 שאלות פתוחות מדורגות + 5 שאלות אמריקאיות עם הסברים מלאים לכל יחידה

🚀 השלב הבא שלנו: פרק 8 – מודל התכנות בשפת Smalltalk ומודל העצם

השלמנו במלואו את פרק 7: שליחת הודעות ב-Smalltalk! בפרק 8 נחקור יחד את מודל התכנות בשפת Smalltalk ומודל העצם: