PDA

View Full Version : سوال: علت تعریف بعضی از پارامترهای توابع به صورت Const چیست؟



JalaliMehr
چهارشنبه 06 مرداد 1389, 09:53 صبح
لطفاً ميشه بفرمايد فرق اين دو چيه.

procedure test1(const count : integer);
procedure test2(count : integer);

مهران رسا
چهارشنبه 06 مرداد 1389, 10:16 صبح
لطفاً ميشه بفرمايد فرق اين دو چيه.

procedure test1(const count : integer);
procedure test2(count : integer);




http://www.drbob42.com/delphi4/defparam.htm

JalaliMehr
چهارشنبه 06 مرداد 1389, 10:56 صبح
والا من نفهميدم شما با چه منطقي آدرس اين لينك رو اينا گذاشتيد. اي كاش يكمي رو سوال من تامل مي كرديد.درسته ستاره ندارم و دليل نميشه سوالم اينطوري جواب بديد.
لطفاً دوستاني كه فرق اين دو prototype رو ميدونند نظرات شونو اعلام كنند

Felony
چهارشنبه 06 مرداد 1389, 11:08 صبح
در کد زیر شما ورودی تابع رو به صورت یک ثابت تعریف کردید ، پس نمیتونید داخل بدنه تابع هیچ تغییری درش ایجاد کنید و فقط میتونید اطلاعات داخل اون رو بخونید :


procedure test1(const count : integer);

مثلا کد زیر مشکل داره چون سعی بر اضافه کردن یک واحد به پارامتر ورودی Count داریم در صورتی که Count به صورت یک ثابت تعریف شده :

procedure test1(const count : integer);
begin
Inc(Count);
end;

ولی در کد زیر میشه در داخل بدنه تابع به پارامتر ورودی دسترسی برای تغییر داشت :

procedure test2(count : integer);

مثلا میشه یه واحد داخل بدنه تابع بهش اضافه کرد :

procedure test2(count : integer);
begin
Inc(count);
end;

JalaliMehr
چهارشنبه 06 مرداد 1389, 11:44 صبح
در کد زیر شما ورودی تابع رو به صورت یک ثابت تعریف کردید ، پس نمیتونید داخل بدنه تابع هیچ تغییری درش ایجاد کنید و فقط میتونید اطلاعات داخل اون رو بخونید :

کد:
procedure test1(const count : integer);
مثلا کد زیر مشکل داره چون سعی بر اضافه کردن یک واحد به پارامتر ورودی Count داریم در صورتی که Count به صورت یک ثابت تعریف شده :
کد:
procedure test1(const count : integer);
begin
Inc(Count);
end;
ولی در کد زیر میشه در داخل بدنه تابع به پارامتر ورودی دسترسی برای تغییر داشت :
کد:
procedure test2(count : integer);
مثلا میشه یه واحد داخل بدنه تابع بهش اضافه کرد :
کد:
procedure test2(count : integer);
begin
Inc(count);
end;


اينكه از كلمه كليدي const خودش معلومه كه نميشه تغييرش داد .آخه بدون const هم رو تغيير ميده تفوتي نداره هيچ تاثيري رو روند كار نداره.
حال سوالم اينكه چرا دلفي وقتي كلاس رو با Shift+Ctrl+C تكميل مي كنه متغير هاي وردي مربوط به Set رو قبل از آنها const قرار ميده .از اين متعجبم

Felony
چهارشنبه 06 مرداد 1389, 12:35 عصر
اينكه از كلمه كليدي const خودش معلومه كه نميشه تغييرش داد .آخه بدون const هم رو تغيير ميده تفوتي نداره هيچ تاثيري رو روند كار نداره.
تاثیری نداره ؟!
مثل اینکه روند و کدهای پروژه های بزرگ رو ندیدید ، وقتی تو یک تابع که ممکنه 1000 خط باشه این وسط پارامتری که ورودی بوده به اشتباه مقدارش تغییر کنه ممکنه 1000 تا مشکل در روند اجرای کد به وجود بیاد و برای دیباگش باید کلی وقت بزارید ، ولی با تعریف پارامتر با Const صریحا اعلام میکنید که حق تغییر در مقدار پارامتر داده نشده و کامپایلر اجازه این اشتباه رو نمیده .


حال سوالم اينكه چرا دلفي وقتي كلاس رو با Shift+Ctrl+C تكميل مي كنه متغير هاي وردي مربوط به Set رو قبل از آنها const قرار ميده .از اين متعجبم
جوابش رو در بالا دادم .

Saeed_m_Farid
چهارشنبه 06 مرداد 1389, 12:37 عصر
حال سوالم اينكه چرا دلفي وقتي كلاس رو با Shift+Ctrl+C تكميل مي كنه متغير هاي وردي مربوط به Set رو قبل از آنها const قرار ميده .از اين متعجبم
برای اینکه مطمئن بشه که داخل procedure ای که شما برای write مشخص کردید مقدار پارامتر ورودی رو تغییر نمیدین، چون معمولاً یا یه Field تو کلاس میذارن که اون رو برای write قرار میدن (مثلاً FTestParam: Integer) و یا اگه خواستید پروسیجر تعریف کنید واسه Write ا Property، معمولاً اگه داخل procedure تغییرش بدین، نتایج غیرمنتظره ای رخ میده، نخواستید می تونید برش دارید، اونوقت اگه پارامتر ورودی رو تغییر دادین کامپایلر Error نمیده تا شما متوجه بشید. فقط همین!

JalaliMehr
چهارشنبه 06 مرداد 1389, 13:53 عصر
مثل اینکه روند و کدهای پروژه های بزرگ رو ندیدید ، وقتی تو یک تابع که ممکنه 1000 خط باشه این وسط پارامتری که ورودی بوده به اشتباه مقدارش تغییر کنه ممکنه 1000 تا مشکل در روند اجرای کد به وجود بیاد و برای دیباگش باید کلی وقت بزارید ، ولی با تعریف پارامتر با Const صریحا اعلام میکنید که حق تغییر در مقدار پارامتر داده نشده و کامپایلر اجازه این اشتباه رو نمیده .
پس چرا خودمان ميخواهيم يك procedure تعريف كنيم و با اينكه هم مي دانيم در داخل procedure تغييرش نخواهيم داد چرا const نمي زاريد.معمولاً در برنامه نويسي كمتر تو prototype كلمه كليدي const مي زارن.


برای اینکه مطمئن بشه که داخل procedure ای که شما برای write مشخص کردید مقدار پارامتر ورودی رو تغییر نمیدین، چون معمولاً یا یه Field تو کلاس میذارن که اون رو برای write قرار میدن (مثلاً FTestParam: Integer) و یا اگه خواستید پروسیجر تعریف کنید واسه Write ا Property، معمولاً اگه داخل procedure تغییرش بدین، نتایج غیرمنتظره ای رخ میده، نخواستید می تونید برش دارید، اونوقت اگه پارامتر ورودی رو تغییر دادین کامپایلر Error نمیده تا شما متوجه بشید. فقط همین
خوب تغيير بديم حواسمون كه بهش هست.اگر اينطوري بخايم تصور كنيم پس C++ كارهاي حرفه اي اگر اينطوري فكر كنن با اون حجم pointer حواسشون نباشه واويلاست.

Felony
چهارشنبه 06 مرداد 1389, 14:10 عصر
پس چرا خودمان ميخواهيم يك procedure تعريف كنيم و با اينكه هم مي دانيم در داخل procedure تغييرش نخواهيم داد چرا const نمي زاريد.معمولاً در برنامه نويسي كمتر تو prototype كلمه كليدي const مي زارن.
جمع نبندید ! اینکه شما از این قاعده پیروی نمیکنید دلیل نمیشه همه اینطور باشن ، اصولش این هست ، میخواین رعایت کنید میخواین رعایت نکنید ، عواقبش در آخر گریبان خودتون یا بنده خدایی که میخواد پروژه رو توسعه بده رو میگیره ، وقتی تو یک روال یا تابع فقط نیاز به خواندن پارامتر دارید بهتره به صورت Const تعریف بشه .


خوب تغيير بديم حواسمون كه بهش هست.اگر اينطوري بخايم تصور كنيم پس C++‎‎ كارهاي حرفه اي اگر اينطوري فكر كنن با اون حجم pointer حواسشون نباشه واويلاست.
حواستون به چی هست ؟ وقتی ابزاری برای راحتی شما در اختیارتون گزاشته شده که خودش حواسش به این چیزها هست بیکارید که خودتون این روند رو کنترل کنید ؟

در مورد ++C هم این موارد رعایت میشه ولی با قواعد خاص خودش ، در غیر این صورت توسعه یک پروژه مثل سیستم عامل یک آرزو بود ... !

JalaliMehr
چهارشنبه 06 مرداد 1389, 14:53 عصر
جمع نبندید ! اینکه شما از این قاعده پیروی نمیکنید دلیل نمیشه همه اینطور باشن ، اصولش این هست ، میخواین رعایت کنید میخواین رعایت نکنید ، عواقبش در آخر گریبان خودتون یا بنده خدایی که میخواد پروژه رو توسعه بده رو میگیره
من جمع نبستم .فقط يك واقعيت تو برنامه تويسي رو خدمتون عرض كردم.شما به اين پست هاي خودتون نگاه كنيد نيازي نبود پارامترها تغيير كنند ولي const تعريف نشدن.
تو اين تاپيك http://barnamenevis.org/forum/showthread.php?t=233642 پست شماره 2
تو اين تاپيك http://barnamenevis.org/forum/showthread.php?t=233378 پست شماره 2
و .... الي آخر
نبايستي رو يه مطلب تعصب نشون بديم.پس اگر به حرف خودتون استناد كنيم شما اصولي برنامه نويسي.


غیر این صورت توسعه یک پروژه مثل سیستم عامل یک آرزو بود
نمي دونم اين به كجاي سوال من ربط داشت.
به هر حال از جوابتون ممنون

مصطفی ساتکی
چهارشنبه 06 مرداد 1389, 15:40 عصر
پارامتر از نوع Const چه تو Delphi و چه تو C Bulider در واقع به صورت reference عمل مي كنن. يعني كامپايلر زمانيكه Const رو مي بينه مجدداً متغير مبداً كه بيرون از رويه قرار داره رو
در متغير مقصد كپي نمي كنه بلكه به اون ارجاع مي كنه.اين نوع پارامتر هاي در توابعي كه در آنها رشته يا ركورد به عنوان ورودي تابع استفاده
ميشه كاربرد داره .
شما اگر بخايد به كرات يك رويه رو فراخواني كنيد كه پارامترهاي رشته اي و ركورد داشته باشه و در داخل رويه هم تغيير نمي كند راه حلش همين استفاده از Const مي باشد.
اگر نياز به تغيير باشه اگر سرعت مطلوبي نياز داشته باشيد يا بايستي از out استفاده كنيد با Pointer.
دوست عزيزمون كه در مورد property ها فرمودند كه به علت اينكه در رويه مورد نظر كسي نتونه تغييرش بده يك از علتهاشه.دليل ديگر اينه كه در پرو‍ژه هاي شبيه سازي كه بسيار زمانگير
و ميزان محاسبات و پارامترها و فراخواني ها زياد در اونجا اگر اين قضيه رعيت نشه سربار زياد رو برنامه متحمل ميشه.
به اين هم يه مثال عيني در اين مورد :

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
ttestrec = record
a,b ,c ,d : Integer;
z,y,x : Extended;
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
public
end;

var
Form1: TForm1;

implementation

{$R *.dfm}
procedure Proc1(const count : ttestrec);
var k : Integer;
begin
k := k + count.a+count.b+count.c;

end;
procedure test2(count : ttestrec);
var k : Integer;
begin
k := k + count.a+count.b+count.c;
end;

procedure TForm1.Button1Click(Sender: TObject);
var t : LongInt;
i : Integer;
forcount : Integer;
k ,b : ttestrec;
begin
t := GetTickCount;
forcount := 10000000000;
k.a := 100;
k.z := 100;
for i := 0 to forcount - 1 do
Proc1(k);
ShowMessage(IntToStr(GetTickCount-t));

b.a := 100;
b.z := 100;

t := GetTickCount;
for i := 0 to forcount - 1 do
test2(b);
ShowMessage(IntToStr(GetTickCount-t));

end;



end.

Felony
چهارشنبه 06 مرداد 1389, 15:47 عصر
من جمع نبستم .فقط يك واقعيت تو برنامه تويسي رو خدمتون عرض كردم.شما به اين پست هاي خودتون نگاه كنيد نيازي نبود پارامترها تغيير كنند ولي const تعريف نشدن.
تو اين تاپيك http://barnamenevis.org/forum/showthread.php?t=233642 پست شماره 2
تو اين تاپيك http://barnamenevis.org/forum/showthread.php?t=233378 پست شماره 2
و .... الي آخر
نبايستي رو يه مطلب تعصب نشون بديم.پس اگر به حرف خودتون استناد كنيم شما اصولي برنامه نويسي.
بله من هم میدونم زیاد رعابت نمیشه ( همه جا هم نیاز به رعایت شدن نیست ولی بهتره رعایت بشه )، در مورد لینک هایی هم که دادید اون ها نمونه سورس هایی هستن که برای کاربران نوشتم ( تعداد خطوط برنامه بسیار کمه ) پس به راحتی با یک نگاه میشه کد رو کنترل کرد ، من تا جایی که یادم باشه در برنامه هایی که مینویسم نکات رو رعایت میکنم و گاهی اوقات هم که کدهای قبلیم رو بررسی میکنم اگر از لحاظ اصول کدنویسی مشکلی ببینم اصلاحش میکنم .


نمي دونم اين به كجاي سوال من ربط داشت.
ربطش این هست که سیستم عاملی مثل ویندوز دارای چند میلیون خط کد هست که اگر قرار باشه به قول شما خود برنامه نویس حواسش جمع باشه و خطا نکنه بعد از این پروژه مغزش فسیل میشه !

موفق باشید .

Felony
چهارشنبه 06 مرداد 1389, 16:26 عصر
این هم توضیحاتی از یک منبع زبان اصلی :


Constant value parameters
For code clarity, and performance, it is often wise to declare arguments that are only ever read by a subroutine as constants. This is done with the const prefix. It can be used even when a non-constant parameter is passed. It simply means that the parameter is only ever read by the subroutine.

لینک منبع (http://www.delphibasics.co.uk/Article.asp?Name=Routines)

مصطفی ساتکی
چهارشنبه 06 مرداد 1389, 17:25 عصر
بهترين منبع براي اين دست از مسائل help خود Delphi و C Bulider كه شما مي تونيد به اونا استناد كنيد.
هر چند بقول آقاي كشاورز اونا هم چند مدتيه در زمينه Help و مستندات كم كار مي كنن.

Felony
چهارشنبه 06 مرداد 1389, 21:45 عصر
پارامتر از نوع Const چه تو Delphi و چه تو C Bulider در واقع به صورت reference عمل مي كنن.
ولی اینطور نیست ، پارامتر هایی که به صورت Const تعریف میشن Byval هستن و فقط نمیشه مقدار پارامتر رو در داخل بدنه تابع تغییر داد مگر اینکه یک شئ رو بهش ارجاء بدید و خواصش رو تغییر بدید .

مصطفی ساتکی
چهارشنبه 06 مرداد 1389, 23:34 عصر
ولی اینطور نیست ، پارامتر هایی که به صورت Const تعریف میشن Byval هستن و فقط نمیشه مقدار پارامتر رو در داخل بدنه تابع تغییر داد مگر اینکه یک شئ رو بهش ارجاء بدید و خواصش رو تغییر بدید .
دوست عزيز اون مثالي كه بالا گذاشتم رو تست كرديد.اگر value باشه بايستي كپي بشه كه در مواردي كه توضيح دادم خودشو نشون ميده و زمانگيره.اينا جز موارد مشترك بين delphi و C Builder .
مثال رو احرا كنيد تا قضيه براتون روشن شه.

Felony
پنج شنبه 07 مرداد 1389, 05:38 صبح
دوست عزيز اون مثالي كه بالا گذاشتم رو تست كرديد.اگر value باشه بايستي كپي بشه كه در مواردي كه توضيح دادم خودشو نشون ميده و زمانگيره.اينا جز موارد مشترك بين delphi و C Builder .
مثال رو احرا كنيد تا قضيه براتون روشن شه.

حرف شما در مورد بهینه شدن کد درسته ، ولی در مورد ارسال با ByRefrence نه ، من تو راهنمای دلفی هم نگاه کردم ، طبق گفته Help دلفی :

Constant Parameters
A constant (const) parameter is like a local constant or read-only variable. Constant parameters are similar to value parameters, except that you can't assign a value to a constant parameter within the body of a procedure or function, nor can you pass one as a var parameter to another routine. (But when you pass an object reference as a constant parameter, you can still modify the object's properties.)

Using const allows the compiler to optimize code for structured - and string-type parameters. It also provides a safeguard against unintentionally passing a parameter by reference to another routine.
در بالا همون جایی که قرمز کردم نوشته شده که پارامتر ها به صورت Value ارسال میشن و فقط نمیشه مقدارشون رو داخل بدنه تابع تغییر داد ، پس نتیجه این میشه که ارسال به صورت ByVal هست و اما در آخر به نکته ای که شما گفتید اشاره کرده و گفته در اون مورد خاص بهینه تر عمل میکنه .

البته شاید هم من اشتباه میکنم و درست متوجه نشدم .

مصطفی ساتکی
پنج شنبه 07 مرداد 1389, 09:36 صبح
دوست عزيز من هم فقط با همين كامپايلر كار نمي كنم.نوشته Similar .اگر value بود ديگه similar نمي نوشت .منظورش اينه اگر مي نوشت reference بعدش سوال پيش ميمود كه چرا نميشه محتواش رو تغيير داد. اگه value باشه بايستي كليه محتوا رو كپي كنه كه اون زمانگير.دلفي out به صراحت اعلام كرده كه از نوع reference حالا جهت اطمينان بجاي const كلمه out رو بزار ميبيني كه از نظر زماني مشابهند.
آخه فرمايشي كه شما مي كنيد const فقط مخصوص دلفي نيست C Bulider ، C، ‍C++‎، java همه دارن به همين شكل عمل مي كن.تو اون زباني شناسه ارجاع(&) داريم ولي دلفي يه جور ديگه پيادش كرده.
به هر حال گفتني ها رو من گفتم قبولش باشماست.

vcldeveloper
دوشنبه 11 مرداد 1389, 04:32 صبح
دوست عزيز من هم فقط با همين كامپايلر كار نمي كنم.نوشته Similar .اگر value بود ديگه similar نمي نوشت .منظورش اينه اگر مي نوشت reference بعدش سوال پيش ميمود كه چرا نميشه محتواش رو تغيير داد. اگه value باشه بايستي كليه محتوا رو كپي كنه كه اون زمانگير.
Const اکثر نوع های داده را به صورت by Value منتقل میکنه، فقط برای آرایه ها، و رکوردها، از by reference استفاده میکنه، و البته استفاده از اون برای string و dynamic array هم باعث میشه که یکسری کدهای مربوط به کنترل reference-counter اونها تولید نشه، و کد Optimized تری به دست بیاد.

در لینک زیر درباره اش توضیح دادم:
http://vcldeveloper.com/articles/different-function-parameter-modifiers-in-delphi/

bootshow
دوشنبه 11 مرداد 1389, 21:33 عصر
در ++C وقتیکه متغیری از نوع شیئ را به تابع میفرستیم یک کپی از آن ساخته میشود(باعث افزایش زمان فراخوانی تابع میشود) و پس از خروج از تابع نابود کننده کپی صدا زده میشود که باعث خرابی اشاره گرها و متغیرهای استاتیک میشود.
(چون این نکته را در کتاب خواندم و مطمئنم درسته اینجا نوشتم.ولی در دلفی فکر کنم متغیر کلاس بصورت اشاره گر فرستاده بشه؟!)
صحبتهای دوستان از نگاهی دیگر:
به همین دلیل اگر رشته یا متغیری که طول آن زیاد باشه وقتی که بصورت پارامتر به تابع فرستاده میشه یک کپی از آن ساخته میشه و زمان اجرای تابع را زیاد میکند.بهمین دلیل اگر از Const استفاده کنیم فقط آدرس متغیر فرستاده میشه و احتیاجی به کپی مقادیر آن نیست.
بطور کلی استفاده از const سرباراضافی بر روی فراخوانی توابع را کم میکند.

vcldeveloper
دوشنبه 11 مرداد 1389, 23:48 عصر
در ++C وقتیکه متغیری از نوع شیئ را به تابع میفرستیم یک کپی از آن ساخته میشود(باعث افزایش زمان فراخوانی تابع میشود) و پس از خروج از تابع نابود کننده کپی صدا زده میشود که باعث خرابی اشاره گرها و متغیرهای استاتیک میشود.
در C و ++C حالت پیش فرض برای پارامترها by reference هست، مگر اینکه صراحتا برنامه نویس حالت دیگه ایی رو انتخاب کنه.


.ولی در دلفی فکر کنم متغیر کلاس بصورت اشاره گر فرستاده بشه؟!
اگر لینک بالا را مطالعه می کردید، توضیح دادم که اشیاء در دلفی کلا خودشان pointer هست؛ پس وقتی به صورت by value ارسال میشند، صرفا یک pointer به تابع منتقل شده.


به همین دلیل اگر رشته یا متغیری که طول آن زیاد باشه وقتی که بصورت پارامتر به تابع فرستاده میشه یک کپی از آن ساخته میشه و زمان اجرای تابع را زیاد میکند.بهمین دلیل اگر از Const استفاده کنیم فقط آدرس متغیر فرستاده میشه و احتیاجی به کپی مقادیر آن نیست.
خیر اینطور نیست! string ها هم در دلفی به صورت pointer پیاده سازی شدند، و پاس کردنشان به یک تابع به طور عادی فقط پاس کردن یک اشاره گر ساده هست. البته string ها در دلفی به صورت copy-on-write عمل می کنند، یعنی اگر string در داخل تابع تغییر داده بشه، اون وقت مقدار قبلی string به همراه تغییرات مربوطه در محل جدیدی از حافظه کپی میشند.

علت استفاده از const رو هم در اون لینک توضیح دادم. برای string، علت استفاده از const بر میگرده به reference-counted بودن stringها در دلفی، و اینکه اگر از const استفاده بشه، از آنجایی که کامپایلر مطمئن هست که تغییری در پارامتر داده نمیشه، از اضافه کردن روال های خاص کنترل و مدیریت reference-counter آن string صرفنظر میکنه.