אייפל (שפת תכנות)

מתוך ויקיפדיה, האנציקלופדיה החופשית
קפיצה לניווט קפיצה לחיפוש
אייפל
Eiffel
Eiffel logo.svg
פרדיגמות תכנות מונחה-עצמים, תכנות מרובה פרדיגמות עריכת הנתון בוויקינתונים
שנה 1985, 1986 עריכת הנתון בוויקינתונים
מתכנן ברטראן מייר עריכת הנתון בוויקינתונים
מפתח ברטראן מייר עריכת הנתון בוויקינתונים
הושפעה על ידי עדה, Simula, Z notation, Simula 67 עריכת הנתון בוויקינתונים
לעריכה בוויקינתונים שמשמש מקור לחלק מהמידע בתבנית OOjs UI icon info big.svg

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

השפה באה לענות על חסרונותיהן של שפות תכנות מונחות עצמים קודמות לה. כתיבת השפה הושפעה מהשפות פסקל, Simula, Ada, Z ושימשה השראה לשפות פופולריות כמו C#‎, Java, Ruby, D, ועוד. מושגים רבים שהוצגו לראשונה על ידי אייפל, לאחר מכן מצאו את דרכם לשפות תכנות מודרניות כ־Java, C#‎ ושפות אחרות.

מאייר כתב ספר על תכנות מונחה עצמים (Object-Oriented Software Construction), בספר ניסח כללים לפרדיגמה, שלבסוף הפכו לשפה עצמה.

מאפיינים עיקריים[עריכת קוד מקור | עריכה]

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

עקרונות עיקריים[עריכת קוד מקור | עריכה]

תכנות לפי חוזה[עריכת קוד מקור | עריכה]

Postscript-viewer-shaded.png ערך מורחב – חוזה (תכנות)

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

  • תנאים לפני ביצוע הפונקציה (pre-conditions).
  • תנאים לאחר ביצוע הפונקציה (post-conditions).
  • מגבלות לגבי תוכן הפרמטרים שהפונקציה מקבלת.
  • מגבלות לגבי התוכן שהפונקציה מחזירה.
  • מגבלות לגבי תוכן החריגות שהפונקציה יכולה לזרוק.
  • תופעות לוואי של הרצת הפונקציה (לדוגמה, שימוש בלולאה לצורך השהייה).
  • נתונים על הביצועים שלה (זיכרון, זמן ריצה).
  • ביטויים קבועים לאורך התוכנית (invariant).

"Design by Contract" הוא סימן רשום של Eiffel Software, והמונח הוטמע והומצא על ידי ד"ר ברנרד מאייר, יוצר השפה. עובדה זאת מאוששת את חשיבות החוזה כמרכיב מרכזי בשפת התכנות אייפל.

דוגמה לשימוש בחוזה[עריכת קוד מקור | עריכה]

 create
   make feature {NONE} 
   -- Initialization
   make (a_day: INTEGER; a_hour: INTEGER) -- Initialize `Current' with `a_day' and `a_hour'.
 
 require 
   valid_day: 1 <= a_day and a_day <= 31
   valid_hour: 0 <= a_hour and a_hour <= 23 
 do 
   day := a_day
   hour := a_hour
 
 ensure 
   day_set: day = a_day
   hour_set: hour = a_hour
 
 end
 
feature -- Access 
   day: INTEGER -- Day of month for `Current'
   hour: INTEGER -- Hour of day for `Current'
 
 feature -- Element change 
   set_day (a_day: INTEGER) -- Set `day' to `a_day'
 
require
   valid_argument: 1 <= a_day and a_day <= 31
 do
   day := a_day
 ensure
   day_set: day = a_day
 end
 
 invariant 
   valid_day: 1 <= day and day <= 31
   valid_hour: 0 <= hour and hour <= 23
  end

עקרון פתיחות/סגירות[עריכת קוד מקור | עריכה]

Postscript-viewer-shaded.png ערך מורחב – עקרון פתיחות/סגירות

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

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

עקרון הגישה האחידה[עריכת קוד מקור | עריכה]

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

עקרון הפרדת פקודות משאילתות[עריכת קוד מקור | עריכה]

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

תאימות לשפות אחרות[עריכת קוד מקור | עריכה]

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

ניהול זיכרון[עריכת קוד מקור | עריכה]

ניהול זיכרון של תוכנית Eiffel הוא מאתגר כהשלכה מהנסיבות הבאות.

  1. תוכנית בשפת Eiffel יכולה לקרוא לפונקציות בשפת C, לכן צריך להתחשב בכך שיכולים להיות בתוכנית שני סוגי זיכרון: זיכרון ל־Eiffel וזיכרון ל־C.
  2. צריך להבחין בין אובייקטים רגילים - אובייקטים בעלי גודל קבוע שנקבע באופן סטטי (בזמן ההידור) על פי מספר תכונות האובייקט, לבין אובייקטים מיוחדים - אובייקטים בעלי גודל משתנה (מערכים, מחרוזות ועוד).
  3. לא מספיק לשחרר זיכרון רק לשם שימוש חוזר בתוכניות בשפת Eiffel, אלא אנו מעוניינים שניתן יהיה להחזיר את הזיכרון אל מערכת ההפעלה לשימוש חוזר גם באפליקציות אחרות.

מסיבות אלה, Eiffel אינה מסתפקת ב־syscall malloc()‎ (שכן malloc()‎ לא יכול להחזיר את הזיכרון אל מערכת ההפעלה), אלא יש לה מנגנון לניהול זיכרון משלה.

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

שני האלגוריתמים העיקריים לאיסוף זבל בשפת Eiffel, הם mark & sweep, ו־memory compaction. כברירת מחדל, כל יישום בשפת Eiffel כולל איסוף זבל אוטומטי. אבל בכל אופן ניתן לשלוט על מנגנון ניהול זיכרון ולכוון אותו כך שיתאים לצרכים הספציפיים של המתכנת באמצעות פונקציות ופרוצדורות השייכות למחלקה MEMORY, המאפשרות למתג את תהליך איסוף הזבל האוטומטי.

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

מבנה השפה[עריכת קוד מקור | עריכה]

משתנים פשוטים[עריכת קוד מקור | עריכה]

נקראים גם EXPANDED

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

flag: BOOLEAN

i: INTEGER

s: STRING

r: REAL

d: DOUBLE

c: CHARACTER

עצמים[עריכת קוד מקור | עריכה]

נקראים גם REFERENCE ומכילים עצמים או מערכים. לדוגמה,

i: MYoBJ

ערכי ברירת מחדל[עריכת קוד מקור | עריכה]

ערך טיפוס
1 0 INTEGER
2 0 REAL
3 0 DOUBLE
4 FALSE BOOLEAN
5 NULL CHARACTER
6 VOID REFERENCE REFERENCE

מערכים[עריכת קוד מקור | עריכה]

נקראים ARRAY. הכרזה לדוגמה,

keywords : ARRAY[STRING]
numbers: ARRAY[INTEGER]

יצירה (מערך מ-1 עד 100).

create keywords.make(1,100)

רשומה[עריכת קוד מקור | עריכה]

נקראת TUPLE, מקבילה של STRUCT או CLASS ללא פונקציות, אלא רק נתונים.

t: TUPLE [name: STRING; weight: REAL; date: DATE]

יכול להוות תאריך או רשומה מסוימת וא"צ להגדיר מחלקה

["Brigitte", 3.5, Last_night]

גישה

t.weight := t.weight + 0.5

אופרטורים[עריכת קוד מקור | עריכה]

שם סימן
1 גדול <
2 קטן >
3 שווה =
4 שונה =/
5 גדול או שווה =<
6 קטן או שווה =>
7 הקצאה =:

תנאי[עריכת קוד מקור | עריכה]

if תנאי
then גוף
else אם לא מתקיים התנאי
end סוף תנאי
if(num>10)  then

  output.putint (num)

  output.new_line

else

  output.putstring ("Error")

end

לולאה[עריכת קוד מקור | עריכה]

from תנאי התחלה
until תנאי עצירה
loop/end גוף הלולאה
from I:=0  until I>10 loop

  RESULT := RESULT + 1

end

פונקציות ופרוצדורות[עריכת קוד מקור | עריכה]

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

פונצקיות - עושות חישובים ומחזירות ערך, אבל לא יכולות לבצע שינויים במשתנים.

פרוצדורות - עושות שינויים במשתנים, אבל לא מחזירות ערך.

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

מחלקות[עריכת קוד מקור | עריכה]

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

note - תיעוד המחלקה.
class - שם המחלקה.
inherit - ירושה (אפשרות).
create - פונקציות מאתחלות.
local - משתני מחלקה.
do...end - גוף המחלקה.
note
description : "targil5 application root class"
date : "$Date$"
revision : "$Revision$"

class
  MY_CLASS

  inherit
      OTHER_CLASS

  create 
      Function1

  feature {NONE} my_function (variable_name: SOME_TYPE)-- Initialization
               -- Run application.
    local
       cmp : CLASS1
    do
      cmp.make
      ....
      ....
   end

end

מנגנון לטיפול בחריגות[עריכת קוד מקור | עריכה]

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

 connect_to_server (server: SOCKET) -- Connect to a server or give up after 10 attempts. 
 require 
    None_Null: server /= Void and then server.address /= Void 
 local 
   attempts: INTEGER 
 do 
   server.connect 
 ensure 
   connected: server.is_connected 
 rescue 
   if attempts < 10 then 
      attempts := attempts + 1 
 retry 
   end 
 end

אפשרויות שונות בשפה[עריכת קוד מקור | עריכה]

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

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

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

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

חוויית מתכנת[עריכת קוד מקור | עריכה]

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

תרגום לשפת מכונה[עריכת קוד מקור | עריכה]

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

תחביר[עריכת קוד מקור | עריכה]

  • המהדר אינו מבחין בין אותיות גדולות וקטנות, אבל מקובל להשתמש בסגנון כתיבה קבוע לשפה כדי לשמור על הקוד קריא לכל מי שמכיר את השפה. נוהגים לכתוב שמות של מחלקות באותיות גדולות, שמות פונקציות באותיות קטנות, שמות משתנים עם אות ראשונה גדולה והשאר קטנות, צירוף מילים כותבים תמיד עם קו תחתון בין המילים.
  • ב־Eiffel אין חובה להפריד בין פקודות באמצעות נקודה פסיק ; בסוף שורה.
  • יש להבדיל בין אופרטור הבדיקה = המחזיר ערך בוליאני (אמת או שקר) כתוצאה של הערכת תנאי, לבין אופרטור ההקצאה =:.
  • הסימון -- (מינוס כפול) פותח הערה באותה שורה.
  • פונקציות יצירה הן סוג של פונקציות בונות (אלא שקוראים להן אקטיבית) המשמשות לאתחול והגדרות המחלקה. מגדירים פונקציות כאלה בחלק CREATE במחלקה, אך ממשים אותן בחלק FEATURS כמו כל שאר הפונקציות.
  • החלק IS בהגדרת הפונקציה מכיל הערה הממצה את מהות המחלקה ("מטפורה").
  • פונקציות נקראות באופן דומה למשתנים, ולכן המתכנת לא צריך לדעת את אופן המימוש.
  • השפה מבנית, נכתבת בבלוקים לכל קבוצת קוד באופן דומה לשפת התכנות עדה.
  • כאשר פונקציה מחזירה פרמטר, משתמשים בפרמטר המובנה בשפה RESULT לצורך החזרה. (בדומה ל-PL/SQL)
  • אין נגישות למערך אחרי הגדרתו. לכן מאתחלים עצמים כגון מערכים, וקבצים בעזרת CREATE.
  • בטיפוס מסוג עצם בברירת מחדל הקצאה מחזירה מצביע לעצם, ולכן אם הוא נמחק קיים מצביע מתנדנד ולכן רצוי להשתמש ב־CLONE או COPY.

יישומי השפה[עריכת קוד מקור | עריכה]

Eiffel רצה על Windows, Linux, Unix, OpenBSD, FreeBSD, macOS, ו־OpenVMS.

  • EiffelStudio - סביבת הפיתוח והמהדר העיקריים של השפה, פותחו ועוצבו על ידי מתכנני השפה. הסביבה חינמית אך ורק לפיתוח תוכנה חופשית.[1]
  • SmartEiffel - מהדר חינמי קוד פתוח מתאים לכל מעבד ANSI C.[2]
  • Visual Eiffel - סביבת פיתוח מסחרית IDE כולל GUI עובד על Win32, Linux.[3]

הערות שוליים[עריכת קוד מקור | עריכה]

  1. ^ EiffelStudio, www.eiffel.org, ‏2020-05-22
  2. ^ SmartEiffel, the GNU Eiffel Compiler, Tools and Libraries, smarteiffel.loria.fr
  3. ^ Visual-Eiffel, visual-eiffel.com