دلالات التحميل الزائد العودية في Scala REPL - لغات JVM

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

سؤال

باستخدام سطر أوامر Scala REPL:

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

يعطي

error: type mismatch;
found: Int(2)
required: String

يبدو أنه لا يمكنك تحديد الأساليب العودية المحملة بشكل زائد في REPL.اعتقدت أن هذا كان خطأً في Scala REPL وقمت بتقديمه، ولكن تم إغلاقه على الفور تقريبًا بـ "wontfix:لا أرى أي طريقة يمكن من خلالها دعم ذلك بالنظر إلى دلالات المترجم، لأنه يجب تجميع هاتين الطريقتين معًا." وأوصى بوضع الأساليب في كائن مرفق.

هل هناك تطبيق لغة JVM أو خبير Scala يمكنه شرح السبب؟أستطيع أن أرى أنه سيكون هناك مشكلة إذا اتصلت الطرق ببعضها البعض على سبيل المثال، ولكن في هذه الحالة؟

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

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

المحلول

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

def test(x: Int) = x + x

وبعد ذلك بقليل، لنفترض أنني أقوم بتشغيل ملف مختلف تجربة وأقوم بإنشاء طريقة أخرى اسمها test, ، لا علاقة لها بالأول:

def test(ls: List[Int]) = (0 /: ls) { _ + _ }

هذا ليس سيناريو غير واقعي تماما.في الواقع، هذه هي الطريقة التي يستخدم بها معظم الناس المترجم الفوري، وغالبًا دون أن يدركوا ذلك.إذا قرر المترجم بشكل تعسفي الاحتفاظ بالنسختين test في النطاق، قد يؤدي ذلك إلى اختلافات دلالية مربكة في استخدام الاختبار.على سبيل المثال، قد نقوم بإجراء مكالمة إلى test, ، تمرير بطريق الخطأ Int بدلا من List[Int] (ليس الحادث الأكثر احتمالا في العالم):

test(1 :: Nil)  // => 1
test(2)         // => 4  (expecting 2)

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

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

نصائح أخرى

% scala28
Welcome to Scala version 2.8.0.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_20).
Type in expressions to have them evaluated.
Type :help for more information.

scala> def foo(x: Int): Unit = () ; def foo(x: String): Unit = { println(foo(2)) } 
foo: (x: String)Unit <and> (x: Int)Unit
foo: (x: String)Unit <and> (x: Int)Unit

scala> foo(5)

scala> foo("abc")
()

سيقبل REPL إذا قمت بنسخ كلا السطرين ولصقهما في نفس الوقت.

كما هو مبين من قبل ارتجالية الإجابة، فمن الممكن أن الزائد. دانيال التعليق على قرار التصميم صحيح، ولكن أعتقد أنه غير مكتمل ومضلل بعض الشيء.لا يوجد محظور من الأحمال الزائدة (لأنها ممكنة)، ولكن ليس من السهل تحقيقها.

قرارات التصميم التي تؤدي إلى ذلك هي:

  1. يجب أن تكون جميع التعاريف السابقة متاحة.
  2. يتم تجميع التعليمات البرمجية التي تم إدخالها حديثًا فقط، بدلاً من إعادة ترجمة كل ما تم إدخاله في كل مرة.
  3. يجب أن يكون من الممكن إعادة تعريف التعريفات (كما ذكر دانيال).
  4. يجب أن يكون من الممكن تعريف أعضاء مثل vals وdefs، وليس فقط الفئات والكائنات.

المشكلة هي...كيفية تحقيق كل هذه الأهداف؟كيف يمكننا معالجة المثال الخاص بك؟

def foo(x: Int): Unit = {}
def foo(x: String): Unit = {println(foo(2))}

بدءًا من البند الرابع، أ val أو def لا يمكن تعريفه إلا داخل ملف class, trait, object أو package object.لذلك، يضع REPL التعريفات داخل الكائنات، مثل هذا (وليس التمثيل الفعلي!)

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: Int): Unit = {}
    }
    // val res1 would be here somewhere if this was an expression
  }
}

الآن، نظرًا لكيفية عمل JVM، بمجرد تحديد أحدها، لا يمكنك توسيعها.يمكنك، بالطبع، إعادة ترجمة كل شيء، لكننا تجاهلنا ذلك.لذلك عليك وضعه في مكان مختلف:

package $line1 { // input line
  object $read { // what was read
    object $iw { // definitions
      def foo(x: String): Unit = { println(foo(2)) }
    }
  }
}

وهذا ما يفسر سبب عدم تحميل الأمثلة الخاصة بك:يتم تعريفها في مكانين مختلفين.إذا وضعتهم في نفس السطر، فسيتم تعريفهم جميعًا معًا، مما قد يؤدي إلى تحميلهم الزائد، كما هو موضح في المثال الارتجالي.

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

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