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

לא ניתן לעשות שימוש מסחרי בחומר זה ללא רשות בכתב מן המחברים או מערכת כתב העת

העברת פרמטרים

פרופ' מוטי בן ארי

המחלקה להוראת המדעים, מכון ויצמן למדע, רחובות

moti.ben-ari@weizmann.ac.il

 
תקציר

 

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

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

 

העברת פרמטרים בפסקל

בפסקל, ניתן להעביר פרמטרים לפרוצדורה או לפונקציה, בשני אופנים: לפי ערך (by value) ולפי כתובת (by reference). הראשונה היא ברירת המחדל, והשניה מצויינת על ידי התוספת של מילת המפתח VAR לפני הפרמטר הפורמלי, ומכאן המונח פרמטר של משתנה (variable parameter).

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

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

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

הואיל ואיננו רוצים ללמד את רעיון המצביעים בשלב מוקדם מדי, הרי שיש להסביר את העקרון של פרמטר של משתנה תוך שימוש בסמנטיקה של "עותק נכנס / עותק יוצא" (copy-in / copy-out), או תוך שימוש במתן שם חדש לפרמטרים האקטואליים. אלא שאף אחד מאלה אינו מדויק מבחינה טכנית בפסקל.

 

העברת פרמטרים בשפת Ada

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

לדוגמה, נניח שהוגדרו הפרוצדורות הבאות (בשפת  Ada):

procedure Quadratic ( A, B, C : in Float; Root1, Root2 : out Float);

procedure Sort (V : in out Vector);

 

פרמטרים מסוג  in משמשים לקריאה בלבד, פרמטרים מסוג out משמשים לכתיבה בלבד, ופרמטרים מסוג  out in  משמשים גם לקריאה וגם לכתיבה.

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

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

פרמטרים סקלריים, כמו מספרים ומצביעים, ממומשים על-ידי העתקה: העתקה פנימה (copy-in) בכניסה לפרוצדורה עבור  inו- in out , והעתקה החוצה (copy-out) בסיום הפרוצדורה עבור out ו- in out.

הקומפיילר יכול לבחור בין העתקה לבין מימוש על-ידי כתובת (reference) עבור מערכים ורשומות. ניתן אפילו לכתוב תכניות חכמות שמחשבות תוצאות שונות לאחר הידור במהדרים שונים, אך תכניות כאלה אינן ניידות (portable).

 

העברת פרמטרים בשפת C ובשפות אחרות

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

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

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

 

כיצד עדיף לנהוג בפסקל?

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

לדוגמה, ההגדרה של פרוצדורה לחיפוש תהיה:

procedure Search ( V: Vector; Key: Float; var Found: Integer);

 

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

המלצה זו, לבחור את אופן העברת הפרמטרים לפי השימוש המתוכנן, נכללת בקורס "יסודות מדעי המחשב I ו- II" (מיועד לכתות י'-י"א), שפותח במכון ויצמן.

 

יעילות

פעמים רבות שומעים שהסיבה השכיחה ביותר לשגיאות (bugs) היא כתיבה מתוחכמת במטרה ליצור תכניות יעילות.

הנסיון המעשי של הנדסת התוכנה המודרנית מכתיב ש:

1.      יעילות צריכה לבוא רק בעדיפות שניה, אחרי נכונות.

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

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

 

לפי הדיעה המקובלת, מערכים צריכים להיות מועברים כפרמטרים של משתנה (var) ולא כפרמטרים של ערך, כיון שמשתני כתובת הם "יעילים יותר" כי אין צורך בהעתקה של המערך כולו.

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

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

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

לפיכך, נראה שהסיבה התקפה היחידה הנוגעת ליעילות בקשר להעברת פרמטרים של משתנה, היא לחסוך זכרון על המחסנית. זה כמובן חשוב ביותר במחשב PC, שמגביל את המחסנית ל- 64K. אלא שבדרך כלל, עומק הקינון של הפרוצדורות הוא קטן מאוד (אפילו בפרוצדורות רקורסיביות), כיון שהן כתובות לצורך מימוש אלגוריתמים שיסרקו מבני נתונים מעומק  log n.

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

 

מסקנות

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

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

שימוש זהיר  באופן העברת הפרמטרים יסייע לתלמידים לאפיין במדויק את הממשקים של הפרוצדורות ויהווה בסיס מוצק ללימודי המשך של מבני נתונים מופשטים (abstract  data  types),   ותכנות  מונחה  עצמים (object-oriented programming).

 

אתר הבטים

תוכן לפי נושאים

תוכן לפי גליונות

חזרה לתחילת העמוד