PDA

View Full Version : کاربردهای goto



eshpilen
یک شنبه 27 آذر 1390, 23:19 عصر
حتما اساتید محترم میدونن که goto کاربردهای بجایی هم داره.
میشه گفت goto دستوری هست که میشه خیلی راحت ازش بد استفاده کرد، و در دوران های باستانی باعث ایجاد عادت ها و کدهای بسیار بد و ناخوانایی شده بود (چون اون موقع این مشکلات هنوز بقدر کافی شناخته و تحلیل و تبیین نشده بودن)، که نتیجتا منجر به نهضت ضد goto شد و goto مبدل گشت به یک تابو.
ولی استفاده های خوب و لازم از goto هم وجود دارن.

بنده یه مثال مفهومی میارم و لطفا تحلیل کنید و نظرتون رو بگید. ضمنا کاربردهای بجا و مفید دیگری از goto اگر سراغ دارید بیان بفرمایید.
البته مثال بنده در PHP هست، ولی خیلی ساده و روشنه و هر برنامه نویسی در هر زبانی باید بتونه براحتی بخونه و بفهمه. تقریبا Pseudocode هست.


<?php

if(cond1) goto s1;
if(cond2) goto s2;
if(cond3) goto s3;

//stage 1
:s1
...
...
...

//stage 2
:s2
...
...
...

//stage 3
:s3
...
...
...

?>
همونطور که میبینید ما یک فایل داریم که عملیات خاصی رو انجام میده و این عملیات خودش شامل 3 زیرعملیات یا 3 مرحله میشه. اما در فایل براساس شرایط خاصی عملیات رو از مرحله های مختلفی انجام میدیم. مثلا اگر شرط cond2 برقرار باشه نیازی نیست یا نباید مرحلهء اول انجام بشه و باید عملیات رو از مرحلهء دوم شروع کنیم.
بنظرم کدش واقعا خوانا و تمیز هست.

حالا سعی کنید همین رو بدون استفاده از goto بنویسید تا مقایسه کنیم.
منکه نتونستم بدون goto یک کد خواناتر و ساده تر و کوتاهتری رو ایجاد کنم. کلی هم ناخواناتر و پیچیده تر میشه.

خب این بحث و مثال اول در فروم دیگری بود که نظر بعضی ها این بود که به goto نیازی نیست و اگر کد خوب نوشته بشه ساختارهای دیگر بهتر و خواناتر هستن.
ولی من فکر میکنم بعکس goto کاربردهای برجسته ای داره و در بعضی موارد به طرز قابل توجهی باعث کاهش پیچیدگی و حجم کد و افزایش قابلیت خوانایی میشه.

syntiberium
دوشنبه 28 آذر 1390, 00:28 صبح
اگر فرض کنیم داخل شرط یک متغیر است که می تواند بین 1 تا 3 مقدار بگیرد :

<?php

//stage 1
if(x>0)
{
...
...
...
}
//stage 2
if(x>1)
{
...
...
...
}
//stage 3
if(x>2)
{
...
...
...
}
?>



:لبخندساده:

میلاد قاضی پور
دوشنبه 28 آذر 1390, 03:58 صبح
بنده یه مثال مفهومی میارم و لطفا تحلیل کنید و نظرتون رو بگید. ضمنا کاربردهای بجا و مفید دیگری از goto اگر سراغ دارید بیان بفرمایید.
این مثالی که شما زدید اتفاقا فکر میکنم جزو مواردی هست که نباید از goto استفاده بشه . از goto زمانی استفاده میشه که بعنوان مثال شما میخواید از (ifهای تودرتو) استفاده نکنید یا جایی که لازم نیست شرطی رو چک کنید . وگرنه کد شما رو میشه با سوئیچ کیس همنوشت خیلی هم کوتاه تر میشه.
شما یکسری شرط یا سوئیچ نوشتید و میدونید که اگر کیس n ام اجرا شد حتما کیسهای n+4ام و n+5 ام هم قابل اجرا هست و میخواید اینکار انجام بشه . در این حالت شما میاید قبل از break مربوط به کیس ان ام از goto استفاده میکنید برای پرش به کیس n+4 و در اون هم یک پرش میکنید به کیس n+5. به این شکل شما میتونیدکدهایی رو که برای رسیدن بهشون نیاز به بررسی شرط داشتن رو سریعن در دسترس خودتون داشته باشید .

مصطفی ساتکی
دوشنبه 28 آذر 1390, 08:25 صبح
من از goto اغلب در هنگام تست استفاده می کنم زمانیکه تو function های بزرگم بخام leakage رو تشخیص بدم چون engine ما function base و if ها و for ها تو در تویی هم وجود داره و leakage ها معولا داخل همچین کد هایی رخ می ده و در پایان روال معمولا اکثر حافظه ها آزاد میشه حدوداً 80 درصد و بقیش ما بین روال. حالا ما می خایم بدون اینکه کد رو تغییر بدیم تشخیص بدیم کدام function فراخوانی شده leakage داره البته توالی فراخوانی function ها تو engine مهمه یعنی نمی تونید هر چند خط یا خطوطی رو که مایلید comment کنید باید همشون فراخوانی شن من در همچین مواردی یک label قبل اون release 80% میزارم بعد از بالا بعد اون جاهایی که مشکوک به leakage هستند goto میزازم به این ترتیب به راحتی leakage تو همچین روال بزرگی رو پیدا می کنم بدون اینکه تغییری تو کد حاصل بشه.

eshpilen
دوشنبه 28 آذر 1390, 12:15 عصر
اگر فرض کنیم داخل شرط یک متغیر است که می تواند بین 1 تا 3 مقدار بگیرد :
...
:لبخندساده:
منطق کدی که شما گذاشتی معادل منطق کد بنده نیست.
بطور مثال کد بنده میگه اگر شرط اول برقرار بود تمام مراحل انجام بشن. یعنی درصورت درستی یک شرط دیگه به مقدار شرطهای بعدی کاری نداره. اما در کد شما هر مرحله به شرطی اجرا میشه که شرط خودش برقرار باشه.
یعنی مثلا اگر شرط اول شما برقرار باشه stage 1 اجرا میشه اما بعدش اگر شرط چک شده در stage های دیگه برقرار نباشه اون کدها اجرا نمیشن.

ضمنا به فرض اگر هم کد شما معادل کد بنده بود، نمیشد گفت حتما باید از اون بجای goto استفاده کنیم. چون بنظر خود بنده کد اول اگر خواناتر و کوتاهتر و تمیزتر نباشه حداقل ناخواناتر هم نیست (بنظر منکه نمیاد و فکر نمیکنم بشه چنین چیزی رو بسادگی اثبات کرد). تازه یوقت شاید بهتر باشه شرط ها رو به شکلی که پیاده سازی با goto داره، در ابتدای فایل مجتمع کنیم.

eshpilen
دوشنبه 28 آذر 1390, 12:31 عصر
این مثالی که شما زدید اتفاقا فکر میکنم جزو مواردی هست که نباید از goto استفاده بشه .
چرا؟

از goto زمانی استفاده میشه که بعنوان مثال شما میخواید از (ifهای تودرتو) استفاده نکنید یا جایی که لازم نیست شرطی رو چک کنید .آره دقیقا فکر کنم نظر بنده رو گفتی. یعنی این یکی از موارد کاربرد واضحش هست که بنده هم در فروم دیگر مطرح کردم. منتها چون کد مثال این حالت یه مقدار حجیم و پیچیده میشد ترجیح دادم کد حالت ساده تری رو بذارم.


وگرنه کد شما رو میشه با سوئیچ کیس همنوشت خیلی هم کوتاه تر میشه. در شرطهای سویچ فقط میشه تساوی رو چک کرد. انواع شرطهای دیگر و شرطهای ترکیبی ممکن نیستن تاجاییکه میدونم.
تازه اونم فقط میتونید تساوی مقدار فقط یک متغییر خاص رو که در ابتدا مشخص میکنید با مقدارهای مختلف چک کنید.
یعنی شرط سویچ خیلی محدود شده هست و نمیشه در خیلی موارد ازش استفاده کرد (در سناریوهای خیلی محدودی از کل سناریوهای ممکن قابل استفاده هست).


شما یکسری شرط یا سوئیچ نوشتید و میدونید که اگر کیس n ام اجرا شد حتما کیسهای n+4ام و n+5 ام هم قابل اجرا هست و میخواید اینکار انجام بشه . در این حالت شما میاید قبل از break مربوط به کیس ان ام از goto استفاده میکنید برای پرش به کیس n+4 و در اون هم یک پرش میکنید به کیس n+5. به این شکل شما میتونیدکدهایی رو که برای رسیدن بهشون نیاز به بررسی شرط داشتن رو سریعن در دسترس خودتون داشته باشید .بنظرم حالت و روش شما زیادی پیچیده هست و احتمالا خوانایی رو کم و بیش کم میکنه.
ضمنا ارتباط خاصی با حالت و مثال ذکر شدهء خودم نمیبینم.
لطفا روی همون مورد تمرکز کنید چون ساده تر و واضح تره.
در اون مورد ساده کد بنده خیلی ساده تر و کوتاهتر و واضح تره. نه؟

eshpilen
دوشنبه 28 آذر 1390, 12:37 عصر
من از goto اغلب در هنگام تست استفاده می کنم زمانیکه تو function های بزرگم بخام leakage رو تشخیص بدم چون engine ما function base و if ها و for ها تو در تویی هم وجود داره و leakage ها معولا داخل همچین کد هایی رخ می ده و در پایان روال معمولا اکثر حافظه ها آزاد میشه حدوداً 80 درصد و بقیش ما بین روال. حالا ما می خایم بدون اینکه کد رو تغییر بدیم تشخیص بدیم کدام function فراخوانی شده leakage داره البته توالی فراخوانی function ها تو engine مهمه یعنی نمی تونید هر چند خط یا خطوطی رو که مایلید comment کنید باید همشون فراخوانی شن من در همچین مواردی یک label قبل اون release 80% میزارم بعد از بالا بعد اون جاهایی که مشکوک به leakage هستند goto میزازم به این ترتیب به راحتی leakage تو همچین روال بزرگی رو پیدا می کنم بدون اینکه تغییری تو کد حاصل بشه.
بنظرم کاربرد واقعی و جالبی رو مطرح کردید، اما مشخص هست که مربوط به زمان توسعه میشه و فقط برای تست و باگیابی کاربرد داره.
من میگم goto کاربردهای واقعی در کد اصلی برنامه داره و بحث اصلیم این بود. براش مثال هم آوردم. شاید بعدا مثال از حالتهای دیگری رو هم گذاشتم.
به هر جهت در این تاپیک از هر گونه کاربرد و ایده ای در ارتباط با goto استقبال میشه و باعث افزایش محتوای تاپیک و استفادهء همه هست.
ممنون.

eshpilen
دوشنبه 28 آذر 1390, 12:51 عصر
بعضی ها طوری صحبت میکنن انگار خود دستور یا لغت goto مشکلی داره و باید سعی کنیم ازش پرهیز کنیم.
درحالیکه در همون مثال سادهء بنده نمیشه هیچ ایراد خاصی ازش گرفت. تازه میتونم بگم کم و بیش یکسری مزایا و خواص خاص خودش رو هم داره.
هیچ دلیلی بنظرم نمیرسه که بخوایم چنین حالتهایی رو به روش دیگری پیاده سازی کنیم. شما کد معادلی بنظرتون میرسه بگید تا بررسیش کنیم.
این استفاده های بد از goto هست که مشکل دارن، ولی خود goto هیچ چیز بدی نیست. بنظر بنده در بعضی یا حتی خیلی جاها goto میتونه به شکلی بکار بره که از ساختارهای دیگر خواناتر باشه و به کوتاه و ساده شدن کد و راحتی مدیریت و ویرایش اون کمک کنه.

syntiberium
دوشنبه 28 آذر 1390, 16:42 عصر
eshpilen:
اگر شرط اول شما برقرار باشه stage 1 اجرا میشه اما بعدش اگر شرط چک شده در stage های دیگه برقرار نباشه اون کدها اجرا نمیشن.
ببخشید من یکمی اشتباه کردم و الان در کد زیر درستش کردم . الان اگر شما x را 1 مقدار بدهید x هم کوچک تر از 2 است و هم کوچک تر از 3 و 4 پس هر سه قسمت اجرا می شوند اما اگر x را 2 مقدار بدهید x دیگر کوچک تر از 2 نیست پس مرحله ی اول اجرا نمی شه اما مرحله ی دوم و سوم اجرا می شوند . (لطفا یکمی روی کد و توضیحات من trace کنید تا متوجه شوید.)


<?php

//stage 1
if(x<2)
{
...
...
...
}
//stage 2
if(x<3)
{
...
...
...
}
//stage 3
if(x<4)
{
...
...
...
}
?>

syntiberium
دوشنبه 28 آذر 1390, 17:25 عصر
eshpilen:
بعضی ها طوری صحبت میکنن انگار خود دستور یا لغت goto مشکلی داره و باید سعی کنیم ازش پرهیز کنیم.

از نظر من goto فقط یک کاربرد داره و اون هم پیچیده کردن کد های نرم افزار برای ایجاد امنیت نرم افزار . من از وقتی برنامه سازی رو به طور جدی شروع کردم تا حالا حتی از یه دونه goto هم استفاده نکردم اما شاید وقتی بخوام یک پروژه را وارد بازار کنم قبلش برای ناخوانا تر شدن کدهام و ایجاد امنیت ازش استفاده کنم چون با goto می تونیم به طرز فجیعی کد هامون را پیچیده کنیم طوری که مغز اون حکری که می خواد از کدهامون سر در بیاره منفجر بشه :شیطان: .

eshpilen
دوشنبه 28 آذر 1390, 18:09 عصر
ببخشید من یکمی اشتباه کردم و الان در کد زیر درستش کردم . الان اگر شما x را 1 مقدار بدهید x هم کوچک تر از 2 است و هم کوچک تر از 3 و 4 پس هر سه قسمت اجرا می شوند اما اگر x را 2 مقدار بدهید x دیگر کوچک تر از 2 نیست پس مرحله ی اول اجرا نمی شه اما مرحله ی دوم و سوم اجرا می شوند . (لطفا یکمی روی کد و توضیحات من trace کنید تا متوجه شوید.)
...

زحمت کشیدی اما این بازم برابر با Pseudocode بنده نیست.
چون شما شرطهای خاصی رو روی یک متغییر خاص تست میکنی.
ولی من همچین محدودیتی وضع نکردم. هر شرط میتونه هرچیزی باشه بنا به منطق و پارامترهای برنامه و لزوما همهء شرطها در ارتباط با یک متغییر مشترک نیستن. شرطها میتونن هرچیزی باشن. هر شرط بصورت جداگانه.
حتی وقتی شرطهای ساده روی یک متغییر مشترک داری هم باز دلیل نمیشه بشه اینطور نوشت. مثلا شاید یک شرط چک بکنه که آیا متغییر کوچکتر یا بزرگتر از عدد خاصی هست و اگر این شرط صحیح نبود یک شرط دیگه چک بکنه که آیا مقدار متغییر زوج هست یا خیر. یا هر شرط ممکنه با متغییرهای متفاوت دیگری هم درگیر باشه.

بطور کلی شما شرطها و پارامترها رو طوری ترتیب دادید که بشه کد رو اونطور نوشت. درحالیکه در شرایط واقعی براحتی ممکنه اینطور نباشه یا نشه به این سادگی نوشت.

یک مورد خاص و محدود رو نمیشه به حالت کلی تری تعمیم داد. حالتی که بنده مطرح کردم نسبت به کدی که شما نوشتید خیلی کلی تر هست و شرایط و پارامترهای خیلی بیشتری رو پوشش میده.

میلاد قاضی پور
دوشنبه 28 آذر 1390, 19:08 عصر
من این مطلب رو در کتاب مرجع سیشارپ پیدا کردم :



The goto Statement
The goto statement allows you to jump directly to another specified line in the program, indicated by a
label (this is just an identifier followed by a colon):
goto Label1;
Console.WriteLine(“This won’t be executed”);
Label1:
Console.WriteLine(“Continuing execution from here”);
A couple of restrictions are involved with goto . You can ’ t jump into a block of code such as a for loop,
you can ’ t jump out of a class, and you can ’ t exit a finally block after try...catch blocks (Chapter 14 ,
“ Errors and Exceptions, ” looks at exception handling with try...catch...finally ).
The reputation of the goto statement probably precedes it, and in most circumstances, its use is sternly
frowned upon. In general, it certainly doesn ’ t conform to good object - oriented programming practice.
However, there is one place where it is quite handy: jumping between cases in a switch statement,
particularly because C#‎ ’ s switch is so strict on fall - through..

eshpilen
دوشنبه 28 آذر 1390, 19:47 عصر
فکر کنم منظورش این بوده که در سویچ های سی شارپ نمیشه دستور break رو از case ها حذف کرد و بنابراین نمیشه با اجرای یک کیس کیس های بعد از اونم اجرا بشن. درحالیکه در خیلی زبانهای دیگر این محدودیت نیست و میتونیم break هرکدام از case ها رو که میخوایم برداریم (*).

*: آره الان رفرنسش (http://msdn.microsoft.com/en-us/library/aa664749%28v=vs.71%29.aspx) رو مطالعه کردم و دقیقا همینطوره.

eshpilen
جمعه 02 دی 1390, 22:41 عصر
راستی یکی از سناریوهای واقعی بنده برای goto اینه:

<?php

if(!isset($_POST['submit'])) goto form;
...
if(another_cond) goto form;
...
if(another_cond) goto form;
...

:form
include 'my_form.php';

?>
فکر میکنم واضح باشه و نیازی به توضیح نیست.
حالا بنظر شما آیا این روش غلطه و چرا و چه آلترناتیوی رو پیشنهاد میکنید.

eshpilen
جمعه 02 دی 1390, 22:43 عصر
switch (true) {

case ($totaltime < 1):
echo "That was fast!";
break;

case ($totaltime > 1):
echo "Not fast!";
break;

case ($totaltime > 10):
echo "That's slooooow";
break;
}




طرز استفاده جالب بود (و به گمانم غیراستاندارد و بنابراین احتمالا غیراصولی)، ولی یه کد معادل با کدی که من نوشتم بنویس.
سناریوی های من اصلا شبیه این نیست.

اگر به کد من دقت کنی، درصورتی که هر شرط برقرار باشه از اجرای بقیهء کدها صرفنظر میشه، اما اگر شرط برقرار نباشه اجرا از خط بعدی ادامه پیدا میکنه.
اما این سویچ که نوشتی مثلا اگر شرط کیس اول برقرار نباشه و شرط کیس دوم برقرار باشه، فقط کدهای کیس دوم اجرا میشن. درحالیکه کیس اول هم باید اجرا میشد، و بعد از اجرای کدهای کیس اول و کیس دوم به ترتیب، شرط کیس سوم هم باید چک بشه و اگر برقرار بود کیس سوم هم اجرا بشه.

فکر کنم این رو یا نمیشه با کیس به این شکل نوشت یا اگرم بشه حجیم تر و پیچیده تر و ناخواناتر از goto میشه.
مثلا خواناترین راهی که الان بنظر بنده میرسه اینه که کدهای کیس های قبل از هر کیس رو در اون کیس هم تکرار کنیم. ولی این صرفا زیاد کردن بیخودی حجم کد هست و انعطاف و قابلیت گسترش و نگهداری برنامه رو هم دشوارتر میکنه. مثلا باید هروقت کدهای کیس های قبلی تغییر کردن یا کیس هایی کم و زیاد شدن کد کیسهای بعدی رو هم آپدیت کنیم.

قضیه همینه که تا اسم goto میاد همه به فکر فرار ازش هستن. درحالیکه باید نگاه کنن ببینن آیا واقعا در خوانایی اون مشکلی هست یا نه و آیا ساختار بهتری وجود داره و چرا. چون مشکل از این مسئله هست، نه صرفا اسم و شکل ساختار استفاده از یک دستور. غیر از اینه؟
اون نمونه کدی که من نوشتم بنظرم کوتاهترین و خواناترین شکل ممکن هست. اگر تونستید یه چیزی بهتر از اون بیارید اونوقت درسته. کدی که همون منطق رو داشته باشه و همون کار رو انجام بده، ولی واضحا بهتر باشه (با دلیل منطقی! نه اینکه صرفا اسم و شکلش goto نباشه). حتی تونستید در همون حد خوانا هم بیارید باز خودش پیشرفتی هست! چون هنوز کسی قادر به این کار نشده.
کدی که با goto نوشته شده بنظرم از نظر امتیاز در حداکثر قرار داره. چون بنظرم تاحداکثر ممکن کوتاه و ساده و روشنه. حتی همون عبارت های goto form خیلی قشنگ همون موقع و همون جا که میخونی روشن میکنن که بقیهء ماجرا چیه (اینکلود کردن و نمایش فرم). یعنی خصیصهء مثبت self document رو هم داره.
همهء اینا باعث خوانایی بالا میشن. و میتونم بگم حتی از نظرهای دیگه مثل پرفورمنس هم مزیت داره. بنابراین واقعا چه دلیلی وجود داره که ما از چنین کدی استفاده نکنیم؟ چه ساختار دیگری چرا بهتر از چنین کدی هست؟