لماذا نفرق بين الطرق التي تُرجع قيمة والطرق التي لا تُرجعها؟

StackOverflow https://stackoverflow.com/questions/1018281

سؤال

لماذا تفرق بعض اللغات بين الأساليب التي تُرجع قيمة والأساليب التي لا تُرجعها؟

أي.في PL/SQL الخاص بـ Oracle، حيث يكون الاختلاف الأساسي بين الوظيفة والإجراء هو أن الوظيفة يجب أن تُرجع قيمة، ويجب ألا يُرجع الإجراء ذلك.

وبالمثل بالنسبة للغات التي لا تفعل ذلك، لماذا لا؟


يحرر:لقد وجدت سؤالاً ذا صلة قد يثير اهتمام الأشخاص الذين يقرؤون هذا السؤال:

هل كانت مفيدة؟

المحلول

لأنه في المفاهيم الأصلية لنظرية وممارسة علوم الكمبيوتر، لم يكن للوظائف والمسارات الفرعية أي علاقة تقريبًا ببعضهما البعض.

عادةً ما يُنسب الفضل إلى لغة فورتران باعتبارها اللغة الأولى التي طبقت كلا الأمرين وأظهرت الفروق.(كان لـ LISP المبكر دور معاكس إلى حد ما في هذا أيضًا، ولكن كان له تأثير ضئيل خارج الأوساط الأكاديمية).

اتباعًا لتقاليد الرياضيات (التي كان علوم الكمبيوتر لا يزال جزءًا منها في الستينيات) كان يُنظر إلى الوظائف فقط على أنها تغليف للحسابات الرياضية ذات المعلمات التي تهدف فقط إلى إرجاع قيمة إلى تعبير أكبر.إن إمكانية تسميتها "عارية" (F = AZIMUTH(SECONDS)) كانت مجرد حالة استخدام تافهة.

من ناحية أخرى، كان يُنظر إلى الإجراءات الفرعية على أنها طريقة لتسمية مجموعة من البيانات التي تهدف إلى إحداث بعض التأثير.كانت المعلمات بمثابة دفعة كبيرة لسهولة استخدامها، وكان السبب الوحيد الذي سمح لها بإرجاع قيم المعلمات المعدلة هو تمكينها من الإبلاغ عن حالتها دون الحاجة إلى الاعتماد على المتغيرات العامة.

لذلك، لم يكن لديهم حقًا أي اتصال مفاهيمي، بخلاف التغليف والمعلمات.

السؤال الحقيقي هو:"كيف أصبح الكثير من المطورين ينظرون إليهم على أنهم نفس الشيء؟"

والجواب على ذلك هو ج.

عندما صممت K+R في الأصل لغة نوع مجمع الماكرو عالية المستوى الخاصة بها لـ PDP-11 (ربما بدأت في PDP-8؟)، لم يكن لديهم أي أوهام حول استقلال الأجهزة.تقريبًا كل ميزة "فريدة" للغة كانت انعكاسًا للغة وبنية آلة PDP (انظر i++ و --i).كان أحد هذه الأمور هو إدراك أنه يمكن (وكان يتم دائمًا) تنفيذ الوظائف والإجراءات الفرعية بشكل مماثل في PDP باستثناء أن المتصل تجاهل فقط القيمة المرجعة (في R0 [، R1]) للإجراءات الفرعية.

وهكذا ولد مؤشر الفراغ، وبعد أن استحوذت لغة C على عالم البرمجة بأكمله، كان الفهم الخاطئ بأن أداة تنفيذ HW/OS هذه (على الرغم من صحتها في كل منصة لاحقة تقريبًا) كان هو نفس دلالات اللغة.

نصائح أخرى

في بيئة نقية أو ذات تأثير، يوجد عالم من الاختلاف، لأنه من الواضح أن الأساليب التي "لا تُرجع أي شيء" تكون مفيدة فقط لآثارها الجانبية.

هذا مشابه للتمييز بين التعبيرات والعبارات، والذي يمكن أن يفسد اللغة ويزيل فئة من البرامج الخاطئة عادةً (وهذا بالطبع هو السبب وراء عدم قيام لغة C بذلك؛)).

ولإعطاء مثال صغير، عندما تميز بوضوح بين التعبيرات والعبارات، if(x = 3), ، في مقابل if(x == 3) غير صحيح من الناحية النحوية (لاستخدام عبارة حيث كان من المتوقع وجود تعبير) وليس مجرد خطأ في النوع (لاستخدام عدد صحيح حيث كان من المتوقع وجود تعبير منطقي).وهذا له فائدة الرفض أيضًا if(x = true) وهو ما قد تسمح به القاعدة القائمة على النوع في سياق تكون فيه التعيينات عبارة عن تعبيرات لها قيمة معاملها الصحيح.

في اللغة التي تغلف التأثيرات بالأحاديات، يصبح التمييز المهم هو بين:

  • الوظائف التي تعود () وهي وظائف خالصة ويمكنها إرجاع قيمة فارغة واحدة فقط عديمة الفائدة تسمى () أو تتباعد
  • الوظائف التي تعود IO () (أو وحدة في موناد أخرى) وهي وظائف ليس لها "نتيجة" باستثناء التأثيرات في موناد الإدخال والإخراج (أو أيًا كان)

إسمح لي بالإجابة على سؤال عمره عامين، وخاصة مع شيء فريد من نوعه في لغتي فيليكس http://felix-lang.org ولكن هنا يذهب على أي حال :)

في Felix، تختلف الوظائف والإجراءات بشكل أساسي، ولا يقتصر الأمر على أن الإجراءات لها آثار جانبية ويتم استدعاؤها في البيانات، في حين أن الوظائف ليس لها آثار جانبية وتستخدم في التعبيرات (لأن Felix لديه أيضًا مولدات وهي وظائف ذات آثار جانبية ..:)

لا، يختلف نموذج التنفيذ اختلافًا جوهريًا، لأسباب تتعلق بالأداء في المقام الأول، ولكن ليس تمامًا.النموذج هو:

  • تضع الوظائف عنوان الإرجاع الخاص بها على مكدس الجهاز، وقيمة الإرجاع أيضًا.
  • تستخدم الإجراءات قائمة مرتبطة في الكومة.الكود الإجرائي مسطح ولا يستخدم مكدس الآلة.

وهذا عادة ما يكون غير فعال، فلماذا تفعل ذلك؟الجواب هو:من المحتمل أن تكون جميع إجراءات فيليكس إجراءات مشتركة (ألياف).يمكنهم تحويل التحكم إلى إجراء آخر عن طريق الوصول إلى القناة.وهذا يؤدي إلى تبادل السيطرة.

  • لأسباب تتعلق بالأداء، لا يعد نسخ مكدس الجهاز عند تبادل التحكم خيارًا.
  • لأسباب تتعلق بإدارة الذاكرة، لا يعد تبديل مؤشرات المكدس خيارًا أيضًا.

يقوم نظام التشغيل عادة بتبديل مؤشرات المكدس للخيوط، وهو أمر سريع إلى حد معقول، ولكن به مشكلة أساسية في أجهزة العناوين الخطية:عليك إما أن تحدد الحد الأقصى لحجم المكدس بقيمة صغيرة جدًا، أو أن تحدد عدد الخيوط بقيمة صغيرة جدًا.على جهاز 32 بت، لا توجد مساحة عنوان كافية حتى للتفكير في هذا الحل.على جهاز 64 بت، يتمتع تبديل المكدس بإمكانيات أكبر، ولكن بالطبع طلبات المستخدم تنمو دائمًا لتتجاوز الأجهزة بعد 3 أيام من إصدارها.:)

يقوم Felix فقط بتبديل مؤشر واحد إلى الأكوام المستندة إلى الكومة، لذلك تكون مفاتيح تبديل السياق سريعة للغاية ولا يتم إهدار سوى مساحة قليلة جدًا من العنوان. بالطبع التكلفة هي تخصيصات الكومة على استدعاءات الإجراء.

في المترجم، يتم تحسين الكثير من بنية النموذج النظري بعيدًا على أساس "كما لو"، لذلك يمكن أن يكون الأداء الفعلي والتنفيذ مختلفًا تمامًا عن النموذج النظري، بشرط أن يتمكن المترجم من إثبات أنه لا يمكنك معرفة ذلك الاختلاف ..بخلاف حرمانك من فرصة صنع فنجان من القهوة مع أوقات الفراغ :)

إذن، لديك هنا إجابة مختلفة عن سبب التعامل مع الوظائف والإجراءات بشكل مختلف.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top