הסיבה שאנשים לא אהבו פרל

02/03/2017

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

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

1. למה זה לא עובד?

קחו את הקוד הבא בפרל:

use strict;
use warnings;
use autodie;

my $i = 0;
open my $f, '>>', 'my.log';

print {$f} "--- perl code\n";

while() {
  print ${f} "I'm still alive $i\n";
  $i++;
  sleep 2;
}

התוכנית פותחת קובץ בשם my.log לכתיבה ומוסיפה לקובץ שורת כותרת ולאחר מכן רושמת מספרים לקובץ בלולאה אין סופית. כמובן שאין דרך לצאת מהתוכנית מלבד Ctrl+C. הבעיה שכשתפעילו את התוכנית ואחרי כמה שניות תלחצו Ctrl+C תגלו שהקובץ נשאר ריק.

2. מה קרה שם

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

הבעיה במקרה שלנו שאף אחד מהדברים לא קורה. לחיצה על Ctrl+C שולחת סיגנל מסוג SIGINT לתוכנית וזו נסגרת לפני שמספיקה לסגור את הקובץ ולכתוב את המידע לדיסק.

פתרון אפשרי אחד הוא לתפוס את הסיגנל ולסגור את הקובץ, כלומר להוסיף לתוכנית את השורות:

local $SIG{INT} = sub {
  close $f;
  exit 0;
};

ואני חושב שכאן בדיוק ההיגיון של פרל נשבר, כי בשביל לכתוב תוכנית מאוד פשוטה שכותבת לקובץ פתאום צריך להבין מה זה סיגנל, מה זה Hash, מהו ה Hash הגלובלי %SIG, מהי פונקציה אנונימית ולכן גם מהו Reference לפונקציה ובסוף מה זה local ומה ההבדל בינו לבין my.

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

פתרון אפשרי אחר הוא להגדיר autoflush על הקובץ באמצעות השורה:

$f->autoflush;

זה לא רע אבל בשביל לגרום לו לעבוד צריך להוסיף לתחילת התוכנית את:

use IO::Handle;

מה שאומר שחייבים להבין מה זה use ומהם מודולים בשביל פעולה פשוטה של כתיבה לקובץ.

3. נו בטח בכל שפה זה ככה לא?

לא ממש. פייתון תסגור בשבילכם לבד את הקובץ בעקבות Ctrl+C ומספיק לכתוב את הקוד הבא כדי לקבל את אותה התוצאה:

import time

i = 0
with open('my.log', 'a') as f:
    print >>f, "--- Python code"
    while True:
        print >>f, "I'm still alive...%d\n" % i
        i += 1
        time.sleep(2)

ואותו הדבר רובי עם הגירסא שלה לאותה התוכנית:

i = 0

open('my.log', 'a') do |f|
  f.puts "--- ruby code"
  while(1)
    f.puts "I'm still alive...#{i}"
    i += 1
    sleep 2
  end
end

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

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

לקח שני זה ששינויים קורים פתאום. פרל היתה במשך שנים ה Go To Language של System Administrators בסביבת יוניקס. היום כמעט כולם בתחום הזה קוראים לעצמם Devops ומעדיפים פייתון. היתרון כאן שאם אתם לא אוהבים טכנולוגיה מסוימת בדרך כלל מספיק לחכות 3-4 שנים כדי שתבוא אחרת במקומה.