ייצוג מחלקה באמצעות עצם: אם מחלקה היא עצם — מי המחלקה שלה?
הכרת מושג ה"מטה-מחלקה" (Metaclass) כיחידת ההפשטה המייצגת מחלקה של מחלקה, תכונת האנונימיות (Implicit), וחקירת שרשרת ההודעות true class... עד להתכנסות למעגל סגור (Fixed Point).
מודל מנטלי ועיקרון מנחה: כש"הכל הוא עצם" פוגש את "כל עצם הוא מופע של מחלקה"
תבנית אפייה מייצרת עוגיות, אבל מי ייצר את תבנית האפייה עצמה? מפעל ליצירת תבניות! ב-Smalltalk, עוגייה היא עצם רגיל, תבנית האפייה היא המחלקה (Class), והמפעל שמייצר את התבנית הזו הוא המטה-מחלקה (Metaclass)!
ב-Smalltalk כל דבר במערכת הוא עצם (כולל המחלקות Object, Color, Point), וכל עצם הוא בהכרח מופע של מחלקה. לכן כל מחלקה היא מופע של מטה-מחלקה אנונימית שהגישה אליה נעשית על ידי שליחת ההודעה class אל עצם המחלקה.
שרשור חוזר של ההודעה class (כמו true class class class...) אינו ממשיך לאינסוף! החל מהצעד השלישי והרביעי אנו מתכנסים למעגל סגור (Fixed Point) המתחלף לסירוגין בין Metaclass לבין Metaclass class.
1. שאלת היסוד שסוגרת את מעגל העקביות ב-Smalltalk
איך שני כללי היסוד שלנו מובילים בהכרח להולדת המושג "מטה-מחלקה" (Metaclass)
אנחנו מגיעים עכשיו אל שיא הארכיטקטורה של Smalltalk — המקום שבו כל חלקי הפאזל שבנינו מתחברים למערכת אחת שלמה, עקבית וסגורה. בוא נזכיר לעצמנו את עקרון היסוד שליווה אותנו מהרגע הראשון ב-Smalltalk: כל דבר במערכת הוא עצם (Everything is an object), וכל עצם הוא בהכרח מופע של מחלקה (Every object is an instance of a class).
עכשיו בוא נחשוב יחד כמו מהנדסי שפות תכנות: אם כל דבר במערכת הוא עצם, נובע מכך ישירות שגם המחלקות עצמן (כגון Object, Color, Point או True) הן עצמים חיים בזיכרון! אנחנו הרי שולחים להן הודעות כל הזמן (כמו Point new או Color blue).
אבל אם מחלקה היא עצם, מיד מתעוררת השאלה הלוגית המתבקשת: של איזו מחלקה היא מופע?
הגדרת המושג: מטה-מחלקה (Metaclass)
מחלקה שהמופעים שלה הם בעצמם מחלקות נקראת מטה-מחלקה (Metaclass). זוהי יחידת ההפשטה המטפלת במנגנון של "מחלקה של מחלקה".
class. למשל: שליחת class למחלקה Color מחזירה את המטה-מחלקה שלה, שנקראת פשוט Color class, ושליחת class ל-Object מחזירה את Object class.
2. ניסוי מחשבתי חי: שרשור ההודעה true class...
מה קורה כשאנחנו שואלים שוב ושוב "ומהי המחלקה של המחלקה הזו?" לאורך 7 שלבים עוקבים?
כדי לראות במו עינינו איך סביבת Squeak עונה על השאלה "מי המחלקה של המטה-מחלקה?", בוא ניקח את העצם הבוליאני הפשוט true ונשלח אליו את ההודעה class שוב ושוב בשרשרת של 7 שלבים:
true class
המופע הבוליאני true הוא מופע יחיד של המחלקה True (תת-מחלקה של Boolean). לכן מוחזרת המחלקה True.
true class class
כעת אנו שואלים את המחלקה True מהי המחלקה שלה. מוחזרת המטה-מחלקה האנונימית שלה: True class.
true class class class
מהי המחלקה של מטה-מחלקה (True class)? כל המטה-מחלקות במערכת הן מופעים של מחלקה אחת מיוחדת: מוחזרת המחלקה Metaclass!
true class class class class
ומהי המחלקה של Metaclass? מכיוון שגם Metaclass היא מחלקה, יש לה מטה-מחלקה משלה: מוחזרת Metaclass class!
true class class class class class ➔ Metaclass ➔ Metaclass class ➔ Metaclass
בשלב 5 אנחנו שואלים: מהי המחלקה של Metaclass class? מכיוון ש-Metaclass class היא בעצמה מטה-מחלקה, היא מופע של Metaclass!
בשלבים 6 ו-7 (וכך עד אינסוף) אנו נכנסים למעגל סגור (Fixed Point) המתחלף לסירוגין בין Metaclass class לבין Metaclass — וכך נמנעת רגרסיה אינסופית!
מסלול ההתכנסות מהמופע הבוליאני true אל לולאת ה-Fixed Point של Metaclass
מיני-סימולציה 18.1: בודק המופעים והמטה-מחלקות האנונימיות
קונסולת "מדרגות ה-Class" ב-Squeak: שרשור true class... (שלבים 1 עד 7)
בחר את עצם ההתחלה או לחץ על "שלח הודעת class נוספת (+)" כדי לטפס שלב אחר שלב בסולם ההפשטה ולראות בזמן אמת מתי המערכת נכנסת למעגל הסגור (Fixed Point) בין Metaclass ל-Metaclass class:
הגשר הנרטיבי: ראינו ששרשור class עובר דרך 5 רמות עד למעגל הסגור – אבל למה בכלל צריך 5 רמות?
אולי אתה שואל את עצמך עכשיו: "רגע, למה בעצם אנחנו צריכים גם מופע, גם מחלקה, גם מטה-מחלקה פרטית, גם Metaclass וגם Metaclass class? האם אי אפשר היה להסתפק במערכת פשוטה יותר של רמה אחת, שתיים או שלוש?"
בלשונית הבאה נצא למסע היסטורי והנדסי מרתק לאורך 5 ארכיטקטורות של מערכות עצמים (משפת Self ועד Squeak), ונראה בדיוק איזו מגבלה בכל רמה הכריחה אותנו לטפס לרמה החמישית!
סיווג עצמים למטה-רמות (Meta-levels) והתפתחות מערכות העצמים מרמה 1 ועד 5 רמות
שלוש שכבות העצמים (מופעים סופיים, מחלקות ומטה-מחלקות בדוגמת המחזות והרומנים), וניתוח מעמיק של 5 ארכיטקטורות: Self (רמה 1), Eiffel ו-++C (רמה 2), Smalltalk-76 ו-Little Smalltalk (רמה 3), LOOPS ו-ObjVlisp (רמה 4), ו-Squeak / Smalltalk-80 (רמה 5).
מודל מנטלי ועיקרון מנחה: כדי שלכל מחלקה יהיו בנאים ומתודות מחלקה משלה, היא חייבת מטה-מחלקה פרטית!
המופע "אוליבר טוויסט" הוא ספר קריאה סופי שאינו יכול לייצר ספרים חדשים. המחלקה "רומן" (Novel) מייצרת ספרים ספציפיים, והמטה-מחלקה (Class / Metaclass) היא זו שמייצרת את המחלקות עצמן ("רומן", "מחזמר").
במערכת בת 3 רמות (כמו Smalltalk-76), כל המחלקות הן מופעים של מטה-מחלקה יחידה (Class), ולכן לא ניתן להגדיר בנאים ייחודיים לכל מחלקה (כמו Point x:y:) מבלי לחשוף אותם לכל שאר המחלקות במערכת!
מודל 5 הרמות של Squeak (Explicit Metaclass) מעניק לכל מחלקה מטה-מחלקה פרטית משלה בהיררכיה מקבילה, וקושר את כל המטה-מחלקות למחלקה Metaclass בקשר מעגלי סגור עם Metaclass class.
1. סעיף 18.2: סיווג עצמים לשלוש שכבות היררכיות (Meta-levels)
הבחנה בין מופעים סופיים (Terminal Instances), מחלקות (Classes) ומטה-מחלקות (Metaclasses)
כדי שנבין לעומק מדוע סביבת Squeak בנויה דווקא במודל של 5 רמות, בוא נסווג תחילה את העצמים בעולם התוכנה שלנו לשלוש שכבות היררכיות עקרוניות לפי יכולת היצירה (Instantiation) שלהם:
1. עצמים פשוטים / מופעים סופיים
עצמים בקצה השרשרת שאינם מסוגלים לייצר עצמים חדשים. למשל: מופעים של תווים, מחרוזות, נקודות, או בדוגמת היצירות הספרותיות והבימתיות: המופעים "אותלו", "מקבת", "כטוב בעיניכם" (מופעי מחזמר/מחזה) ו-"1984", "אוליבר טוויסט", "מלחמה ושלום" (מופעי רומן).
2. מחלקות (עצמים מייצרי מופעים)
עצמים המסוגלים לייצר מופעים סופיים. בדוגמה שלנו אלו הן המחלקות "מחזמר" ו-"רומן" (Novel), או בשפה שלנו המחלקות Point, Color ו-String.
3. מטה-מחלקות (מייצרות מחלקות)
עצמים המסוגלים לייצר מחלקות חדשות (כגון המחלקה הגנרית Class או מטה-המחלקות ב-Squeak). המופעים שלהן הם המחלקות מהשכבה השנייה!
2. סעיפים 18.3–18.7: התפתחות מערכות העצמים – מרמה 1 ועד 5 רמות
איך שפות התכנות מונחות העצמים נבדלות זו מזו במספר ה"רמות" במודל העצמים שלהן, ומה פתר כל שלב?
אפיון: מערכת "שטוחה" ללא מחלקות כלל. כל עצם מתאר את עצמו באופן עצמאי (טבלה של שמות וערכים — שדות ומתודות ייעודיים), ויצירת עצמים חדשים נעשית באמצעות שכפול (Cloning) של עצם אב-טיפוס קיים (Prototype), תוך שיתוף התנהגות באמצעות מצביעי parent ו-traits.
אפיון: קיימת הבחנה ברורה בין עצמים למחלקות (עצמים מתוארים על ידי מחלקות), אך המחלקות עצמן אינן עצמים בזמן ריצה! הן מתקיימות כיישויות תחביריות בזמן הידור בלבד, אינן מיוצגות כעצמים חיים בזיכרון ואינן מסוגלות לקבל הודעות.
אפיון: המחלקות הן עצמים חיים בזמן ריצה המגיבים להודעות, וכל המחלקות כולן הן מופעים של מטה-מחלקה גנרית יחידה ומשותפת (הנקראת לרוב Class), היורשת מהמחלקה הגנרית "עצם" (Object) ומגדירה את המבנה האופייני של מחלקה (משתני מופע, מצביע למחלקת-על, מילון מתודות) ואת מתודת היצירה המשותפת new.
⚠️ המגבלה המרכזית: מכיוון שכל המחלקות הן מופעים של אותה מטה-מחלקה יחידה (Class), לכל המחלקות יש בדיוק את אותן מתודות מחלקה ואת אותם משתני מחלקה! לא ניתן להגדיר בנאים ייחודיים לכל מחלקה (כמו Point x: 3 y: 4 או Color r:g:b:) מבלי לחשוף אותם לכל שאר המחלקות במערכת!
אפיון: פותרת את מגבלת רמה 3 בכך שהיא מאפשרת להגדיר מטה-מחלקה פרטית לכל מחלקה (או לשתף מטה-מחלקה בין מספר מחלקות), וכך לכל מחלקה יכולים להיות מתודות מחלקה ומשתני מחלקה ייחודיים משלה (ומדיניות יצירת מופעים עצמאית). כל המטה-מחלקות הפרטיות הללו הן מופעים של מטה-מחלקה גנרית משותפת אחת ("מטה-עצם" / "המטה-מחלקה בה' הידיעה"), היורשת מ"עצם".
אפיון: לכל מחלקה נוצרת אוטומטית מטה-מחלקה פרטית משלה שמתארת רק אותה, וגרף הירושה של המטה-מחלקות חופף ומקביל לגרף הירושה של המחלקות הרגילות. כל המטה-מחלקות הן מופעים של המחלקה הגנרית Metaclass, שלה עצמה יש מטה-מחלקה משלה (Metaclass class). המודל פותר את בעיית הרגרסיה האינסופית ("מי יצר את המטה-מחלקה?") באמצעות קשר מעגלי סגור בין Metaclass ל-Metaclass class!
משכפול אב-טיפוס ברמה 1 (Self) ועד למודל 5 הרמות והמעגל הסגור ב-Squeak
מיני-סימולציה 18.2: מסווג שלוש שכבות העצמים (דוגמת הספרים והמחזות – סעיף 18.2)
מכונת הזמן של הארכיטקטורות: מרמה 1 (Self) ועד רמה 5 (Squeak)
עבור בין 5 הארכיטקטורות ונסה בכל אחת מהן לבצע שלוש משימות הנדסיות: (1) יצירת עצם חדש בזמן ריצה, (2) שליחת הודעה למחלקה עצמה, ו-(3) הגדרת בנאי ייחודי למחלקה (כמו Point x: 10 y: 20):
הגשר הנרטיבי: הבנו מדוע Squeak זקוקה ל-5 רמות – עכשיו בוא נפרוס את 10 החוקים השולטים במודל הזה!
עכשיו, כשהבנו מדוע מודל 5 הרמות של Squeak ו-Smalltalk-80 נולד, אנחנו מוכנים לצלול אל חוקי הברזל שמנהלים כל אינטראקציה במערכת.
בלשונית הבאה נתחיל מחמשת החוקים הבסיסיים (חוקים 1–5), ננתח שורת קוד חיה שיוצרת אליפסה בצבע כחול שקוף (TranslucentColor), ונעקוב צעד-אחר-צעד אחר אלגוריתם איתור המתודה (Method Lookup) במעלה שרשרת הירושה!
מודל העצמים ב-Smalltalk: חמשת החוקים הבסיסיים ואיתור מתודות במעלה ההיררכיה
חמשת חוקי היסוד הראשונים (Rules 1–5), ניתוח דוגמת הקוד של EllipseMorph ו-TranslucentColor, וההבחנה הקריטית בין "קשר מופע" (Instance of – צעד ראשון באיתור) לבין "קשר ירושה" (Superclass – המשך הטיפוס).
מודל מנטלי ועיקרון מנחה: צעד אחד על חץ "מופע של", ואז טיפוס על חיצי "ירושה" בלבד!
כשאתה שולח הודעה לעצם (כמו translucentBlue class), העצם לא מחזיק בתוכו את קוד המתודות. הוא עושה צעד אחד אל המחלקה שלו (TranslucentColor), ומשם מטפס במדרגות הירושה (Color ← Object) עד שהוא מוצא את המתודה!
לעולם אל תבלבל בין קשר מופע (Instance of) לבין קשר ירושה (Inherits from): איתור מתודה חוצה קשר מופע פעם אחת בלבד בהתחלה (מהמקבל אל מחלקתו), ומאותו רגע עולה אך ורק בשרשרת הירושה (superclass).
כאשר המתודה class מאותרת לבסוף במחלקה Object ומורצת, המשתנה הפנימי self שלה עדיין מצביע על המקבל המקורי (translucentBlue), ולכן מוחזרת מחלקתו המדויקת: TranslucentColor!
1. סעיף 18.8: חמשת החוקים הבסיסיים של מודל העצמים (Rules 1–5)
חמשת עמודי התווך הראשונים שעליהם נשענת כל פעולה ב-Squeak
מודל העצמים השלם של Squeak נשלט על ידי עשרה חוקי יסוד מדויקים. חמשת החוקים הראשונים מסכמים את התנהגות העצמים, המחלקות והירושה הרגילה:
כל דבר במערכת הוא עצם.
כל עצם הוא מופע של מחלקה.
לכל מחלקה יש מחלקת-על (למעט שורש העץ ProtoObject).
כל חישוב מתבצע אך ורק באמצעות שליחת הודעות.
איתור מתודה מתחיל במחלקת המופע ועולה במעלה שרשרת הירושה.
2. הוכחת החוקים בקוד חי: Color, TranslucentColor ו-EllipseMorph
פירוק שורת הקוד של אליפסה בכחול שקוף וזיהוי כל העצמים וההודעות שבה
בוא נבחן סדרת ביטויים ב-Squeak שממחישה כיצד חמשת החוקים האלה פועלים יחד ביצירת צורה גרפית שקופה למחצה:
בוא ננתח בדיוק אילו הודעות נשלחות כאן ולאילו עצמים:
- ההודעה
blueנשלחת אל עצם המחלקהColorומחזירה מופע שלColor. - ההודעות
alpha: 0.4ו-classנשלחות אל עצם הצבע: שליחתalpha: 0.4לצבע הכחול יוצרת ומחזירה עצם חדש (שנקרא לוtranslucentBlue), שהוא מופע של תת-המחלקהTranslucentColor! - מחלקת-העל (
superclass) שלTranslucentColorהיאColor, ומחלקת-העל שלColorהיאObject(ההודעהsuperclassנשלחת לעצם המחלקה). - ההודעות
color:ו-openInWorldנשלחות בשרשור (Cascade עם;) אל המופע החדש שנוצר מהמחלקהEllipseMorph.
3. סעיף 18.9: כיצד מאותרת המתודה class בעת שליחתה ל-translucentBlue?
מעקב דו-שלבי: קפיצת "מופע של" (קו מקווקו) ואחריה טיפוס בשרשרת "יורשת מ-" (קו רציף)
כאשר אנחנו מבצעים את הביטוי translucentBlue class (כלומר (Color blue alpha: 0.4) class), מתרחש תהליך איתור המתודה (Method Lookup) לפי חוק 5:
- מעבר מהעצם למחלקתו (Instance of): המקבל הוא העצם
translucentBlue. מנגנון האיתור פונה אל המחלקה שממנה הוא נוצר —TranslucentColor. - חיפוש ב-
TranslucentColor: האם המתודהclassמוגדרת ב-TranslucentColor? לא! - טיפוס למחלקת-העל
Color: האיתור עולה במעלה קשר הירושה אלColor. האםclassמוגדרת שם? לא! - טיפוס למחלקת-העל
Object: האיתור ממשיך לעלות אלObject. האם המתודהclassמוגדרת ב-Object? כן! נמצאה! המתודה מופעלת על המקבל המקורי (self = translucentBlue) ומחזירה את מחלקתו:TranslucentColor.
הבחנה בין קשר מופע (מקווקו) לקשר ירושה (רציף) בשליחת translucentBlue class
מיני-סימולציה 18.3: מפרק ההודעות והעצמים בביטוי ה-EllipseMorph
סימולטור איתור מתודות חי (Method Lookup) ויצירת EllipseMorph שקוף
שנה את ערך השקיפות (alpha:) כדי ליצור צבע אטום (alpha = 1.0, מופע של Color) או שקוף למחצה (alpha = 0.4, מופע של TranslucentColor), ובצע מעקב צעד-אחר-צעד אחר איתור ההודעה בשרשרת הירושה:
alpha:) עבור האליפסה:
alpha: 0.4 (TranslucentColor)
הגשר הנרטיבי: הבנו איך מאתרים מתודה שנשלחת למופע רגיל – אבל מה קורה כששולחים הודעה למחלקה עצמה (כמו TranslucentColor blue או TranslucentColor new)?
ראינו שכאשר שולחים הודעה למופע translucentBlue, החיפוש מתחיל במחלקתו TranslucentColor ועולה אל Color ואל Object.
אבל מה קורה כשאנחנו שולחים הודעה ישירות לעצם המחלקה TranslucentColor (למשל TranslucentColor blue או TranslucentColor new)? היכן מתחיל החיפוש אז, ואיך היררכיית המטה-מחלקות המקבילה (חוקים 6 ו-7) פותרת את אחת ממלכודות הבחינה המפורסמות ביותר? בוא נעבור ללשונית 4!
עקרונות המטה-מחלקות, היררכיה מקבילה (Rule 7) ותהליך איתור המתודה new
6 עובדות הברזל של מטה-מחלקות (Rule 6), ההודעות שמחלקות מקבלות כעצמים, אפקט הראי של ההיררכיה המקבילה (Rule 7), שכתוב מתודות מחלקה (blue), ומלכודת הבחינה הקלאסית: כיצד מאותרת TranslucentColor new ב-Behavior!
מודל מנטלי ועיקרון מנחה: אפקט הראי — היררכיית המטה-מחלקות משקפת במדויק את היררכיית המחלקות!
לכל מחלקה יש "צל" צמוד ואישי משלה — המטה-מחלקה שלה (למשל ל-Color יש את Color class). כשהמחלקה TranslucentColor יורשת מ-Color, גם ה"צל" שלה (TranslucentColor class) יורש אוטומטית מה"צל" של Color (Color class)!
הקשר בין מחלקה (TranslucentColor) לבין המטה-מחלקה שלה (TranslucentColor class) הוא קשר של "מופע של" (Instance of) ולא קשר ירושה! מחלקת-העל של TranslucentColor היא Color.
כשמבצעים TranslucentColor new, החיפוש לא עובר דרך Color! הוא מתחיל ב-TranslucentColor class, מטפס בשרשרת המטה-מחלקות (Color class ← Object class ← Class ← ClassDescription) ונעצר ב-Behavior!
1. סעיף 18.10: חוק 6 – כל מחלקה היא מופע של מטה-מחלקה (Rule 6)
6 עובדות הברזל של מטה-מחלקות וההודעות שאנחנו יכולים לשלוח למחלקות כעצמים חיים
כעת אנו נכנסים אל חמשת החוקים המשלימים של המודל (חוקים 6–10), העוסקים במטה-מחלקות.
חוק 6 קובע: Every class is an instance of a metaclass (כל מחלקה היא מופע של מטה-מחלקה).
בכל פעם שאנחנו יוצרים מחלקה חדשה במערכת (למשל Color), נוצרת עבורה אוטומטית מטה-מחלקה פרטית יחידה (Color class), והמחלקה Color היא המופע היחיד שלה.
📌 6 עובדות הברזל שעליך לזכור על מטה-מחלקות:
class: ההתייחסות למטה-מחלקה נעשית תמיד דרך המופע היחיד שלה — שליחת Color class מחזירה את המטה-מחלקה של Color.
TranslucentColor לבין TranslucentColor class הוא "מופע של"; היא אינה תת-מחלקה שלה! מחלקת-העל שלה היא Color.
💬 אילו הודעות ניתן לשלוח למחלקה בהיותה עצם?
subclasses– מחזירה מערך של תתי-המחלקות הישירות שלה.allSuperclasses– מחזירה אוסף של כל מחלקות-העל שלה בשרשרת הירושה.instVarNames– מחזירה מערך עם שמות משתני המופע שהוגדרו במחלקה עצמה.allInstVarNames– מחזירה את כל שמות משתני המופע, כולל אלו שהוגדרו במחלקות-העל!
🔎 מה מציג חלון ה-Inspector כשבוחנים עצם ומחלקה?
כאשר אתה פותח את כלי ה-Inspector על עצם (כגון הצבע הכחול Color blue), כותרת חלון ה-Inspector מציגה את שם המחלקה שלו (Color) ולא את שם העצם עצמו, כדי לאשר מאיזה טיפוס הוא נוצר. וכאשר תפתח Inspector על עצם המחלקה Color עצמה, הכותרת תציג את מחלקתה — כלומר Color class!
2. סעיף 18.11: חוק 7 – היררכיית המטה-מחלקות מקבילה להיררכיית המחלקות!
אפקט הראי, ירושת מתודות מחלקה (blue), ומסלול איתור המתודה TranslucentColor new
חוק 7 קובע: The metaclass hierarchy parallels the class hierarchy. היררכיית הירושה של המטה-מחלקות מקבילה ומשתקפת באופן מושלם להיררכיית הירושה של המחלקות הרגילות! כלומר, המטה-מחלקה של מחלקת-העל היא מחלקת-העל של המטה-מחלקה:
מהי המשמעות האדירה של חוק 7? המשמעות היא שמתודות מחלקה מורשות בדיוק כמו מתודות מופע! בוא נבחן שני תרחישים מרתקים שמוכיחים זאת:
🔵 תרחיש 1: שליחת TranslucentColor blue ושכתוב (Overriding)
כאשר אנו שולחים את ההודעה blue אל המחלקה TranslucentColor:
1. החיפוש מתחיל במחלקתה של המקבלת — ב-TranslucentColor class.
2. המתודה אינה שם, ולכן החיפוש עולה אל מחלקת-העל שלה — Color class, שם blue מוגדרת ומחזירה כחול רגיל!
💡 שאלה לדיון: כיצד נגרום ל-TranslucentColor blue להחזיר כחול שקוף?
פשוט נגדיר (נדרוס / Override) מתודה בשם blue בתוך המטה-מחלקה TranslucentColor class!
🏆 תרחיש 2 (מלכודת הבחינה!): היכן מוגדרת ומאותרת המתודה new?
כאשר מבצעים TranslucentColor new:
1. המקבל הוא עצם המחלקה TranslucentColor.
2. החיפוש מתחיל במחלקתו — ב-TranslucentColor class (ולא ב-Color!).
3. בהיעדר דריסה מקומית, החיפוש עולה בשרשרת המטה-מחלקות: TranslucentColor class ← Color class ← Object class.
4. מ-Object class החיפוש ממשיך אל מחלקת-העל שלה Class ← ClassDescription ← ונעצר ב-Behavior, שבה המתודה new ממומשת בפועל!
5. המתודה new ב-Behavior משתמשת בערך ה-self (שהוא המקבל המקורי TranslucentColor!) ולכן מחזירה מופע חדש של TranslucentColor (ולא של Behavior)!
היררכיית המחלקות (ימין) מול היררכיית המטה-מחלקות המקבילה (שמאל) ומסלול new עד Behavior
מיני-סימולציה 18.4: משערך הודעות למחלקות ומטה-מחלקות
מעבדת איתור מתודות במטה-מחלקות: TranslucentColor blue ו-TranslucentColor new
בחר אחד משלושת התרחישים הקלאסיים וצפה במסלול האיתור המדויק שלו על גבי היררכיית המטה-מחלקות (כולל מהו ערך ה-self בכל שלב ואיזה מופע מוחזר בסוף!):
הגשר הנרטיבי: ראינו ש-Object class יורשת מ-Class, מ-ClassDescription ומ-Behavior – מה תפקידה של כל אחת מהן, ואיך נסגר המעגל של Metaclass?
במסלול האיתור של new גילינו שבקצה עץ המטה-מחלקות נמצאות שלוש מחלקות ליבה מסקרנות: Class, ClassDescription ו-Behavior.
מדוע הפרידו המתכננים של Smalltalk את ההתנהגות של מחלקות לשלוש שכבות נפרדות? ואיך חוקים 8, 9 ו-10 סוגרים את הקשר המעגלי של Metaclass ו-Metaclass class? בוא נעבור ללשונית 5!
ירושת הליבה (Behavior, ClassDescription, Class) והמעגל הסגור של Metaclass
פירוק תפקידי שלוש מחלקות הליבה (Rule 8), מדוע כל המטה-מחלקות הן מופעים של Metaclass היורשת מ-ClassDescription (Rule 9), וסגירת הקשר המעגלי בין Metaclass ל-Metaclass class (Rule 10).
מודל מנטלי ועיקרון מנחה: כל מטה-מחלקה היא גם "מחלקה" (יורשת מ-Behavior) וגם "עצם" (מופע של Metaclass)!
מכיוון שמטה-מחלקות הן מחלקות שמייצרות מופעים, כולן יורשות בסופו של דבר (דרך Object class) מ-Class ← ClassDescription ← Behavior ← Object.
מכיוון שכל מטה-מחלקה היא גם עצם, כל המטה-מחלקות כולן (TranslucentColor class, Color class, Object class וכו') הן מופעים של המחלקה Metaclass (שיורשת מ-ClassDescription).
המחלקה Metaclass היא מופע של המטה-מחלקה שלה Metaclass class, ואילו Metaclass class (בהיותה מטה-מחלקה!) היא מופע של Metaclass. כאן נעצרת הרגרסיה האינסופית!
1. סעיף 18.12: חוק 8 – כל מטה-מחלקה יורשת מ-Class ומ-Behavior
פירוק שלוש שכבות הליבה שמעניקות למחלקות ולמטה-מחלקות את כוחן: Behavior, ClassDescription ו-Class
ראינו קודם שכל מטה-מחלקה (כמו TranslucentColor class או Color class) יורשת במעלה עץ המטה-מחלקות עד שהיא מגיעה אל Object class.
אבל ממי יורשת Object class? כאן נכנס לפעולה חוק 8 (Rule 8: Every metaclass inherits from Class and Behavior):
בקצה עץ המטה-מחלקות, Object class יורשת מ-Class, אשר יורשת מ-ClassDescription, אשר יורשת מ-Behavior, אשר יורשת מ-Object!
שורש ההתנהגות ויצירת המופעים
מספקת את המינימום ההכרחי הנדרש למחלקה: הגדרת מבנה המופעים, הידור מתודות והרצתן, קישור להיררכיית הירושה, ומכילה את המתודות הבסיסיות ליצירת עצמים: new, basicNew, new: ו-basicNew:.
ארגון, פרוטוקולים ומעקב שינויים
מחלקה מופשטת המרחיבה את Behavior ביכולות ארגוניות המשמשות את סביבת הפיתוח והדפדפנים: שמות מפורשים למשתני מופע, ארגון מתודות בפרוטוקולים (קטגוריות), הערות תיעוד, מעקב שינויים (Change sets) ושמירה לקובץ (file-in / file-out).
ממנה יורשות שתי מחלקות אחיות: Class ו-Metaclass!
מחלקות בעלות שם ומשתני מחלקה
מוסיפה את המאפיינים הייחודיים למחלקות רגילות בעלות שם גלובלי (שאינם קיימים במטה-מחלקות אנונימיות!): שם המחלקה, ניהול משתני מחלקה (classVariables) ומאגרים משותפים (poolDictionaries).
2. סעיפים 18.13–18.14: חוקים 9 ו-10 – הפרדוקס הלוגי וסגירת המעגל של Metaclass
כיצד הקשר המעגלי בין Metaclass ל-Metaclass class בולם את הרגרסיה האינסופית?
עכשיו אנחנו מגיעים אל השיא האינטלקטואלי של הפרק כולו:
כל מטה-מחלקה במערכת (כמו TranslucentColor class, Color class, Object class) היא עצם חי בזיכרון. ואם היא עצם, לפי חוק 2 היא חייבת להיות מופע של מחלקה כלשהי! לאיזו מחלקה שייכות כל המטה-מחלקות?
👑 חוק 9 (סעיף 18.13): Every metaclass is an instance of Metaclass
כל המטה-מחלקות במערכת הן מופעים של מחלקה אחת מיוחדת הנקראת Metaclass!
וממי יורשת המחלקה Metaclass עצמה? מכיוון שמטה-מחלקות הן אנונימיות (חסרות שם גלובלי), Metaclass אינה צריכה את תכונת השם של Class, ולכן היא יורשת ישירות מ-ClassDescription (כאחות של Class)!
♾️ חוק 10 (סעיף 18.14): The metaclass of Metaclass is an instance of Metaclass
מכיוון ש-Metaclass היא מחלקה, לפי חוק 6 חייבת להיות לה מטה-מחלקה משלה: Metaclass class (היורשת מ-ClassDescription class).
אבל של מי מופע היא Metaclass class? בהיותה מטה-מחלקה, לפי חוק 9 היא בעצמה מופע של המחלקה Metaclass!
כאן נסגר המעגל הסופי: Metaclass היא מופע של Metaclass class, ו-Metaclass class היא מופע של Metaclass!
שילוב חיצי הירושה (רציפים) וחיצי המופעים (מקווקווים) עד למעגל הסגור של Metaclass
מיני-סימולציה 18.5: חוקר ארבע מחלקות הליבה של המודל (Behavior, ClassDescription, Class, Metaclass)
מבוך ההיררכיה של Squeak: סינון שכבות ירושה (Inherits From) מול מופעים (Instance Of)
בחר כל צומת בגרף של Squeak או סנן את שכבות החצים (כחול = ירושה superclass, ירוק = מופע class) כדי לראות איך כל צומת מחובר בשני הצירים וכיצד הכל מתכנס אל Object (בירושה) ואל המעגל של Metaclass (במופעים):
הגשר הנרטיבי: סגרנו את המעגל של Metaclass – בוא נסכם את 10 החוקים ו-9 עקרונות המודל ונפתור ביטויי בחינה מורכבים!
כעת כל עשרת החוקים של מודל העצמים ב-Squeak פרוסים לפניך בבהירות מלאה. בלשונית האחרונה והמסכמת של פרק 18 נרכז את רשימת 9 עקרונות הברזל המסכמים של המודל, נתאמן על פיצוח ביטויי השוואה מורכבים של בחינות (כמו a class superclass class == b class class superclass), ונתרגל את כל מושגי הפרק ב-12 כרטיסיות זיכרון תלת-ממדיות!
סיכום עקרונות מודל המטה-מחלקות, מנתח ביטויי בחינה וכרטיסיות זיכרון (3D Flashcards)
9 עקרונות הסיכום של מודל המחלקות ב-Smalltalk (סעיף 18.15), מעבדת פתרון ביטויי שרשור לבחינה (כגון a class superclass class == b class class superclass), ו-12 כרטיסיות זיכרון תלת-ממדיות על כל מושגי פרק 18.
מודל מנטלי ועיקרון מנחה: 10 חוקי היסוד ו-9 עקרונות המודל יוצרים מערכת עקבית, שלמה וסגורה!
יש רק אלגוריתם איתור מתודות אחד במערכת כולה: בין אם שולחים הודעה למופע רגיל ובין אם שולחים הודעה למחלקה, תמיד מתחילים במחלקה של המקבל ועולים בשרשרת ה-superclass!
בזכות ההיררכיה המקבילה (Rule 7), עבור כל מחלקה C שאינה שורש העץ מתקיים תמיד:
C superclass class == C class superclass!
הקשר ההדדי בין Metaclass ל-Metaclass class מבטיח שכל עצם במערכת הוא מופע של מחלקה ללא שום חריג וללא רגרסיה אינסופית.
סעיף 18.15: תשעת עקרונות היסוד המסכמים של מודל המחלקות והמטה-מחלקות
Class, מ-ClassDescription ומ-Behavior.
Metaclass.
Metaclass היא מחלקה, ולכן קיימת עבורה מטה-מחלקה (Metaclass class), ו-Metaclass היא המופע היחיד שלה.
Metaclass היא סוג של מחלקה (עבור מחלקות אנונימיות), ולכן יורשת ישירות מ-ClassDescription.
Metaclass class היא מטה-מחלקה ולכן היא גם עצם, ובתור שכזו היא מופע של Metaclass — זהו הקשר המעגלי במערכת!
חמשת חוקי הבסיס (1–5) לצד חמשת חוקי המטה-מחלקות (6–10)
מיני-סימולציה 18.6: מפצח ביטויי הבחינה בשרשור class ו-superclass
כרטיסיות זיכרון תלת-ממדיות (3D Flashcards) לכל 12 מושגי פרק 18
לחץ על כל כרטיסייה כדי להפוך אותה ולבחון את עצמך על כל אחד מ-12 מושגי היסוד של פרק 18:
נחשפו: 0 / 12השלמנו במלואו את פרק 18: המושג "מטה-מחלקה"!
בפרק זה סגרנו את מעגל ההפשטה והעקביות של מודל העצמים ב-Smalltalk וב-Squeak: החל מההבנה שגם מחלקה היא עצם חי בזיכרון (מופע של מטה-מחלקה אנונימית), דרך 5 רמות האבולוציה של מערכות עצמים, ועד ל-10 חוקי היסוד, איתור המתודה new ב-Behavior והמעגל הסגור של Metaclass ו-Metaclass class.
class ו-superclass, צייר לעצמך בראש (או על דף הטיוטה) את שני העמודים המקבילים: עמוד המחלקות מימין ועמוד המטה-מחלקות משמאל. זכור ש-class מזיז אותך אופקית (על חץ "מופע של"), ואילו superclass מזיז אותך אנכית למעלה (על חץ "ירושה")!