• الإعلانات

    • فيصل الحربي

      تسجيل عضوية جديدة في المنتدى   01/31/2016

      السلام عليكم ورحمة الله وبركاته  عزيزي العضو الجديد :  حاليا رسالة الإيميل لتأكيد صحة إيميلكم تذهب للبريد العشوائي ( جاري حل المشكلة )  فإذا لم تجد رسالة التحقق من إيميلكم في صندوق الوارد لديكم إتجه للبريد العشوائي ( JUNK)  وقم بتفعيل إشتراككم من هناك   

Khaled Alshaya

المشرفون
  • عدد المشاركات

    2,052
  • تاريخ الانضمام

  • تاريخ اخر زياره

كل شيء نشر بواسطة Khaled Alshaya

  1. أخ محمد, أقصد بالتحويل, تحويل اسم المصفوفة إلى مؤشر من نوع كذا, و هناك عدة أنواع من الـ Implicit Conversion بين أنواع المؤشرات نفسها. لم أتكلم عن تحويل مؤشر من نوع *void إلى مؤشر من نوع آخر, هل يمكن أن توضح أكثر. تحياتي...
  2. السلام عليكم ... بالنسبة للسؤال الأول المتعلق بالـ overloading الخاص بالـ C-String في مكتبة Cpp القياسية فهذا كفى و وفى فيه الأخ محمد, و كما قال مؤشرات الأحرف حالة خاصة, و باقي أنواع المؤشرات تعامل عن طريق النسخة العامة التي تقبل *void صدقني أني لا ألوم أي أحد يكره C و من بعدها ++C بسبب هذا الموضوع بالذات, حتى Stroustrup قال بأنه شر لابد منه لضمان التوافقية مع C. أولاً, لابد أن تعلم و أظنك تعلم, أن اسم المصفوفة هو عنوان أول عنصر فيها. بكل بساطة خطأ, العبارة السابقة خطأ 100% إلا إذا عدلناها قليلاً لتصبح: اسم المصفوفة هو عنوان أول عنصر فيها إذا دعت الحاجة إلى ذلك أي إذا كان هناك conversion مقبول. كيف؟ بداية دعنا ننظر إلى أبسط مثال, و هو المثال التالي: char arr[] = {3, 2, 1, 0}; الآن, عندما يرد الاسم arr و الذي يعتبر من نوع مصوفة حرفية رباعية العناصر في مكان يستقبل مؤشر من نوع: char* p; فإن قيمة اسم المصفوفة تعامل كما لو كانت العبارة التالية: char* p = &arr[0]; char* p = arr; // same! هكذا قرر مصمم C! الآن, الأمر الذي قلت بأنه خاطئ في البداية يتضح عندما ننظر إلى السطر التالي: ??????? p = &arr; ماهو نوع p؟ في هذه الحالة, اسم المصفوفة لم يطلب المبرمج معاملته على أنه مؤشر حرفي, و إنما أخذنا عنوان المصفوفة نفسها. و نوع عنوان المصفوفة التي تكلمنا عنها في البداية هو: char (*p) [4] = &arr; ببساطة هو مؤشر لمصفوفة حرفية مكونة من أربع حروف, و كما قلنا اسم المصفوفة في هذه الحالة لم تنطبق عليه عملية التحويل. و لهذا, فإنك عندما تقوم بطباعة عنوان المصفوفة نفسها: cout<<&c<<endl; فإن النوع الذي يمكن التحويل إليه هو *void فقط, لأنه يمكن تحويل جميع أنواع المؤشرات إليه, يمكن أن تقول عنه the hole that makes pointers in C++ not type-safe :) بالطبع ليس هناك implicit conversion للتحويل بين عنوان المصفوفة و بين مؤشر حرفي. هذا كاف لحل اللغز الذي تتكلم عنه :cool: ربما خطر ببالك سؤال آخر, و ربما هذا المثال يلقي الضوء عليه: char array[] = {0, 1, 2, 3, 4}; void* array_address = &array; void* char_address = array; assert(array_address == char_address); // the address is the same! تلك المؤشرات تشير إلى نفس العنوان بالضبط! كما تعلم المؤشرات تشير إلى أماكن في الذاكرة, و عندما نقوم بعمل dereferencing للمؤشر فإننا نحصل على تلك القطعة بشكل مختلف حسب نوع المؤشر. فمثلاً: int some_garbage = 0xdeedbeef; char* cp = reinterpret_cast<char*>(&some_garbage); int* ip = &some_garbage; int sum = 0; sum += *ip; // *p is the first four bytes shaping an int sum += *ic; // *ic is the first byte of some_garbage و أيضاً, عندما تقوم بتحريك المؤشر, فإن عملية التحريك تتم حسب حجم نوع ما يشير إليه, لذلك: /* 'a++' moves 'a' by one byte in memory. */ char* a; /* 'b++' moves 'b' by on "array of four chars in memory */ char (*b)[4]; كما تلاحظ المؤشر b يتحرك أربع bytes عند زيادة المؤشر, لأن حجم النوع الذي يشير إليه هو 4 bytes مكونة من أربع حروف في مصفوفة. بينما a يتحرك byte واحد فقط. تحياتي...
  3. السلام عليكم, الموضوع بسيط, و عبارة عن مشاركة خبرة لا أكثر, نريد ممن لديه تجربة أن يشاركنا بها. ماهي اللغة التي كنت تتمنى أن تتعلمها, و لكنك لم تفعل لأي سبب كان بغض النظر عن السبب نفسه. و ماهي اللغات التي تستحق التعلم من وجهة نظرك؟ سيكون من الرائع, أن توضح بالخطوط العريضة لنا الميزات التي جذبتك إلى تلك اللغات. بالنسبة لي, كانت Javascript هي اللغة التي لم أتعلمها حتى الآن رغم أني أدرت البدء مرات عديدة بتعلمها, و اللغة التي تستحق التعلم في هذا الزمان بلاشك Python و القادمة Cpp0x. لماذا هاتان اللغتان؟ ربما بعد أن نسمع آرائكم أنتم, تحياتي,
  4. سلسلة النظرة الأولى على VS 2010

    بصراحة كـ IDE لم أجرب حتى الآن ما يجعلني أترك VS ربما أحتاج لتعلم vim أو emacs حتى أغير رأيي :P و لكن لو نظرت بشكل عام لهذا الإصدار ستجده مخيب للآمال بالنسبة لمترجم ++C. بالنسبة لـ GCC فإنه يدعم Cpp0x بشكل كامل ما عدا الـ Memory Model الجديدة و ما يتبعها من الـ Threading, و ذلك لأنها تحتاج لكثييير من العمل, بينما باقي الميزات أغلبها موجود و ميزات يحتاجها معظم مبرمجو ++C, بينما MCpp يدعم خمس ميزات جديدة تقريباً! و هناك CLang التي تعمل فوق LLVM و التي يستخدم مترجمها على Mac بشكل رائع, و نتائج إخباراته تتفوق على GCC بشكل كبير جداً الذي يتفوق أصلاً على MCpp في نقاط كثيرة. مترجم C في CLang يعمل منذ مدة ليست بالبسيطة بين أيدي المبرمجين في شركات كثيرة, و مترجم ++C يتقدم تطويره يوماً بعد يوم, و يعد بسرعة رهيبة في الترجمة التي تعاني منها مترجمات ++C الأثرية التصميم, و مستوى من الـ Optimizaion لم تصل إليه مترجمات ++C الحالية في كثير من الجوانب و ذلك بالإعتماد على LLVM كـ Backend, و رسائل أخطاء كما في الـ Java :P, رسائل الأخطاء بالذات هي ما يزعجني حول مترجمات ++C بشكل عام حتى الآن إضافة إلى المترجمات monolithic و هو ما قام CLang بتصحيحه بشكل كامل, و توفير مكتبات للـ Static Analysis و غيره بحيث يصبح المترجم عبارة عن Driver للمكتبات الباقية. و فوق كل هذا ببلاش. بالمناسبة السنة القادمة هو موعد إعلان ولادة ++C الجديدة, و على MCpp اللحاق قبل أن يسحب GCC و CLang عندما يكتمل البساط من تحته. عموماً, الـ IDE لا يعلى عليه و لكن الإصدار كان متسرعاً قليلاً حسب رأيي بالنسبة لكامل الطقم. تحياتي...
  5. السلام عليكم ... أخ PWCT Maker, كما قال الأخوة, الـ Associative Arrays لا تكتمل لغة برمجة يستخدمها بها أكثر من مبرمج. طبعاً لغات الـ Scripting مشهورة في هذا و لا داعي للسرد, و لكن أقوى لغة تمتلك الـ Associative Arrays هي Lua. و السبب أنها مصممة بطريقة لكي تعمل كل شيء تتوقعه في اللغة. ببساطة الـ Array و الـ Dictionary و OOP concepts كلهم يمكن تطبيقهم باستخدام الأعجوبة المسماة Table في Lua الصغيرة :) dummy = {1, 2, 4, 5, 6} -- first array index starts at 1. Forget C for a moment! for i = 1, 5 do print(dummy[i]) end dummy = {hello = "hello", world = "world"} print(dummy["hello"]) print(dummy.world) ============================== 1 2 4 5 6 hello world تحياتي...
  6. مصطلحين بالوراثة

    السلام عليكم ... لايوجد وراثة متعددة و ولا طريقة مباشرة لتطبيق مفهوم الـ mixin في Java. ماهي اللغات الأخرى التي تعرفها حتى نتكلم عن الموضوع بشكل بسيط؟ تحياتي...
  7. السلام عليكم ... أعتذر عن خطأ بسيط في الكود الذي في الأعلى :) المشكلة تظهر عندما نجد ملف بالاسم المحدد, فيتوقف البحث. المشكلة أنه قد يكون هناك مجلدات أخرى لم يصل لها البحث أصلاً. هذه نسخة معدلة و تمت تجربتها: #include <iostream> #include <string> #include <vector> #include <boost/filesystem.hpp> using namespace std; using namespace boost::filesystem; void find_file(const path& root, const string& file_name, vector<path>& found_files) { directory_iterator current_file(root), end_file; bool found_file_in_dir = false; for( ; current_file != end_file; ++current_file) { if( is_directory(current_file->status()) ) find_file(*current_file, file_name, found_files); if( !found_file_in_dir && current_file->leaf() == file_name ) { // Now we have found a file with the specified name, // which means that there are no more files with the same // name in the __same__ directory. What we have to do next, // is to look for sub directories only, without checking other files. found_files.push_back(*current_file); found_file_in_dir = true; } } } int main() { string file_name; string root_path; vector<path> found_files; std::cout << root_path; cout << "Please enter the name of the file to be found(with extension): "; cin >> file_name; cout << "Please enter the starting path of the search: "; cin >> root_path; cout << endl; find_file(root_path, file_name, found_files); for( std::size_t i = 0; i < found_files.size(); ++i) cout << found_files[i] << endl; } ملاحظة حول الكود في المشاركة الأولى أيضاً, هي السطر التالي: std::cout << root_path(); لا أدري من أين أتت الأقواس, رغم أن الكود الموجود لدي على الجهاز لايحتوي على تلك الأقواس, ربما بسبب التعديل اليدوي في المحرر الظريف في المنتدى :( تحياتي...
  8. خطأ في حال إدخال حرفي أو null

    طيب ما هي البيئة التي تعمل عليها؟ هل هي VC.NET؟ أبسط الحلول هو أن يكون تكون الدالة ToDouble تقوم برمي Exception في حالة عدم القدرة على التحويل, و من الـ catch يمكنك أن تقوم بعملية إسناد صفر للمتغيرات.
  9. لماذا مايكروسوفت

    النقاش تحول إلى "هل المبرمج" يستطيع إنتاج شيء باستخدام أي تقنية يعمل بها, سواء كانت Flash أو #C؟ الإجابة بكل بساطة هي نعم, المبرمج يستطيع التكيف مع التقنية التي يعمل بها. و لكن لم يكن هذا الذي تناقشنا حوله أصلاً! ما قلناه أنا و الأخ حسن بطريقة أفضل مما قلته, هو أن VB صدرت للعالم أشباه مبرمجين, و لم نقل أن كل من يستخدم VB فهو شبه مبرمج, لأن هذا كلام غير منطقي بكل تأكيد. طبعاً أول نقطة, هي أن المستخدم هو من يحدد المبرمج من غير المبرمج, و طبعاً نقطة لا تحتاج إلى رد, لأن هذا الإدعاء هو كقولك أن المريض هو من يحدد الطبيب الحقيقي من الشخص الذي يدعي أنه طبيب. باقي النقاط تناقش أول سطر في إجابتي, و هو موضوع لا نختلف فيه. المشكلة الحقيقية, برأيي أن هناك أشخاص يقومون "بإنتاج" برامج باستخدام تقنيات Microsoft في الغالب و غيرها من التقنيات بشكل عام, ليس لديهم أدنى الأساسيات. شخصياً, رأيت "مبرمجين" يقومون بكتابة برامج من النوع المعروف في عالمنا العربي, دون أدنى معرفة بأساسيات البرمجة, من حيث اختيار الـ Data Structure المناسبة, و هكذا. هذا طبعاً إن كنت متفائلاً, و كان ذلك الشخص "مبرمج" جيد حسب التصنيف! ما بالك "بمبرمجين" لا يعرفون ماهي الـ Stack أو الـ Queue و لايعرف أبسط أنواع البحث و الترتيب. رجاءً, الـ Abstraction ليس له علاقة بهذه الأمور, لأن هذه الأمور هي من اختصاص المبرمج, و الـ Framework يقوم بتوفيرها لا أكثر. طبعاً, هذه هي النتيجة عندما تقنع البشر بأنهم يمكن أن يكونوا مبرمجين بتعلمهم لـ IDE و كيفية وضع عدة أزرار على form و من ثم عمل compile و بالصلاة على النبي أصبح لدينا برنامج. أنا لم أقل, أنه يجب على الجميع أن يعمل في أخطر أنواع البرمجيات, كل ما قلناه هو أن القوقعة التي يعيش فيها البعض يجب أن يخرج منها, لأنه في النهاية تعلم كيفية إنتاج ملفات تنفيذية باستخدام IDE معين, حسب Guidelines معينة, و هذا لا يجعل منه مبرمجاً. و هذا الأمر ليس إهانة كما يعتقد البعض, و إنما هو دعوة لكي نرجع للأساسيات قبل أن ننتج برامج لا تستحق أن تعمل. و أنا مع الرأي القائل, بأن المستقبل هو الـ Concurrent Programming, و لاداعي لأن أقول بأن أي شخص ليس لديه الأساسيات لن يستطيع استيعاب مواضيع البرمجة المتوازية, وبالعربي الفصيح "ما راح ياكل خبز". هذه ليست "فلسفة" أكاديمية, هذا واقع نعيشه للأسف. نحن لم نطالب بأن تكتب Iterative Quick Sort, أو كتابة خوارزميات في الـ Graph Theory. كل ما قلناه, هو أنه يجب أن تكون هناك أساسيات قبل أن تقدم على فعل أي شيء. و تلك الأساسيات لحسن الحظ متوفرة حتى على الويب, و لكنها تحتاج إلى من يلتقطها, و هذا ما أكدته بأن هناك مبرمجين حقيقيين لم يدخلو أسوار الجامعات أصلاً, و ربما يكونوا أفضل ممن دخلوها و المنتدى شاهد على ذلك. أما من يصعد إلى آخر السلم خطوة واحدة, فسيقع في النهاية. تحياتي...
  10. ملاحظة عظيمة :) لأن عملية الإرجاع ستكون مكلفة. فلو قمنا بالتالي: vector<path> found_files = find_file(...); طبعاً, الـ vector الموجود في الدالة سيكون على الـ stack الخاص بها. بينما الـ vector الذي حصلنا عليه موجود على الـ stack في الدالة main على سبيل المثال. لاحظ أن ذلك كلام عام. لأن معظم المترجمات الشهيرة تقوم بعمل Optimization اسمه RVO و هو يعني Return Value Optimization, بمعنى أن العائد من الدالة سوف يوضع على الـ Stack في الدالة التي نادت دالة أخرى مباشرة, دون حجز شيء على stack الدالة المناداة. الحل الآخر أن تقوم باستخدام المؤشرات, أو المؤشرات الأوتوماتيكية كـ auto_ptr من المكتبة القياسية أو shared_ptr الأكثر قوة من boost, و يصبح الأمر مثل استخدام الـ GC. بشكل عام, لا يحبذ استخدام المؤشرات لأن استخدامها يجب أن يكون للضرورة فقط عندما لا يمكن إنجاز الأمر بدونها. الحل المختصر هو أن تقوم بعمل out parameter. طبعأً لو كان الأمر راجع لي و الكود لي لكنت قمت بكتابة الكود بـ Cpp0x خصوصاً أن GCC 4.5 أصبح يدعمه بشكل شبه كامل قبل سنة من اكتمال الـ Standards :P يمكن أن أكتب الكود بـ Cpp0x إن أحببت, و هناك ميزة الـ Move Constructor التي تلغي جميع المشاكل التي تكلمنا عنها من حيث عملية النسخ. حيث يصبح السطر الذي وضعناه في الأعلى اعتيادياً جداً, دون الحاجة إلى استخدام المؤشرات أو القلق حول عملية النسخ.
  11. السلام عليكم ... لم تحدد نظام التشغيل, و المكتبات التي تستخدمها, و لا ماذا تريد عمله من إيجاد ملف معين, و لا خيارات البحث كالتوقف عند إيجاد ملف بذلك الاسم, أو إكمال البحث لإيجاد باقي الملفات المشابهة في الاسم في مجلدات أخرى. عموماً, أنا استخدمت boost لإنجاز الأمر, و هي تعمل بكل تأكيد على نظامك مهما كان :) الكود يقوم بإيجاد __جميع__ مسارات الملفات بالاسم الذي يدخله المستخدم, و يجب عليك تحديد مسار أولي لكي يبدأ البحث من خلاله: #include <iostream> #include <string> #include <vector> #include <boost/filesystem.hpp> using namespace std; using namespace boost::filesystem; void find_file(const path& root, const string& file_name, vector<path>& found_files) { directory_iterator current_file(root), end_file; for( ; current_file != end_file; ++current_file) { if( is_directory(current_file->status()) ) find_file(*current_file, file_name, found_files); if( current_file->leaf() == file_name ) { // No more than two files with same name in the same directory, // add the file to found_files and exit. found_files.push_back(*current_file); break; } } } int main() { string file_name; string root_path; vector<path> found_files; std::cout << root_path(); cout << "Please enter the name of the file to be found(with extension): "; cin >> file_name; cout << "Please enter the starting path of the search: "; cin >> root_path; cout << endl; find_file(root_path, file_name, found_files); for( std::size_t i = 0; i < found_files.size(); ++i) cout << found_files[i] << endl; } هناك الكثير من التحسينات التي قد تقوم بها, و لكن لا أعتقد أنها لازمة إن كان الاستخدام بسيطاً, و ربما تحتاج إلى استخدام دوال النظام الذي تعمل عليه, لجعل الكود أسرع من هذه الطريقة أو لإضافة خيارات أكثر لعملية البحث. تحياتي....
  12. ربما الآلة الحاسبة تفترض أن العملية هي: -(n!)
  13. كيفية بداية السي ++ لمبرمجي الجافا

    السلام عليكم ... أخ هويدي, هل أنت راغب في التعرف أم تعلم ++C؟ لا يوجد طريقة سهلة لتعلم ++C كما أنه لا توجد طريقة سهلة لتعلم Java. الطريق الأفضل بكل شك, هو الكتاب الأسطوري The C++ Programming Language Third Edition, و من الأفضل أن يكون الـ Special Edition :) ذلك الكتاب يعطيك كل ما تريده لكي تملك اللغة, و يصبح استخدام الـ Frameworks مسألة وقت للتعود عليها لا أكثر, بمعنى أصح ستبني فوقه ما تشاء في أي اتجاه. المشكلة أن هذا الكتاب دسم, و جمله مركزة. لذلك إن كنت تحب كتباً أسهل و لكن بنفس الجودة, فهناك خياران, الأول Accelerated Cpp و الثاني Cpp Primer. الأول عبارة نسخة مختصرة عن الثاني. و رجاءً لا تأخذ الكتب التي تسرد ++C سرداً تاريخياً بدلاً من موضوعياً. عندما تكون المؤشرات في ثاني فصل من الكتاب, يمكن أن تشبه ذلك بثاني فصل عن الـ GC في Java. بمجرد أن تنتهي, فأنصحك بتعلم Qt, رغم أني لم أتعلمها إلى الآن :) الـ Frameworks المفضلة لدي, هي Boost, و هناك POCO و هناك الكثير. كل بمميزاته و عيوبه. أفضل كتاب في هذه المرحلة, هو Effective Cpp و Effective STL و سلسلة Effective الرائعة, أعتقد أنه يوجد للـ Java أيضاً؟! كتاب Thinking in Cpp هو كتاب رائع أيضاً, و يأتي في هذه المرحلة. بعد ذلك, عليك بأفضل كتاب برأيي حتى الآن: The Design and Evolution of Cpp و لكن آخر نسخة منه صدرت عام 94 و لكن النسخة القادمة قريبة ربما. إن كنت تريد أن تفهم فلسفة لغات الـ C-Like بشكل عام و تاريخها أيضاً (++C خصوصاً) عليك به :) هناك كتاب The C++ Standard Library: A Tutorial and Reference أكثر من رائع كمرجع للمكتبة القياسية. حتى لو غيرت رأيك بعدم تعلم ++C, فعليك بأوراق Stroustrup, انتقي منها ما تشاء, و هذا الرجل أعطاه الله موهبة الكتابة بجانب البرمجة بالمناسبة. تحياتي...
  14. لماذا مايكروسوفت

    أخ asm-soft, رجاءً دعك من الـ Best Practices للحظة, لأنه يبدو أنها من الكماليات لدى البعض, فكلمة مبرمج تعني أي شخص يمكنه أن يفتح IDE و الباقي على ربنا, يعني Power User. يا أستاذ System Down, لو استثنينا المشاريع الشخصية و الألعاب, فجميع البرامج بلا استثناء تعمل لإنجاز مهام حساسة. أليست برامج المحاسبة برامج حساسة, طيب ماذا عن الـ Controllers التي في السيارة, أم أن المبرمجين الذي تتكلم عنهم لا يجرؤون على التفكير حتى في البرمجة لغير Windows؟ طيب ماذا عن الطائرات, ماذا عن إشارات المرور, ماذا المواقع التي تقدم خدمة الدفع على الانترنت, ماذا عن المواقع الاجتماعية؟ في آخر الأمر يأتي "عيل" على قولة اخواننا المصريين يسرق معلومات بطاقتي الإتمانية, لأنه برأيك الشخصي البرمجة يجب أن تكون مفتوحة "للجميع" و الشخص الذي قام ببرمجة الموقع هو جزء من هذا الجميع الذين لهم الحق في البرمجة! أتمنى أن تعطيني مثالاً, عن برنامج لا يعمل لإنجاز أمر مهم, عدا عن الألعاب و الـ Personal Projects. تحياتي...
  15. لماذا مايكروسوفت

    أولاً أعتذر منك يا أستاذي إن فهمت أني ظهرت بما تسميه "الفوقية العلمية". ثانياً, VB انتهت, و بغير إرداة مستخدميها و مجتمع المبرمجين و بجرة قلم من أحد مدراء Microsoft. ثالثاً, البرمجة ليست للهواة, و سبب الكوارث التي نراها هو هذا الأمر. و ليس المقصد هنا الشهادة الجامعية, لأن كثير من الخبراء لا يملكونها, و لكنها ليست للهواة. نقطة انتهى. الكلام ليس عن الهواية الشخصية, و لكن عمن يأخذ دورة ستة أشهر بأحد التقنيات, ليصبح "مبرمج". رابعاً, من يدعي أنه مبرمج دون أن يفهم معنى المؤشرات(الذاكرة بالطبع و ليس المؤشرات بشكلها الموجود في C فقط) فليس بمبرمج. نقطة انتهى. ما أراه و أسمعه, هو أن من أتقن أداة أصبح مبرمج. و هذا يصلح كتشبيه أن كل من أمسك مشرط, أصبح جراح. تحياتي...
  16. لماذا مايكروسوفت

    مالذي تتكلم عنه أخ متميز! مادخل التطور بإلغاء لغة من الوجود؟ لا أحب الجدال كثيراً, و لكن إنهاء VB و غيرها, لعبة تسويقية و لا تمت للتطور بشيء. ++C ظهرت قبل أن يولد معظم من دخل هنا في النقاش, و من قبلها C و معها Pascal و معها Fortran و معها ..................................................... و إلى الآن موجودين و ليس هناك خوف أن البرنامج الذي تعبت عليه سنين, سيصبح من التاريخ, لأن هناك شخص يقول بأن التطور هو أن تقوم بإعادة كتابة برنامجك من الصفر لعيون تقنية أخرى دون سبب حقيقي. ألم يكن من الممكن أن تتطور VB كما تطور غيرها؟! قضية أن Microsoft أوهمت الكثيرين أن البرمجة هي أسهل المهام, و أن أي شخص يمكن أن يبرمج بـ VB قضية أخرى لا داعي للخوض بها أيضاً. و الناتج؟ برامج لا ترقى أن نسميها برامج أصلاً.
  17. لماذا مايكروسوفت

    مايكروسوفت تمنعك(تحتكر) بطريقة مباشرة أو غير مباشرة من استخدام منصة غير التي تقدمها, بدءأ من أسفل الـ Tech Stack و صعوداً إلى الـ End User. الاقتباس الذي أحضرته لايخدم مايكروسوفت بأي شكل, و لا داعي لأن أتصور أن هذا مقتبس من دعاية لمايكروسوف لأن قسم الدعاية والإعلان عليه العوض في تلك الحالة. ببساطة أخي, الجملة التي وضعتها تعني أن تلك التقنيات الأخرى تعطيك الحرية, لتعمل بها أينما شئت, دون أن تفرض عليك شيئاً. تحياتي...
  18. بسم الله الرحمن الرحيم, في الجزء الأول من هذا الموضوع, بدأنا حديثاً موجزاً عن الـ Type Safety و الـ Strong Typing في مقابل الـ Weak Typing.و حديثنا في هذا الموضوع عن الـ Static Typing في مقابل الـ Dynamic Typing. الغريب أنك إن لم تكن قرأت من قبل حول هذا الموضوع في مصادر "حقيقية" فسيصبك الإحباط, لتناقض المعلومات حوله. إذاً ماذا نعني عندما نقول أن هذه اللغة Statically Typed؟ و ماذا نعني عندما نقول أن هذه اللغة Dynamically Typed؟ لربما كانت الإجابة على "طرف لسانك" لو أنك قرأت عن الموضوع من قبل, و لكن: هل الإجابة هي أن كل لغة مترجمة هي لغة Statically Typed و كل لغة مفسرة هي Dynamically Typed؟! ماذا عن اللغات المترجمة وقت الشغيل Jitted!!! الـ Dynamic Typing عندما نتكلم عن أقصى معنى لها, تعني أن أي متغير في البرنامج النهائي أو بمعنى أصح at run-time يحمل جميع المعلومات الأخرى غير القيمة التي يحملها أساساً, مثل اسمه "التمثيل النصي لاسمه", نوعه, حجمه, الأنواع التي يرثها كما في OOP, و هكذا و عندما تكون اللغة Dynamically حتى النخاع فإن جميع المعلومات التي يمكن أن تستقيها من الكود يمكن أن تحصل عليها أو تعدلها بطريقة أو بأخرى عند تشغيل البرنامج at run-time. فالمتغير ليس فحسب, مكاناً توضع فيه قيمة و حسب و إنما data structure متكاملة تحمل جميع المعلومات التي تحددها اللغة إضافة إلى القيمة التي يفترض أن يحملها. هذا الأمر يوفر ميزات كثيرة و عيوب كثيرة أيضاً, فالعيب واضح, فلن يعود بإمكاننا استخدام الذاكرة بشكل كفؤ لأن المتغير يملأ حيزاً كبيرة, و ربما يكون حجم تلك المعلومات الإضافية أضعافاً مضاعفة من الحجم اللازم لحمل قيمة عدد صحيح int مثلاً. هذا الأمر يظهر عندما يكون البرنامج يعالج كمية كبيرة نسبياً من البيانات. و لكن الميزات كثيرة! فمثلاً تصور أننا نستخدم لغة تشبه ++C في الـ Syntax و لكنها Dynamic و أردنا كتابة دالة تقوم باستدعاء دالة تسمى print لكائن ما: void call_print(object) { object.print(); } هل ترى! الـ Generic Programming في أوج عظمتها :) سيتم البحث عن دالة اسمها print في معلومات الكائن المسمى object, ثم سيتم إحضار عنوانها و يتم ندائها, و في الغالب العمليات أكثر تعقيداً و اللغة تصبح مرنة إلى أبعد الحدود. لكن هناك سؤال, هل تستطيع دفع تكلفة ظهور الأخطاء وقت تشغيل البرنامج؟ في المقابل ستحصل على مرونة إلى حد أن هناك مبرمجون, يفضلون الـ Prototype Inheritance على الـ Classic Inheritance! الأولى لـ SmallTalk و هي لغة Dynamic و الثانية لـ Simula و هي المعتادة في اللغات الـ C-Like. الـ prototype inheritance هي مثال حقيقي على الـ Dynamic Typing, فأنت تأخذ كائن و لنقل أنه person, و تضيف عليه متغيراً اسمه student_number و تضيف دالتان get و set و أصبح لديك كائن جديد, و لا تنسى كل هذا تم عند تشغيل البرنامج! الـ Static Typing, على النقيض تعني أن المتغير يحمل معلومات أقل عن نفسه وقت التشغيل. قد يكون هذا التعريف غامضاً قليلاً, و لكن في أول الطيف هناك C و ++C حيث لا يحمل أي متغير عن نفسه أي شيء في الذاكرة على الإطلاق. و لا يوجد في اللغتان أصلاً طريقة لمعرفة وجود متغير معين من عدمه في الناتج النهائي عند الحديث عن الـ Optimized Code للمترجمات الشهيرة. هذا هو السبب الحقيقي لكون C و ++C لغات Efficient أكثر من اللغات الحية الأخرى لمهمات كصناعة المترجمات و الـ RDBMS حيث كميات البيانات خيالية. لربما كان من الغريب لمعظم دارسي C معرفة أن المصفوفات لاتحمل حتى حجمها معها في الذاكرة! هذا مصطلح أطلق عليه الأستاذ Stroustrup مايسمى بالـ Zero Overhead Principle :) في مترجمات اللغات الأكثر حداثة, كـ Java و #C و غيرهم يتم إضافة معلومات إلى الأنواع و لكنها بسيطة مقارنة بالمعلومات التي يتم إضافتها للمتغيرات في لغة Dynamic حتى النخاع كـ Python. ميزات الـ Static Typing واضحة, و عيوبه واضحة, و لكن بشكل عام الـ Static Typing تظهر محاسنها كلما كان حجم المشروع أكبر. فالمترجم بجانب المبرمج لاكتشاف أخطاء ربما تكون تافهة و لكنها غير ظاهرة كجمع نص مع عدد في حالة كون اللغة strongly typed مما يؤدي إلى خطأ وقت التشغيل بدلاً من إعلامنا بذلك مبكراً. الجميل في الأمر, أن هناك اتجاهاً نحو ما يسمى بالـ Reflection في اللغات الـ Statically Typed, و هذا بكل بساطة يعني أننا نستطيع الاستعلام عن بعض المعلومات المتوفرة عن المتغير و لكن لا يسمح لنا بتعديلها كما في اللغات الـ Dynamic الخالصة. ربما كنت قد أصبت بالإحباط عند وصولك إلى هذا السطر لأنني قلت: "فمثلاً تصور أننا نستخدم لغة تشبه ++C و لكنها Dynamic" فأنا قد أكدت في الموضوع السابق أن هذا الأمر لا علاقة له بلغة البرمجة نفسه و إنما بالـ Implementation المستخدم! في الحقيقة أن الجملة السابقة صحيحة و لكنها تحتاج إلى توضيح... عندما نستخدم مفسراً, فإن اللغة تصبح Dynamic لأن المفسر بطبعه يحمل جميع المعلومات عن الكود وقت التشغيل. بينما لو استخدمنا مترجماً, سيكون لدينا حالتان: الأولى هي أن يقوم المترجم باستخدام المعلومات التي استخلصها في الكود لترجمة البرنامج إلى منصة معينة دون إلحاق معلومات المتغير, و الحالة الثانية هي أن يقوم بإلحاقها! و في هذه الحالة تصبح اللغة Dynamic حتى باستخدام مترجم! لربما كان أوضح مثال هو عند بناء برنامج بلغة C مع تفعيل خواص الـ Debugging, في حينها ستصبح جميع المعلومات متوفرة في الناتج النهائي, و عند تفعيل خواص الـ Optimization فإن جميع المعلومات كأنها لم تكن أصلاً! هذا المثال ليس مثالاً محبذاً لدى الكثيرين عند الحديث عن الـ Dynamic Typing لأن اللغة في الحقيقة لاتوفر طرقاً للاستعلام عن تلك المعلومات من داخل اللغة نفسها وليس عن طريق برنامج خارجي على سبيل المثال. هذا يقودنا إلى الفقرة القادمة... دائماً عند وضع تعريف لشيء ما, فلابد أن تجد له ثغرات, و خصوصاً عند الحديث عن موضوع شائك كهذا! لابد أن تعي أن اللغات عندما تبنى فإن صاحبها على الأغلب يضع في الحسبان كونها ستصبح لغة مفسرة أو مترجمة, و بالتالي فإن هناك لغات ملائمة أكثر بطبعها للـ Dynamic Typing و هناك لغات ملائمة أكثر للـ Static Typing. ما نريد أن نصل إليه هو أن هناك لغات توفر مرونة في أنواعها, يصبح إنتاج مترجم لها معدوم الفائدة, لأن المترجم عليه أن يضع معلومات ضرورية لتلك المتغيرات للتأكد من صحة العمليات. فمثلاً, هناك تجارب لإنتاج مترجمات لـ Python, و لكن طبيعة اللغة نفسها و مرونتها لا تسمحان للمترجم بافتراض شيء حول المتغيرات, و يصبح من شبه المحتم أن يلحق معلومات المتغير وقت التشغيل. بينما في لغات أخرى, فإن هذا الأمر ليس صحيحاً بالضرورة, فمثلاً هناك مفسرات للغة C و لغة ++C, و هناك مترجمات, و نفس الأمر ينطبق على Haskell و Ocaml على سبيل المثال لا الحصر. إذاً, الأمر يتعلق بالافتراضات التي وضعها صاحب اللغة. و لكن أتمنى عند وصولنا لهذه النقطة, أن نكون قد وصنا إلى اتفاق أن استخدام مترجم لايعني أن اللغة Statically Typed. و لكن عند استخدام مفسر فإن الأمر شبه محسوم, و لكن تظهر لنا حالة شاذة و هي كون المفسر المستخدم يقوم بإنتاج كود Jitter يتم تنفيذه بعد ذلك. في هذه الحالة المعلومات قد تكون موجودة قبل الترجمة الفورية و ربما يقوم بالتخلص منها في الكود النهائي. يمكن أن تضع "سيناريوهات" عن لغات تقع في الوسط! لا نريد أن نعقد الموضوع أكثر من ذلك فأنا قد تهت! هناك لغات اختارت أن يكون هذا الأمر صريحاً في اللغة نفسها, بمعنى أن اللغة تفرض وجود الأمرين معاً في نفس الوقت, و لكن هذا توجه حديث نسبياً, و هو أحد شواذ التعريف الذي وضعناه. فمثلاً, في لغة #C النسخة الرابعة, استحدث صانعوها ما يسمى بالـ Dynamic Type رغم أن لغة #C لغة Statically Typed عند النظر إلى مترجماتها الشهيرة. فلو نظرت إلى المثال التالي: dynamic dynamic_int = 10; int static_int = 10; فمن المؤكد أن dynamic_int يحمل معلومات أكثر عن نفسه, و فائدة هذه الميزة لا تظهر إلا لو تخيلنا مثالاً أكثر تعقيداً كأن تقوم بتحميل مكتبة وقت التشغيل و من ثم تنادي دالة من أحد كائناتها دون حتى أن تعرف ماهو الكائن, و لا تخبر المترجم بماهية الكائن, و هل لديه تلك الدالة أصلاً؟ كل ذلك يتم وقت تشغيل البرنامج. بالطبع يمكنك القيام بذلك بدونها, و لكن المشكلة في الـ Static Typing أن المترجم لابد أن يعلم نوع الشيء الذي تريد استخدامه, و هذا الأمر قد يكون صعباً جداً في حالة كون الكود الذي تريد استخدامه بل ببساطة مكتوب بلغة أخرى كـ ++C مثلاً, و ربما تتضارب بعض الأنواع فيها مع #C. ببساطة هناك شخص قام بكتابة glue دون أن تراه كطبقة بين العالم الخارجي و بين متغيرك الـ Dynamic و سيحاول أن يبحث في المعلومات التي حصل من ذلك الكائن في العالم الخارجي لتطبيق ما أردته دون تعقيد أو حتى تفكير بماهية ذلك الكائن و هل من الممكن تمثيله بسهولة في اللغة أم لا. ضربت مثالاً آخر منذ مدة ليست بالقصيرة حول الـ Static Scope و الـ Dynamic Scope و كيف أن الـ Dynamic Scope يحتاج إلى Dynamic Types حتى يعمل. المثال تجده على الرابط التالي حتى نختصر الموضوع: What is lexical scope? قبل أن أترككم في رعاية الله, يجب أن أقول لكم بأنه لايوجد أحد ادعى بأنه يملك تعريفاً شاملاً للمصطلحات التي تكلمنا عنها. و ما ذكرته كان من المعلومات البسيطة التي أملكها, و من الخبرة الأبسط التي اكتسبتها. لذلك فإني أرحب بأي تصحيح أو إضافة مفيدة إلى الموضوع. بقي جزء قادم بإذن الله, و هو عبارة عن معاينة عن قرب لبعض اللغات لعرض المفاهيم التي تكلمنا عنها في الموضوع الأول و الثاني. تحياتي,
  19. مساعدة ضروري

    السلام عليكم ... أخي كل ما تحتاج إليه هو خوارزمية بسيطة, تسمى Shunting-yard algorithm. ستجد مثالاً في الوصلة عن الخوارزمية.
  20. أهلاً أخ PWCT Maker, الإضافة التي تكلمت عنها هي إضافة رائعة جداً في الحقيقة, و لا يسعني إلا أن أهنئك إن كنت أضفت كل تلك الميزات دون اطلاع سابق على لغات أخرى, أي أنك رأيت الحاجة لمثل هذه الميزات. لانريد أن نوسع الموضوع ليشمل مواضيع أخرى, و لكن نريد المواضيع أن تكون متخصصة أكثر لكي تصبح أكثر فائدة, لذلك لاداعي أخي العزيز للكلام عن الـ Implementations بشكل عام, لأن هذا بحر لا ينتهي. بالنسبة للميزة التي تكلمت عنها حضرتك - و التي تعجبني شخصياً - تسمى في عالم لغات البرمجة: Lazy Evaluation. هذه الميزة موجودة في صلب Haskell و يمكن تطبيقها في لغات أخرى, و لكن للأسف تصبح أكثر بشاعة إذا لم يتوفر دعم في اللغة نفسها. هذه الميزة ليس لها علاقة بالـ dynamic types في الحقيقة, و هي تأتي على أشكال عدة إضافة للذي ذكرته أخي العزيز. نحتاج إلى مقال عنها... قريباً بإذن الله :)
  21. الـ Operators هي من ضمن تعريف اللغة نفسه, و عندما أقول تعريف اللغة نفسه فأنا أقصد ذلك حرفياً من المثال الذي طرحته. ستجد في آخر الـ Cpp Standards حوالي 16 صفحة عبارة عن قواعد ++C بالنسبة للـ Syntax. و ستجد إشارة إلى الـ C Standards حسبما أذكر لكيفة التعامل مع الـ Operators Precedence. عموماً لو أن الـ Operators المستخدمة ليست لنوع Primitive كـ int لكان من الصحيح القول أنها ليست في تعريف اللغة, و لكن مثالك يستخدم متغير primitive و هو من النوع int. بعيداً عن الكلام الذي في الأعلى, iostream هو header يقوم بتعريف مكتبات الإدخال و الإخراج في ++C لا أقل و لا أكثر. تحياتي....
  22. كلامك صحيح إن كان ما قلته هو الذي حصل دون أن تسيء فهم مدرسك. هل الذي يدرسك ++C درسها أصلاً؟ هذه هي المشكلة الحقيقية عند من يدرسون ++C في الجامعات للأسف.
  23. السلام عليكم ... لا أخي الخاصية ليست تكافؤ Identity. لاحظ أنه عندما تكون c=0 فإن العبارة اليمنى تعتمد على قيمة d. فمثلاً: a.b = (a.b.c)+(a.b.c`.d) 1.1 = (1.1.0)+(1.1.1.d) 1 != d (if d == 0) أنا مع جدول الصواب أيضاً لأنه الأسهل :)
  24. أهلاً أخ عمرو, لا أعتقد أن الـ Type Inference يشبه المثال الذي ذكره الأخ PWCT Maker, لسبب بسيط, و هو أن الـ Type Inference هو عكس المثال المذكور. في المثال المذكور, قام الأخ بإضافة قليل من الـ Strong Typing على لغة Weak كما في حالة Lua أيضاً, بينما في حالة الـ Type Inference فنحن قمنا بإضافة مرونة "تشبه الموجودة" في الـ Weak Typing و لكن في لغة Strong. في أي لغة برمجة Strongly Typed, هناك أنواع تمثلها المتغيرات و هناك قيم و هي تعتبر الـ Domain لهذه المتغيرات. لغات البرمجة الـ Strongly Typed تنقسم إلى قسمين رئيسيين. الأول هو أن يكون النوع خاصية من خصائص القيم, بينما المتغيرات نفسها ليس لها أنواع, و لكنها تحمل أنواع القيم التي تحملها. فمثلاً في Python: x = 5 x = 'Hello Amr' x = [x for x in range(0, 10)] لاحظ أن x ليس لها نوع, و قمنا بحمل أكثر من قيمة من أنواع مختلفة في x و لكن اللغة لا تسمح بإجراء عمليات بين أنواع مختلفة. بينما في لغات أخرى كمعظم اللغات الـ Strongly Typed فإن المتغيرات نفسها يكون لها نوع, و القيم بكل تأكيد لها أنواع و هي أنواع المتغيرات الموجودة في اللغة, فمثلاً في ++C: int x; x = 5.0; // ERROR! كما تلاحظ, x نفسها لها نوع, و ليس القيم التي تحملها فقط. عندما نذهب مع الأسلوب الثاني في الـ Strong Typing ستقع مشكلة, و هي أن الأنوع أو الـ Type Annotations أو اسم النوع المكتوب أمام المتغير قد يكون معقداً بالنسبة للمستخدم و لكن معرفته أمر عادي جداً بالنسبة للمترجم. فمثلاً في ++C عندما نريد المرور على كل عنصر في set تحتوي على عناصر من نوع set هي الأخرى: std::set<std::set<int>> my_sets; ... for(std::set<std::set<int>>::const_iterator i = my_sets.begin(); i != my_sets.end(); ++i) { // Do something with my_sets elements! } لاحظ أننا كتبنا "Annotation" للمتغير i لنوع معقد دون فائدة, كان من الممكن أن يقوم المترجم بمعرفته. فمثلاً: std::set<std::set<int>> my_sets; ... for(auto i = my_sets.begin(); i != my_sets.end(); ++i) { // Do something with my_sets elements! } لاحظ كيف جعلت auto الكود مختصراً اكثر! و فوق كل ذلك نحن بمجرد النظر إلى الـ initializer الخاص بـ i عرفنا النوع بشكل عام, و تركنا تحديد النوع بشكل دقيق للمترجم. هذا هو الـ Type Inference باختصار. و هو كما قلنا سابقاً ميزة في اللغات الـ Very Strong و لكن ليس هناك منطق من وجوده أصلاً في لغة كـ Python أو لغة Weak كـ Perl مثلاً. تحياتي...
  25. أخ عمرو, في الأعلى قسمنا الـ Strongly Typed Languages إلى لغات تهتم بإعطاء نوع للقيم و المتغيرات, و أخرى "تخفف" هذه التشديد بإعطاء نوع للقيم و لكن المتغيرات تعامل على أنها أوعية. عندما نتكلم بشكل نظري, فإن الـ Weak Typing تعني أن القيم لا تنتمي إلى أنواع مختلفة. فمثلاً, في Perl: print("1"==1); سوف تخبرك اللغة بأنهما متساويان! هما بالتأكيد متساويان إن كان النوع غير مهم في اللغة أو بمعنى آخر Weak. باختصار, النوع لايدخل في تحديد "شرعية" العملية, لأن اللغة ستوفر طريقة أو حلاً وسطاً لتطبيق العملية على الطرفين. أخ متميز, بإذن الله الموضوع القادم سوف يكون عن هذا الأمر :) تحياتي...