יש באגים מטומטמים

זהירות – פוסט מחשביסטי.

בואו נראה אתכם. מה לא בסדר בקטע הקוד הבא (מתוך rsyncrypto):


    static autofd autofd::dup( int filedes )
    {
        return autofd( dup(filedes) );
    }

בגלל הבאג הזה התוכנה לא אפשרה להצפין כאשר רשימת הקבצים להצפנה מתקבלת מ-stdin. תשובה בהמשך המאמר.

תשובה:
הוא קורא לעצמו ללא תנאי סיום. הקוד הזה היה צריך להיות:


    static autofd autofd::dup( int filedes )
    {
        return autofd( ::dup(filedes) );
    }

שני תווים, וכל ההבדל שבעולם.

שחר

מאת

שחר שמש

מייסד–שותף וחבר ועד בתנועה לזכויות דיגיטליות מייסד שותף בעמותת „המקור”. פעיל קוד פתוח. מפתח שפת התכנות Practical

27 תגובות בנושא “יש באגים מטומטמים”

  1. אחד היתרונות של IDEs – אפשר לראות לפי צביעה של הקריאה לפונקציה שאתה קורא לפונקציה של המחלקה 🙂
    במה אתה משתמש כדי לפתח?

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

    שחר

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

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

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

  5. סתם למי שסקרן, וכמוני לא ידע קודם מה הקידומת של PAAMAYIM_NEQUDOTAIM עושה, זה קורא לפונקציה dup מהמשתנים הגלובליים, כלומר יש שני פונקציות dup, האחת היא שיטה (מתודה) של האובייקט autofd, והשניה היא גלובאלית. הקידומת :: גורמת למהדר לבחור דווקא את הפונקציה הגלובאלית.

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

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

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

    אז נכון שאפשר להתרגל לתכנת בצורה יותר “יפה” גם ב ++C, אבל אתה לא תעשה את זה במיוחד לפרוייקט, ואתה לא יכול לכפות את עצמך על אחרים… ולכן השפות כדוגמת ++C תמיד יגרמו לבעיות בגלל התחביר של השפה, אלא אם השפה תכתיב צורת תכנות טובה יותר (בהצלחה) …

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

    שחר

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

    אתה אכן מתנהג כמו טרול.

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

    שחר

  9. לא התכוונתי למונח מphp, פשוט, לא ידעתי איך לתאר את השם של התוים האלה בעברית, אז שאלתי את השם שלהם מphp.
    אתה צודק. זה לא סוכר סינטקטי, טעות שלי. אולי זה סוכר סינטקטי בהקשר של, אם לא תשתמש בשמות משתנים זהים בסקופ הגלובאלי, או שתקדים global_ לכל פונקציה כזו לא יהיו בעיות כאלה.
    סתם סקרנות, למה לא לדחוף את dup המקורית לתוך namespace משלה, מה שהיה מונע בלבול?
    הכוונה היא שקשה (לי לפחות) לחפש בגוגל, מה תוים מסויימים בהקשר מסויים עושים. חיפוש של “c++ ::” לא נתן לי שום דבר, ואין לי רעיון חכם יותר לחיפוש.

  10. להגיד את האמת, לא עקבתי אחרי הלוגיקה.
    א. אתה לא יכול להחליט לאיזה namespace ישתייכו פונקציות מערכת, או לשנות את שמם.
    ב. האופרטור נקרא “scope resolution operator”. אתה מוזמן לחפש אותו תחת השם הזה.

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

    שחר

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

    עידו

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

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

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

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

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

    ועל כן:
    Java – לא בא בחשבון (דרישה כבידה על לינוקס ועל חלונות)
    ‎.NET – לא בא בחשבון (תחשוב התקנה על לינוקס)
    Perl, Python, Ruby – לא בא בחשבון (תחשוב התקנה על חלונות)

    מה שמשאיר, פחות או יותר, רק תכנות בשפה שמתקמפלת לקוד Native. בהקשר הזה, C++‎ עדיף פה בהרבה על, לדוגמא, C, ואני יודע את זה בוודאות כי הפרוייקט התחיל את דרכו כפרוייקט C, וכאשר היה צריך להכניס Multi platform לא היתה ברירה אלא להפוך את הפרוייקט למהפיכה רצינית של ספגטי ושל ‎#ifdef, או להפוך אותו ל-C++‎.

    שחר

  14. אני לא בטוח. זה מאוד תלוי בנסיבות.

    תראה, ברור שבמקרה הספציפי, לא הייתי עושה פונקציית מעטפת לפונקציית מערכת (כלומר method שכל מה שהוא עושה זה לקרוא לפונקציה הגלובלית ואז ל-constructor) אם לא היתה פונקצית מערכת כזו.

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

    למשל, אני לא רואה מה היתרון של מחלקת singleton שכל תפקידה הוא להגדיר פונקציות שלהן אני קורא על פני לשים את אותן הפונקציות בתוך ה-global namespace. כמובן שאני אדאג שלא יהיו התנגשויות שמות, אבל מאוד קשה לי לראות את עצמי מתעקש על מחלקות במקום שבו הן לא הגיוניות.

    שחר

  15. ההגיון הוא לחלק אותן בצורה הגיונית. גם אם הן פונקציות שמוכלות בעצמן, יותר יפה והגיוני לקרוא ל
    math::sin
    distance::to_miles
    file::is_open
    מאשר לדחוף את כולם לאותו namespace. מה גם, שאז אתה יכול לכתוב using namespace math ואז לא תהיה לך בעיה עם התנגשות של שמות בכלל.

    אבל אולי תתן לי דוגמא איפה זה לא הגיוני ומעצבן לדחוף פונקציות גלובליות לnamespace כלשהו?

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

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

    אגב, אולי תתקין תוסף שמודיע אם יש תגובה לתגובה שלי?

  17. תחליף את “ואז” ל”וכן”. וכן לא תהיה בעיה של התנגשות שמות. מה גם שאתה יכול לכתוב using namespace ולחסוך הקלדה חוזרת של math:: וגם יהיה ברור יותר מה הפונקציה עושה (היא משתמשת במתמטיקה וסטטיסטיקה)

  18. ל-א.ל.

    יותר יפה והגיוני לקרוא ל

    יותר יפה – אולי
    יותר הגיוני – ממש ממש לא.

    בכלל, אני נגד הפעלה פנאטית של מדיניות תכנות ללא הסתכלות על הפרטים. אם אתה תנסה לעשות את הסידורים שאתה מציע פה, אתה מהר מאוד תגלה שיש לך פונקציות שאתה צריך בכמה namespaces, ואז אתה בבעיה (למשל – to_miles סביר להניח שתצטרך גם ב- units).

    ואז מה תעשה? תתחיל לעשות הגדרות כפולות? תשתמש ב-proxy functions? תתחיל לשנות את הקוד?

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

    בתור הערת אגב – מרחבי שמות הן טכניקה שמשמשת, בראש ובראשונה, את זה שספריות לא ידרכו על פונקציות שהמשתמש הגדיר. C++‎ בעצם אמר “אין לנו זכות להגיד למתכנת שהמחלקה iostream היא מחוץ לתחום, אז את המחלקה שלנו נשים בתוך מרחב השמות std”.

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

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

    שחר

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

סגור לתגובות.

Bear