Godot: الكتابة الاختيارية في GDScript

تم إنشاؤها على ٢٥ أغسطس ٢٠١٧  ·  38تعليقات  ·  مصدر: godotengine/godot

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

لقد تعلمت لغة البرمجة المسماة "Nim" لأنها تحتوي على وحدة نمطية ودية للغاية لـ GDNative وأنا مهتم بتعلم المساهمة هناك (نظرًا لأن C ++ صعب بالنسبة لي بصريًا ولكن لا علاقة له بهذا ، فقط بعض الخلفية). يتم كتابة Nim بشكل ثابت وأنا أعلم أن GDSCript ديناميكي لكنني صادفت موقفًا قد أرغب فيه في تحديد النوع لتسهيل الأمور.

بشكل أساسي عند كتابة دالة ، سيكون من الجيد أن أتمكن من تحديد نوع المتغير الذي يُسمح بتمريره حتى يتمكن إكمال الكود من معرفة ما أتحدث عنه ، لكنني متأكد من أن هناك مزايا أخرى لـ هذه.

شيء مثل

func myfunction(a, b : int, c : InputEvent , d : String = "Default Value"):
    (...)

عندما يكون a ديناميكيًا ، يكون bd ثابتًا ولكنه يظهر ما أعتقد أنه يمكن أن يبدو عليه بناء الجملة.

أعلم أنه يمكنك تحديد تلميح الكتابة للمحرر عند استخدام الكلمة الأساسية للتصدير ، لكن لا يتعين عليك الاحتفاظ بالمتغير في هذا النوع بمجرد تنفيذ البرنامج النصي. قد تكون هذه الفكرة ضد ما هو المقصود بـ GDScript ، أو الكثير من العمل لتحقيق مكاسب قليلة جدًا ، لكن دعنا نتحدث.

discussion feature proposal gdscript

التعليق الأكثر فائدة

يجب أن يكون هذا متاحًا في Godot 3.1.

ال 38 كومينتر

يبدو أنك تستطيع أن تفعل

func myfunction(something = InputEvent):

وسيمنحك ذلك حدث إدخال فارغ إذا لم يجتازوا أي شيء ، لكنهم لا يفرضون أن يكون المتغير من هذا النوع

myfunction('string')

سيعمل بشكل جيد.

إنها على خريطة الطريق :)
https://github.com/godotengine/roadmap/blob/master/ROADMAP.md

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

لسوء الحظ لا ، لا توجد أي مراجع لذلك حتى الآن ، إلى جانب بعض مناقشات irc.

CCreduz ، لإعطاء بعض التلميحات حول ما

@ يجب أن يبدو

ماذا عن:

func myfunction(something is InputEvent, something_else is String):

هذا جيد جدًا بالنسبة لي ، يجعل الكلمة المفتاحية أكثر فائدة ويسهل فهم الكود

أنا أعترض. سأكون بخير مع String something أو something : String . something is String سيئًا بالنسبة لي.

String something أو something is String كلاهما جيد بالنسبة لي. استخدام القولون سيجعل الكثير من علامات القولون في الكود على ما أعتقد.

إذا لم يتم استخدام is فسأفضل String something لأنني معتاد على هذا الترميز من لغات أخرى وأعتقد أنه أكثر شيوعًا.

تضمين التغريدة
إذا كان بإمكانك تحديد النوع عند إنشاء var أيضًا ، مثل var something:String = " " فأنا أوافق

بخلاف ذلك ، أعتقد أنه سيكون من المحير أكثر استخدام الفاصلة المنقوطة في تعريفات الوظائف فقط.

يستخدم "Is" للسؤال عن الميراث في gdscript الآن ، فلماذا لا يتطلب ذلك؟

C مثل نوع البادئة سيكون أفضل IMO. إنه أقصر وأسرع في الكتابة ويمكن أن يحل محل var أو func عند استخدام الأنواع.

مثال:

int some_variable

int some_function(int some_argument):
    return some_variable + some_argument

تصويتي على ذلك.

@ juan-garcia-m
لا أعتقد أنه يجعل الأمر أكثر قابلية للفهم بالنسبة لشخص ليس على دراية بـ C مثل الكتابة. أعتقد أنه قد يكون من الأسهل الكتابة ، ولكن أقل قابلية للقراءة.
أنا أفضل أن أعرف في لمحة ما هي الوظيفة أو المتغير ، واستبدال هذه الكلمات الرئيسية بأنواع من شأنه أن يزيل هذه القدرة بالنسبة لي ؛ إنه أحد أسباب صعوبة الدخول إلى C و C ++ بالنسبة لي.

من الواضح أن اللغة لا يمكن أن تصنع لي ، لكنني متأكد من أنني لست الوحيد الذي يشعر بهذه الطريقة.

مشكلة واحدة مع "هي" ، يتم استخدامها حاليًا في 3.0 لما كان يُعد "يمتد" ، أي التحقق مما إذا كانت العقدة تنتمي إلى فئة أم لا.

تضمين التغريدة
لهذا السبب يبدو من المناسب التحقق من النوع في إعلان الوظيفة بالنسبة لي.
لا يزال يتم استخدام الامتدادات في الجزء العلوي من البرنامج النصي ، ولكن لفحص النوع ، يتم استخدام "is" (وأعتقد typeof للحرفية).

تعد بادئة النمط C أكثر تعقيدًا بشكل عام ، وبالنسبة لهذه الأنواع من اللغات ، يبدو أن المعيار هو المتغير: اصطلاح النوع ، بحيث يتم استخدامه

لماذا تم إغلاق هذا؟ لم يتم تنفيذه بعد ...

لقد أغلقته لأنه كان مجرد مناقشة ، لكنني سأعيد فتحه لتتبع تقدم الميزة المطلوبة

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

var foo: String = 'bar'

... بدلاً من مجرد استبدال الكلمة الرئيسية var بالنوع ...

String foo = 'bar'

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

إليك كيف يجب أن تبدو:
godot windows tools 64_2017-12-12_17-21-27

اتباع بناء جملة Python (مشابه أيضًا لـ TypeScript و Haxe).

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

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

نعم ، قابلية قراءة الشفرة ذاتية للغاية. أعدت كتابة المثال الخاص بك في الشكل الذي سيبدو عليه مع بناء جملة النمط C. _I_ أجد الكود أدناه أكثر قابلية للقراءة ولا أجد صعوبة في التمييز بين المتغيرات والوظائف.

extends Node

const int MY_CONSTANT = 0
String my_member_variable = "Value"

void my_empty_func():
    pass

float my_other_func(bool arg1, Node2D arg2, bool default = false):
    Vector2 local_variable
    int other_variable = 0

    return float(other_variable)

يجب أن لا أتفق مع أن عبارة "أسرع في الكتابة" ليست حجة جيدة لأنها تؤثر بشكل مباشر على إنتاجية المطورين. يعد أسلوب Python أكثر تعقيدًا في القراءة والكتابة من أسلوب C ، والأكثر من ذلك أننا نرى الآن أنه سيتعين علينا كتابة -> فقط لتحديد نوع الإرجاع. الحجج الوحيدة التي يمكنني رؤيتها لبناء جملة أسلوب بايثون هي 1. لجذب المزيد من الأشخاص الذين هم على دراية ببايثون و 2 لأنه من الأسهل تنفيذها ، ولا أعتقد أن أيًا من الحجج جيدة بشكل خاص. لا أقترح أنه من السهل تنفيذه ، فأنا متأكد من أنه أكثر صعوبة وعلى الأرجح يتجاوز مستوى مهارتي ، لكنني أعتقد أنه سيكون يستحق ذلك على المدى الطويل.

على أي حال ، هذه هي قيمة بنساتي فقط: ابتسم :. أنا أستمتع بالتطوير في GDScript حتى الآن وأتطلع إلى وجود نظام نوع صوتي.

تدعم Python هذا بالفعل ، لذلك أعتقد أن أفضل ما يمكننا فعله هو النسخ من هناك

بالنسبة للأشخاص الذين يكرهون الكلمة المفتاحية var ، قد يكون من الممكن إضافة صيغة Nim like التي تسمح بشيء كهذا.

  a:int
  b:float
  c:char

const
  PI:float = 3.1416
  MAX:int = 100

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

نوع الإرجاع void ليس له معنى كبير بالنسبة لي ، أتخيل أنه سيكون من الأسهل حذف تعريف نوع الإرجاع في هذه الحالة.

أخيرًا ، يبدو -> غريبًا بالنسبة لي إذا كنا سنحصل على أنواع إرجاع ، لكنني أدركت أنك قد لا تفعل شيئًا مثل func somefunc(): String: (ربما؟) لكنني لست معجب بهذا السهم مثل بناء الجملة لأنه لا يشير أيضًا إلى الكثير بالنسبة لي ، ويبدو اتجاهيًا ولكن لا علاقة له بذلك ، يذكرني بالعمليات الحكيمة >> و << لكن هؤلاء هي اتجاهية بطريقة ما.

__ألم أقصد إغلاق المشكلة__

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

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

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

لذا ، أعتقد أن القدرة على الحصول على أكبر قدر ممكن من معلومات البرنامج النصي ستجعل Godot أكثر قابلية للتوسعة لكتاب الإضافات.

أعتقد أيضًا أن بناء جملة نمط TypeScript (باستخدام var name: String = "Godot" ) هو الأفضل لأنه أصبح إلى حد ما بناء جملة قياسيًا للكتابة الاختيارية المضافة إلى اللغات الديناميكية.

أيضًا ، يعد اتباع بناء جملة بايثون فكرة جيدة:
https://www.python.org/dev/peps/pep-0484/
https://docs.python.org/3/library/typing.html

سيساعد هذا الأشخاص الذين يأتون إلى GDScript من لغات ديناميكية مماثلة بكتابة اختيارية.

راجع للشغل ، متى / في أي إصدار يمكن أن نتوقع أن يتم تنفيذ هذا؟ لقد رأيت 3.1 المذكورة؟

يجب أن يكون هذا متاحًا في Godot 3.1.

حول الحجج ضد بادئة نمط C كونها أكثر تعقيدًا أو أقل قابلية للفهم / مقروئية ، ومن المرحب أكثر أن تتعامل مع بناء جملة بيثون أو ما شابه - ألا تستخدم جميع المستندات نوع البادئة من النوع C مع كل الطرق وما شابه؟ مثل ، لمجرد سحب واحدة من صفحة الكاميرا بسرعة set_orthogonal ( float size, float z_near, float z_far ) لم أفهمها تمامًا بنفسي في البداية ، لكن الأمر يستغرق لحظة فقط لأتعلم على ما أعتقد ، ومن المنطقي تمامًا بعد ذلك.

مرحبا ، اقتراح هنا.

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

https://crystal-lang.org/docs/

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

فيما يلي مثال لما يمكن أن يفعله هذا النوع من النظام (لمن يعرف القليل من الياقوت)

def test(x)
    return true if x
    return "This is false"
end

puts test(false).upcase
puts test(true)

انتاج:

Error in test.cr:6: undefined method 'upcase' for Bool (compile-time type is (Bool | String))

puts test(false).upcase
                 ^~~~~~

أفكار؟

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

يذهب المثال من @ m4nu3lf بعيدًا إلى حد بعيد ، فهو في الواقع يستنتج النوع الناتج بناءً على التفرع. لا أستطيع أن أرى كيف يتم ذلك دون محاكاة تنفيذ الكود ، حيث يمكن أن يصبح معقدًا للغاية. لست متأكدًا إلى أي مدى يريد reduz أن يذهب مع GDScript.

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

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

vnen نظريًا باستخدام بعض الكلمات الرئيسية الجديدة للمعلمات / أنواع الإرجاع / المتغيرات مثل "auto" أو "let" وباستخدام نفس خوارزمية Crystal-lang ، يمكنك استنتاج النوع في وقت الترجمة .
إنها كتابة ثابتة مع الاستدلال الكامل بالنوع.
لنفترض أن لديك
auto my_field = 42 في البرنامج النصي ، يمكنك ببساطة استنتاج النوع ليكون int وتقييد المتغير الأساسي على ints فقط.

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

  • إنشاء وظائف لكل مجموعة جديدة من أنواع الوسيطات واستنتاج الأنواع الداخلية لكل تعبير إرجاع ، وحفظ قائمة أنواع الإرجاع المحتملة كنوع القيمة المرجعة.
  • بالنسبة للفروع ، قم بإخراج جميع الفروع المحتملة التي يتم تعيين متغير لها ، لاستنتاج جميع الأنواع الممكنة للمتغير في وقت معين. في أي وقت ، قم بتقييد نوع المتغير بتلك

علاوة على ذلك ، يجب عليك التحقق من حالة "المثيل" وما شابه ذلك

if my_var instanceof MyClass:
...

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

auto x = MyClass.new()
if (...):
   x = "hi"

ثم بعد هذا x إما MyClass أو سلسلة. ستتمكن فقط من استدعاء الطرق المشتركة لكليهما لتجنب أخطاء وقت التشغيل.

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

@ m4nu3lf أنا أفهم ما هو طلبك ، TypeScript مشابه جدًا (وهي لغة أكثر دراية بها).

ومع ذلك ، هناك بعض المشكلات التي يجب مراعاتها في GDScript:

  • أولاً ، ليس من التافه تنفيذ ذلك. يمكنني النظر في كيفية تحقيق ذلك للغات الأخرى ، ولكن لا يزال الأمر سيستغرق وقتًا طويلاً. لهذا السبب أريد أن أخطو خطوة واحدة في كل مرة وأفكر في هذا لاحقًا. تم إنشاء TypeScript بواسطة نفس الشخص الذي صنع Turbo Pascal و C # ، لذلك هناك الكثير من الخبرة التي لا أمتلكها.
  • يتم تجميع GDScript في ملف واحد في كل مرة. يتطلب كل من Crystal و TypeScript تجميع المشروع بالكامل قبل استخدامه. هذا يعني أنه من الغائم قليلاً التحقق من التفاعل مع البرامج النصية والمفردات الأخرى.
  • شجرة المشهد. باستخدام get_node() (والذي يتم استخدامه كثيرًا) ، من المستحيل ببساطة معرفة نوع العقدة التي ستحصل عليها. أنت تعرف فقط أنه Node ولكن يمكن أن يكون من أي نوع فرعي. ينطبق الأمر نفسه على الموارد عندما تتصل بـ load() ، خاصةً إذا كنت تسميها باسم ديناميكي. يعاني _input(event) من نفس المشكلة ، نظرًا لأن event يمكن أن يكون أي نوع فرعي من InputEvent.
if my_var instanceof MyClass:
    ...

تم استنتاج هذا بالفعل لإكمال الكود. يمكن إعادة استخدامها لفحص النوع الفعلي. هذه الحالة على وجه الخصوص تافهة ، لكنها يمكن أن تتورط فيها تمامًا. على سبيل المثال ، إذا أضفت شرطًا ثانيًا: if some value == 42 and my_var is Sprite ، فلن يعمل إكمال الكود بعد الآن.


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

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

لماذا هذا مغلق؟

أخطأت قليلاً ، يا سيئ.

العودة إلى البادئة و postfix: يستخدم كل من UML و Kotlin ": type".
الأساسية كانت أيضًا "DIM a as INT" (واستخدمت "as" بدلاً من ":" أو "is")

programaths لقد مر وقت طويل منذ ذلك الحين ، وقد تمت مناقشته مرارًا وتكرارًا. علاوة على ذلك ، هناك علاقات عامة تنفذ postfix ، لذا فهي غير واردة بعض الشيء الآن: مبتسم:

هل يجب أن أغلق هذا؟

@ LeonardMeagher2 سيتم إغلاقه تلقائيًا عند دمج العلاقات العامة الخاصة بي.

@ bojidar-bg أردت فقط إضافة بعض الأماكن التي تستخدم فيها postfix لأنها مثيرة للاهتمام بحد ذاتها. UML مخصص للتحليل والأشخاص غير التقنيين أيضًا. Kotlin هي لغة تم تطويرها لتكون أكثر راحة وحداثة من Java أثناء تنفيذ "Java فعال".

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

من الجيد دائمًا امتلاك المواد ، أليس كذلك؟ ؛-)

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات