על ליגטורות, שפות תכנות וסמיוטיקה טיפוגרפית

פורסם ב:

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

הפונט המדובר נקרא FiraCode. הוא הרחבה לפונט מוקדם יותר, Fira Mono, ונועד לקריאת וכתיבת קוד בסביבות פיתוח. היחוד שלו הוא בתמיכה בליגטורות – “משלבי אותיות”, כך אומרת לי ויקיפדיה – לסימנים מקובלים בעולם התכנות.

התמונה מראה צירופי אותיות שונים והליגטורות שלהם ביחד

ליגטורות, קורבן ההצלחה של עצמן

ראשית, מה זה ליגטורות? ליגטורה היא שילוב טיפוגרפי של שתי אותיות סמוכות. למשל, הצירוף AE בכתב הלטיני ניתן לכתיבה כליגטורה, Æ, וכך גם ה-ß הגרמני, שניתן לפרק לאותיות ss (או sz).

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

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

טיפוגרפיה יצירתית בעולם מוגבל

ועכשיו נחזור לעולם התכנות. רוב שפות התכנות שבשימוש נפוץ בימינו מורכבות ברובן משילוב של פקודות המבוססות על הכתיב הלטיני (if, while, def, class), יחד עם שימוש יצירתי בסימני פיסוק. למה סימני פיסוק? כי שפות תכנות רוצות להביע הרבה רעיונות שהכתיב הלטיני לאו דווקא מאד יעיל בהן, כמו יחסים מתמטיים (שווה, גדול מ-,), פעולות על מידע (השמה למשתנה, חיבור טקסט) או סתם מידע נוסף שהמלל עצמו לא מעביר (סימון חלק מהקוד כהערה שאין לבצע). חלק מהפעולות הללו נראות אותו דבר ברוב שפות התכנות (>= לסימון שווה-או-גדול-מ-, למשל), וחלקם ספציפיים לשפות ספציפיות או למשפחות של שפות דומות (== לפעולת השוואה, => לסימון פונקציית lambda. לא משנה מה זה כרגע). image

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

זו הסיבה שהרבה מהפקודות המקובלות היו ניסיון “לצייר”, באמצעות תווי מקלדת רגילים, סימנים מתמטיים מורכבים יותר. למשל הסימון לבדיקת אי-שוויון בשפות רבות הוא != (סימן קריאה+שווה), שמנסה לדמות לסימן אי השוויון המתמטי ≠ (שווה עם קו עליו). וסימן החץ שמשמש בתחום במדמ”ח שנקרא lambda calculus שמייצג פונקציה שפועלת על קלט (כשהחץ מייצג את המעבר מהקלט לפלט) הפך בשפות רבות להיות => (שווה+גדול מ-) או –> (מקף+גדול מ-), שנראים קצת כמו חץ, במגבלות הז’אנר. הם כולם נולדו כפשרה – הרצון להביע רעיונות מורכבים באמצעות סימנים מוסכמים, אבל רק כאלה שאפשר להקליד בקלות.

ליגטורה כפונדמנטליזם – חזרה למקורות

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

person => person.Name

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

image

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

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

עם הסימן של החץ שהבאתי למעלה, או עם ה-Bind בהודעה שקישרתי, יש לליגטורות יתרון ברור, והוא שהסימנים הללו הם יחסית חדשים בנוף המיינסטרים של שפות התכנות – הרבה מהם נכנסו לאורך 10-15 השנים האחרונות ((נכנסו למיינסטרים, כן. בבקשה אל תתחילו לאזכר כאן שפות תכנות שהשתמשו ב-bind ו-lambda עוד במאה ה-18. הן קיימות, כן, אני יודע. אבל לא בהיקף של שפות כמו C++ ו-Java בשנות ה-90 וה-2000)) עם שפות כמו scala ו-haskell ועדכונים לשפות ותיקות כמו C# ו-javascript, ולכן המשמעות שלהן הרבה פחות צרובה במוח של רוב המתכנתים. רוב המתכנתים שאני מכיר יצטרכו לבלות שניה או שתיים בלהבין מה המשמעות של >>=, בעוד הליגטורה bindligature (למי שמכיר את פעולת ה-bind) תהיה ברורה הרבה יותר.

אבל חוץ מהחסרון הזה, שאולי ליגטורות באות לפתור בעיה שלא באמת קיימת, בעיה שהיתה פותרת את עצמה עם הזמן והנסיון, יש כאן עוד בעיה, והיא שרוב שפות התכנות מאד משתדלות להיות פשוט טקסט, לא פחות ולא יותר. שאם אני אקרא את אותו הקוד גם מדף מודפס, אני אוכל להבין אותן בדיוק כמו אם אקרא אותו על מסך המחשב. What you see is what you get – אם אני רואה תו מסוים בקוד, זה התו שהמחשב גם רואה, ומבצע את הפעולות על פיו. אבל כאן נוצרת לנו שכבת תרגום בין מה שהמחשב רואה (!=) לבין מה שאני רואה (≠). האם זה יפריע לאנשים ללמוד את התחביר האמיתי של השפה, לא זה שמוסתר מאחורי הסימנים היפים? האם זה יוביל לבאגים שנובעים מכך שאני, המתכנת, לא באמת קורא את אותו קוד שהמחשב מבצע? אולי. אני לא יודע. אני בינתיים אשאר עם האמביוולנטיות שלי.


פורסם ב:

by

Comments

4 תגובות על “על ליגטורות, שפות תכנות וסמיוטיקה טיפוגרפית”

  1. תמונת פרופיל של יובל
    יובל

    שתי הערות:
    1. לא יודע לגבי שם החברה, כנראה סתם חשבו שזה מושג מגניב (כמו שמה הקשר בין האי Java, או הקפה שמגיע לשם, לשפת התכנות?). בכל מקרה ליגטורה זה גם מה שמחבר בין העלה לגוף בקלרינט וסקסופון.
    2. נזכרתי בשפת התכנות APL שהיו בה הרבה סימנים ייחודיים ברמה שפותחה מקלדת מיוחדת עבורה…

    1. תמונת פרופיל של אבנר שחר קשתן

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

  2. תמונת פרופיל של Gabis
    Gabis

    אחלה פוסט!

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

    אני מפספס משהו?

    1. תמונת פרופיל של אבנר שחר קשתן

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