কোনও কার্যক্রমে কেবলমাত্র একটি রিটার্নের বিবৃতি দেওয়া ভাল অভ্যাসের ভাল কারণ রয়েছে?
অথবা কোনও কাজ থেকে এটি যুক্তিযুক্তভাবে সঠিক হওয়ার সাথে সাথেই ফিরে আসা ঠিক আছে, মানে ফাংশনে অনেকগুলি রিটার্নের বিবৃতি থাকতে পারে?
কোনও কার্যক্রমে কেবলমাত্র একটি রিটার্নের বিবৃতি দেওয়া ভাল অভ্যাসের ভাল কারণ রয়েছে?
অথবা কোনও কাজ থেকে এটি যুক্তিযুক্তভাবে সঠিক হওয়ার সাথে সাথেই ফিরে আসা ঠিক আছে, মানে ফাংশনে অনেকগুলি রিটার্নের বিবৃতি থাকতে পারে?
উত্তর:
"সহজ" পরিস্থিতিতে ফিরে আসার পদ্ধতিটির শুরুতে আমার প্রায়শই বেশ কয়েকটি বিবৃতি থাকে। উদাহরণস্বরূপ, এটি:
public void DoStuff(Foo foo)
{
if (foo != null)
{
...
}
}
... এর মতো আরও পাঠযোগ্য (আইএমএইচও) তৈরি করা যায়:
public void DoStuff(Foo foo)
{
if (foo == null) return;
...
}
সুতরাং হ্যাঁ, আমি মনে করি কোনও ফাংশন / পদ্ধতি থেকে একাধিক "প্রস্থানস্থান" রাখা ভাল।
DoStuff() { DoStuffInner(); IncreaseStuffCallCounter(); }
কেউই কোড কমপ্লিটের উল্লেখ বা উদ্ধৃত করেনি তাই আমি এটি করব।
প্রতিটি রুটিনে রিটার্নের সংখ্যা হ্রাস করুন । কোনও রুটিনটি বোঝা আরও শক্ত যদি এটি নীচে পড়ে, আপনি কোথাও উপরে ফিরে আসার সম্ভাবনা সম্পর্কে অবগত নন।
যখন পাঠযোগ্যতা বাড়ায় তখন কোনও রিটার্ন ব্যবহার করুন । নির্দিষ্ট রুটিনগুলিতে, উত্তরটি জানার পরে, আপনি তাৎক্ষণিকভাবে কলিং রুটিনে ফিরিয়ে দিতে চান। যদি রুটিনটি এমনভাবে সংজ্ঞায়িত করা হয় যে এটির জন্য কোনও পরিষ্কারের প্রয়োজন নেই, অবিলম্বে না ফেরার অর্থ আপনার আরও কোড লিখতে হবে।
আমি বলব যে একাধিক প্রস্থান পয়েন্টগুলির বিরুদ্ধে নির্বিচারে সিদ্ধান্ত নেওয়া অবিশ্বাস্যরূপে বোকামি হবে কারণ আমি কৌশলটি বারবার অনুশীলনে দরকারী বলে খুঁজে পেয়েছি , বাস্তবে আমি প্রায়শই বিদ্যমান কোডটিকে একাধিক বহির্গমন পয়েন্টগুলিতে স্বচ্ছতার জন্য রিফেক্টর করেছি। আমরা দুটি পদ্ধতির সাথে এইভাবে তুলনা করতে পারি: -
string fooBar(string s, int? i) {
string ret = "";
if(!string.IsNullOrEmpty(s) && i != null) {
var res = someFunction(s, i);
bool passed = true;
foreach(var r in res) {
if(!r.Passed) {
passed = false;
break;
}
}
if(passed) {
// Rest of code...
}
}
return ret;
}
কোড যেখানে একাধিক প্রস্থান বিন্দু এই তুলনা করা হয় অনুমতি: -
string fooBar(string s, int? i) {
var ret = "";
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
আমার মনে হয় পরবর্তীকটি যথেষ্ট পরিষ্কার। যতদূর আমি একাধিক বহির্গমন পয়েন্টের সমালোচনা বলতে পারি এই দিনগুলির একটি বরং প্রত্নতাত্ত্বিক দৃষ্টিভঙ্গি।
আমি বর্তমানে এমন একটি কোডবেসে কাজ করছি যেখানে এতে কাজ করা দু'জন লোক অন্ধভাবে "একক পয়েন্টের প্রস্থান" তত্ত্বের সাবস্ক্রাইব করেছে এবং আমি আপনাকে বলতে পারি যে অভিজ্ঞতা থেকে এটি একটি ভয়ঙ্কর ভয়ঙ্কর অনুশীলন। কোডটি বজায় রাখা অত্যন্ত কঠিন করে তোলে এবং কেন তা আপনাকে দেখাব।
"একক পয়েন্টের প্রস্থান" তত্ত্বের সাহায্যে, আপনি অনিবার্যভাবে এমন কোডের সাথে সজ্জিত হন যা দেখতে এইরকম লাগে:
function()
{
HRESULT error = S_OK;
if(SUCCEEDED(Operation1()))
{
if(SUCCEEDED(Operation2()))
{
if(SUCCEEDED(Operation3()))
{
if(SUCCEEDED(Operation4()))
{
}
else
{
error = OPERATION4FAILED;
}
}
else
{
error = OPERATION3FAILED;
}
}
else
{
error = OPERATION2FAILED;
}
}
else
{
error = OPERATION1FAILED;
}
return error;
}
এটি কেবল কোডটি অনুসরণ করা খুব কঠিন করে না, তবে পরে বলুন আপনাকে ফিরে যেতে হবে এবং 1 এবং 2 এর মধ্যে একটি অপারেশন যুক্ত করতে হবে আপনাকে পুরো ফ্রেইকিং ফাংশনটি সম্পর্কে ইন্ডেন্ট করতে হবে, এবং সৌভাগ্য যে সমস্ত নিশ্চিত করে আপনার যদি / অন্য শর্ত এবং ধনুর্বন্ধনী সঠিকভাবে মিলে যায়।
এই পদ্ধতিটি কোড রক্ষণাবেক্ষণকে অত্যন্ত কঠিন এবং ত্রুটির প্রবণ করে তোলে।
স্ট্রাকচার্ড প্রোগ্রামিং বলছে আপনার কাছে ফাংশন অনুযায়ী কেবল একবারের জন্য বিবৃতি দেওয়া উচিত। এটি জটিলতা সীমাবদ্ধ করার জন্য। মার্টিন ফওলারের মতো অনেকের যুক্তি রয়েছে যে একাধিক রিটার্ন স্টেটমেন্ট সহ ফাংশনগুলি লেখা সহজ। তিনি এই যুক্তিটি তাঁর ক্লাসিক রিফ্যাক্টরিং বইয়ে উপস্থাপন করেছেন । আপনি যদি তাঁর অন্যান্য পরামর্শ অনুসরণ করেন এবং ছোট ফাংশনগুলি লিখেন তবে এটি ভাল কাজ করে। আমি এই দৃষ্টিকোণের সাথে একমত এবং কেবলমাত্র কঠোর কাঠামোগত প্রোগ্রামিং পিউরিস্টরা ফাংশন অনুযায়ী একক রিটার্নের বিবৃতি মেনে চলেন।
GOTO
ফাংশন বিদ্যমান থাকলেও নিয়ন্ত্রণ প্রবাহ সরানোর জন্য ব্যবহার সম্পর্কে কথা বলে বিবেচিত হয়েছিল । এটি কখনও "কখনও ব্যবহার করবেন না" বলে না GOTO
।
ক্যান্ট বেক নোট হিসাবে যেমন ইমপ্লিমেন্টেশন প্যাটার্নগুলিতে একটি গার্ডেন তৈরির ক্ষেত্রে প্রহরী ধারাগুলির বিষয়ে আলোচনা করার সময় একটি একক প্রবেশ এবং প্রস্থান পয়েন্ট থাকে ...
"একই রুটিনে অনেক লোকের মধ্যে ঝাঁপিয়ে পড়ার সময় সম্ভব হওয়া বিভ্রান্তি রোধ করা ছিল। ফোরট্রান বা অ্যাসেম্বলি ভাষার প্রোগ্রামগুলিতে প্রচুর বৈশ্বিক ডেটা সহ লেখা যখন এটি প্রয়োগ করা হয়েছিল তখনও বোঝা যায় যে কোন বিবৃতি কার্যকর হয়েছিল তা বোঝাও কঠোর পরিশ্রম ছিল .." "ছোট পদ্ধতি এবং বেশিরভাগ স্থানীয় ডেটা সহ এটি অযথা রক্ষণশীল" "
আমি গার্ড ক্লজগুলির সাথে লিখিত একটি ফাংশনটি দেখতে পাই যা দীর্ঘ দীর্ঘ নেস্টেড if then else
বিবৃতিগুলির চেয়ে আরও বেশি সহজে অনুসরণ করা যায় ।
কোনও ফাংশনে যার কোনও পার্শ্ব-প্রতিক্রিয়া নেই, সেখানে একক রিটার্নের বেশি হওয়ার কোনও যুক্তিসঙ্গত কারণ নেই এবং আপনাকে এগুলি কার্যকরী শৈলীতে লিখতে হবে। পার্শ্ব-প্রতিক্রিয়াযুক্ত একটি পদ্ধতিতে জিনিসগুলি আরও ক্রমযুক্ত (সময়-সূচকযুক্ত) হয়, তাই আপনি কার্যকর হওয়া স্টাইলে লেখেন, এক্সিকিউট বন্ধ করার জন্য কমান্ড হিসাবে রিটার্ন স্টেটমেন্ট ব্যবহার করে।
অন্য কথায়, যখন সম্ভব হয়, এই শৈলীর পক্ষে
return a > 0 ?
positively(a):
negatively(a);
এটার উপরে
if (a > 0)
return positively(a);
else
return negatively(a);
যদি আপনি নিজেকে নেস্টেড শর্তগুলির বেশ কয়েকটি স্তর লিখতে দেখেন তবে সম্ভবত একটি উপায় রয়েছে যা আপনি চুল্লিটি ব্যবহার করতে পারেন, উদাহরণস্বরূপ প্রাকটিক তালিকাটি ব্যবহার করে। যদি আপনি দেখতে পান যে আপনার আইএফস এবং এলিসগুলি সিনট্যাক্টিকভাবে অনেক দূরে রয়েছে তবে আপনি এটিকে ছোট ফাংশনে বিভক্ত করতে চাইতে পারেন। একটি শর্তযুক্ত ব্লক যা স্ক্রিনফুল পাঠ্যের চেয়ে বেশি ছড়িয়ে পড়ে তা পড়া শক্ত।
এমন কোনও কঠোর এবং দ্রুত নিয়ম নেই যা প্রতিটি ভাষার ক্ষেত্রে প্রযোজ্য। একক রিটার্ন স্টেটমেন্ট থাকার মতো কিছু আপনার কোডটি ভাল করবে না। তবে ভাল কোড আপনাকে আপনার ফাংশনগুলি সেভাবে লিখতে দেয়।
আমি এটি সি ++ এর কোডিং মানগুলিতে দেখেছি যা সি থেকে একটি হ্যাং-ওভার ছিল, যেন আপনার কাছে আরএআইআই বা অন্য স্বয়ংক্রিয় মেমরি পরিচালনা নেই তবে আপনাকে প্রতিটি রিটার্নের জন্য পরিষ্কার করতে হবে, যার অর্থ কাট-পেস্ট ক্লিন-আপ বা গোটো (যৌক্তিকভাবে পরিচালিত ভাষায় 'শেষ পর্যন্ত' সমান) এর উভয়টিই খারাপ ফর্ম হিসাবে বিবেচিত। যদি আপনার অনুশীলনগুলি সি ++ বা অন্য কোনও স্বয়ংক্রিয় মেমরি সিস্টেমে স্মার্ট পয়েন্টার এবং সংগ্রহগুলি ব্যবহার করে থাকে তবে তার পক্ষে এর শক্ত কারণ নেই, এবং এটি পাঠযোগ্যতা এবং আরও অনেক রায় সম্পর্কিত কল হয়ে যায়।
auto_ptr
আপনি সমান্তরালে প্লেইন পয়েন্টার ব্যবহার করতে পারেন। যদিও এটি প্রথম স্থানে একটি অপ্টিমাইটিজ সংকলক সহ 'অপ্টিমাইজড' কোড লেখা অদ্ভুত হবে।
try
... finally
জাভাতে) এবং আপনাকে সংস্থান রক্ষণাবেক্ষণ করতে হবে যা আপনি একটি একক দিয়ে করতে পারেন একটি পদ্ধতি শেষে ফিরে। আপনি এটি করার আগে, পরিস্থিতি থেকে মুক্তি পাওয়ার জন্য আপনার কোডটি রিফ্যাকচারিংয়ের গুরুত্ব সহকারে বিবেচনা করা উচিত।
আমি এই ধারনাটির দিকে ঝুঁকেছি যে ফাংশনের মাঝখানে রিটার্নের স্টেটমেন্টগুলি খারাপ। আপনি ফাংশনটির শীর্ষে কয়েকটি গার্ড ক্লজ তৈরি করতে রিটার্নগুলি ব্যবহার করতে পারেন, এবং অবশ্যই ইস্যু ছাড়াই ফাংশন শেষে কী ফিরে আসবে তা সংকলককে জানান, তবে ফাংশনের মাঝামাঝি রিটার্নগুলি মিস করা সহজ হতে পারে এবং ফাংশনটি ব্যাখ্যা করতে শক্ত করুন।
কোনও কার্যক্রমে কেবলমাত্র একটি রিটার্নের বিবৃতি দেওয়া ভাল অভ্যাসের ভাল কারণ রয়েছে?
হ্যাঁ , আছে:
প্রশ্নটি প্রায়শই একাধিক রিটার্নের মধ্যে একটি মিথ্যা দ্বিবিজ্ঞান হিসাবে উত্থাপিত হয় বা বিবৃতি দিলে গভীরভাবে বাসা বেঁধে থাকে। প্রায় সবসময়ই একটি তৃতীয় সমাধান থাকে যা একমাত্র প্রস্থান পয়েন্ট সহ খুব লিনিয়ার (গভীর বাসা বাঁধে না)।
আপডেট : দৃশ্যত MISRA নির্দেশিকা একক প্রস্থানকেও প্রচার করে।
স্পষ্টতই, আমি বলছি না যে একাধিক রিটার্ন পাওয়া সর্বদা ভুল। তবে অন্যথায় সমতুল্য সমাধান দেওয়া, একক রিটার্নের সাথে একটিকে পছন্দ করার জন্য অনেকগুলি ভাল কারণ রয়েছে।
Contract.Ensures
একাধিক রিটার্ন পয়েন্ট ব্যবহার করতে পারেন ।
goto
সাধারণ ক্লিনআপ কোডটি পেতে ব্যবহার করে থাকেন তবে আপনি সম্ভবত ফাংশনটি সহজ করেছেন যাতে return
ক্লিন-আপ কোডের শেষে একটি একক থাকে। সুতরাং আপনি বলতে পারেন যে আপনি সমস্যার সমাধান করেছেন goto
, তবে আমি বলতে চাই আপনি এটি একটির সরল করে সমাধান করেছেন return
।
একক বহির্গমন পয়েন্টটি ডিবাগিংয়ে একটি সুবিধা প্রদান করে, কারণ এটি আপনাকে কোনও ফাংশন শেষে একটিমাত্র ব্রেকআপপয়েন্ট সেট করার অনুমতি দেয় যা আসলে কী মান ফিরে আসবে তা দেখার জন্য।
সাধারণভাবে আমি কোনও ফাংশন থেকে কেবল একটি একক বহির্গমন পয়েন্ট থাকার চেষ্টা করি। অনেক সময় আছে তবে, এটি করার ফলে প্রয়োজনীয়গুলির চেয়ে আরও জটিল ফাংশন বডি তৈরি শেষ হয়, এক্ষেত্রে একাধিক প্রস্থান পয়েন্ট থাকা ভাল। ফলস্বরূপ জটিলতার উপর ভিত্তি করে এটি সত্যই "রায় দেওয়ার আহ্বান" হতে হবে তবে জটিলতা এবং বোধগম্যতার ত্যাগ ছাড়াই লক্ষ্যটি যতটা সম্ভব অল্প বহির্গমন পয়েন্ট হওয়া উচিত।
না, কারণ আমরা আর 1970 এর দশকে বাস করি না । যদি আপনার ফাংশনটি এত দীর্ঘ হয় যে একাধিক রিটার্ন একটি সমস্যা হয় তবে এটি খুব দীর্ঘ।
(এক্ষেত্রে ব্যতিক্রম ছাড়া কোনও ভাষাতে যে কোনও মাল্টি-লাইন ফাংশনের একাধিক প্রস্থান পয়েন্ট থাকবে তা বাদ দিয়ে) have
আমার পছন্দটি একক প্রস্থানের জন্য হবে যদি না এটি সত্যিই জিনিসগুলিকে জটিল করে তোলে। আমি খুঁজে পেয়েছি যে কিছু ক্ষেত্রে, একাধিক উপস্থিতি পয়েন্টগুলি আরও আরও উল্লেখযোগ্য ডিজাইনের সমস্যাগুলি মাস্ক করতে পারে:
public void DoStuff(Foo foo)
{
if (foo == null) return;
}
এই কোডটি দেখার পরে, আমি অবিলম্বে জিজ্ঞাসা করব:
এই প্রশ্নের উত্তরগুলির উপর নির্ভর করে এটি হতে পারে
উপরের উভয় ক্ষেত্রেই সম্ভবত কোডটি একটি দৃked়তার সাথে পুনরায় কাজ করা যেতে পারে যাতে 'foo' কখনই বাতিল হয় না এবং প্রাসঙ্গিক কলারগুলি পরিবর্তিত হয় তা নিশ্চিত করা যায়।
আরও দুটি কারণ রয়েছে (নির্দিষ্ট আমি সি ++ কোডে মনে করি) যেখানে একাধিক উপস্থিতি আসলে নেতিবাচক প্রভাব ফেলতে পারে। এগুলি কোড আকার এবং সংকলক অপ্টিমাইজেশন।
কোনও ফাংশন থেকে প্রস্থান করার সময় স্কোপে থাকা একটি নন-পড সি সি ++ অবজেক্টের তার ডেস্ট্রাক্টর ডেকে আনা হবে। যেখানে বেশ কয়েকটি রিটার্নের স্টেটমেন্ট রয়েছে, এমন ঘটনাও ঘটতে পারে যে সুযোগে বিভিন্ন অবজেক্ট রয়েছে এবং তাই কল করার জন্য ধ্বংসকারীদের তালিকা আলাদা হবে। সংকলকটি তাই প্রতিটি রিটার্ন বিবৃতি জন্য কোড উত্পন্ন করা প্রয়োজন:
void foo (int i, int j) {
A a;
if (i > 0) {
B b;
return ; // Call dtor for 'b' followed by 'a'
}
if (i == j) {
C c;
B b;
return ; // Call dtor for 'b', 'c' and then 'a'
}
return 'a' // Call dtor for 'a'
}
কোডের আকারটি যদি কোনও সমস্যা হয় - তবে এটি এড়ানোর মতো কিছু হতে পারে।
অন্যান্য সমস্যাটি "নামযুক্ত রিটার্ন মান অপটিমিজেশন" (ওরফে অনুলিপি এলিজেন, আইএসও সি ++ ''03 12.8 / 15) সম্পর্কিত। সি ++ কোনও প্রয়োগকে কপি কন্সট্রাক্টরকে কল করতে এড়াতে অনুমতি দেয় যদি তা করতে পারে:
A foo () {
A a1;
// do something
return a1;
}
void bar () {
A a2 ( foo() );
}
কোডটি যেমন হয় তেমন 'a1' অবজেক্টটি 'foo' তে নির্মিত হয় এবং তার কপির কন্ট্রাক্টকে 'a2' বানানোর জন্য ডাকা হবে। তবে অনুলিপি এলিজেন সংকলককে স্ট্যাকের 'a2' হিসাবে একই জায়গায় 'a1' নির্মাণের অনুমতি দেয়। সুতরাং ফাংশনটি ফিরে আসার পরে অবজেক্টটির "অনুলিপি" করার দরকার নেই।
একাধিক প্রস্থান পয়েন্টগুলি এটি সনাক্ত করার চেষ্টা করে সংকলকটির কাজকে জটিল করে তোলে এবং কমপক্ষে ভিসি ++ এর অপেক্ষাকৃত সাম্প্রতিক সংস্করণের জন্য অপ্টিমাইজেশানটি ঘটেনি যেখানে ফাংশন বডিটিতে একাধিক রিটার্ন ছিল। দেখুন ভিসুয়াল C ++ 2005 নামযুক্ত ফেরত মান অপ্টিমাইজেশান আরো বিস্তারিত জানার জন্য।
throw new ArgumentNullException()
এই ক্ষেত্রে সি # তে রয়েছে), আমি আপনার অন্যান্য বিবেচ্য বিষয়গুলি সত্যই পছন্দ করেছি, সেগুলি আমার কাছে বৈধ, এবং কিছু ক্ষেত্রে সমালোচনাও হতে পারে কুলুঙ্গি প্রসঙ্গ।
foo
পরীক্ষা করা হচ্ছে এই প্রশ্নের সাথে এই বিষয়ের কোনও যোগসূত্র নেই, যা করা if (foo == NULL) return; dowork;
বা করা উচিতif (foo != NULL) { dowork; }
একক বহির্গমন পয়েন্ট থাকা সাইক্লোমেটিক জটিলতা হ্রাস করে এবং তাই তাত্ত্বিকভাবে , সম্ভাব্যতা হ্রাস করে যে আপনি যখন আপনার কোডগুলিতে বাগগুলি পরিবর্তন করবেন তখন এটি আপনার কোডগুলিতে প্রবর্তন করবে। অনুশীলন যাইহোক, পরামর্শ দেয় যে আরও বাস্তববাদী পদ্ধতির প্রয়োজন। সুতরাং আমি একটি একক প্রস্থান বিন্দু রাখার লক্ষ্য রাখি, তবে আমার কোডটি যদি আরও বেশি পাঠযোগ্য হয় তবে বেশ কয়েকটিতে অনুমতি দিন।
আমি নিজেকে কেবল একটি return
বিবৃতি ব্যবহার করতে বাধ্য করি , কারণ এটি একটি অর্থে কোডের গন্ধ তৈরি করে। আমাকে বিস্তারিত বলতে দাও:
function isCorrect($param1, $param2, $param3) {
$toret = false;
if ($param1 != $param2) {
if ($param1 == ($param3 * 2)) {
if ($param2 == ($param3 / 3)) {
$toret = true;
} else {
$error = 'Error 3';
}
} else {
$error = 'Error 2';
}
} else {
$error = 'Error 1';
}
return $toret;
}
(শর্তগুলি আরব্রিটরি ...)
যত বেশি শর্ত হয়, ফাংশনটি তত বড় হয়, পড়তে তত বেশি কষ্ট হয়। সুতরাং আপনি যদি কোডের গন্ধে সজ্জিত হন তবে আপনি এটি উপলব্ধি করতে পারবেন এবং কোডটি রিফ্যাক্টর করতে চান। দুটি সম্ভাব্য সমাধান হ'ল:
একাধিক রিটার্ন
function isCorrect($param1, $param2, $param3) {
if ($param1 == $param2) { $error = 'Error 1'; return false; }
if ($param1 != ($param3 * 2)) { $error = 'Error 2'; return false; }
if ($param2 != ($param3 / 3)) { $error = 'Error 3'; return false; }
return true;
}
পৃথক ফাংশন
function isEqual($param1, $param2) {
return $param1 == $param2;
}
function isDouble($param1, $param2) {
return $param1 == ($param2 * 2);
}
function isThird($param1, $param2) {
return $param1 == ($param2 / 3);
}
function isCorrect($param1, $param2, $param3) {
return !isEqual($param1, $param2)
&& isDouble($param1, $param3)
&& isThird($param2, $param3);
}
মঞ্জুর, এটি দীর্ঘ এবং কিছুটা অগোছালো তবে এইভাবে ফাংশনটি রিফ্যাক্টর করার প্রক্রিয়াতে আমরা করেছি've
আমি বলব আপনার প্রয়োজনীয় সংখ্যক, বা কোড ক্লিনার তৈরির মতো কোনও হওয়া উচিত (যেমন গার্ডের ধারাগুলি )।
আমি কোনও "সেরা অনুশীলন" ব্যক্তিগতভাবে কখনও শুনিনি / দেখিনি যে আপনার কেবলমাত্র একটি রিটার্নের বিবৃতি থাকা উচিত।
বেশিরভাগ ক্ষেত্রে, আমি একটি যুক্তিযুক্ত পথের উপর ভিত্তি করে যত তাড়াতাড়ি সম্ভব একটি ফাংশন থেকে প্রস্থান করার প্রবণতা করেছি (গার্ড ক্লজগুলি এটির একটি দুর্দান্ত উদাহরণ)।
আমি বিশ্বাস করি যে একাধিক রিটার্ন সাধারণত ভাল হয় (কোডটি আমি সি # তে লিখি)। একক-ফেরত শৈলী হ'ল সি থেকে হোল্ডওভার But তবে আপনি সম্ভবত সি-তে কোডিং করছেন না probably
সমস্ত প্রোগ্রামিং ভাষায় কোনও পদ্ধতির জন্য কেবলমাত্র একটি প্রস্থান বিন্দুর প্রয়োজন নেই এমন আইন নেই । কিছু লোক এই শৈলীর শ্রেষ্ঠত্বের উপর জোর দেয় এবং কখনও কখনও তারা এটিকে একটি "বিধি" বা "আইন" হিসাবে উন্নীত করে তবে এই বিশ্বাস কোনও প্রমাণ বা গবেষণা দ্বারা সমর্থন করে না।
একাধিক রিটার্ন শৈলী সি কোডে একটি খারাপ অভ্যাস হতে পারে, যেখানে সংস্থানগুলি স্পষ্টতই ডি-বরাদ্দ করতে হয়, তবে জাভা, সি #, পাইথন বা জাভাস্ক্রিপ্টের মতো ভাষাতে যেমন স্বয়ংক্রিয় আবর্জনা সংগ্রহ এবং try..finally
ব্লক (এবং using
সি # তে ব্লক) এর মতো নির্মাণ রয়েছে ), এবং এই যুক্তি প্রযোজ্য নয় - এই ভাষাগুলিতে কেন্দ্রীভূত ম্যানুয়াল রিসোর্স অবলোকনের প্রয়োজন খুব অস্বাভাবিক।
এমন একাধিক কেস রয়েছে যেখানে একক রিটার্ন বেশি পঠনযোগ্য এবং এমন ক্ষেত্রে নেই যেখানে। দেখুন এটি কোডের রেখার সংখ্যা হ্রাস করে, যুক্তিকে আরও পরিষ্কার করে দেয় বা বন্ধনী এবং ইনডেন্টের সংখ্যা বা অস্থায়ী ভেরিয়েবলের সংখ্যা হ্রাস করে কিনা See
সুতরাং, আপনার শৈল্পিক সংবেদনশীলতা অনুসারে যতগুলি রিটার্ন ব্যবহার করুন, কারণ এটি কোনও প্রযুক্তিগত নয়, এটি একটি বিন্যাস এবং পাঠযোগ্যতার সমস্যা issue
আমি আমার ব্লগে আরও বেশি দৈর্ঘ্যে এ সম্পর্কে কথা বলেছি ।
অনিবার্য সম্পর্কে যেমন খারাপ কথা বলা হয় তেমনি একক বহির্গমন-পয়েন্ট সম্পর্কে বলার জন্য ভাল কথা রয়েছে "তীর" প্রোগ্রামিং সম্পর্কে ফলস্বরূপ that
ইনপুট বৈধতা বা সংস্থান বরাদ্দের সময় যদি একাধিক প্রস্থান পয়েন্টগুলি ব্যবহার করা হয়, তবে আমি সমস্ত 'ত্রুটি-প্রস্থান' খুব কার্যকরভাবে ফাংশনের শীর্ষে রাখার চেষ্টা করি।
উভয় স্পার্টান প্রোগ্রামিং "SSDSLPedia" এবং নিবন্ধ একক কার্যকারিতা প্রস্থান বিন্দু "পোর্টল্যান্ড প্যাটার্ন সংগ্রহস্থলের প্রয়োগ এর উইকি" এর নিবন্ধ এই সমস্যা এড়ানোর কিছু অন্তর্দৃষ্টিপূর্ণ আর্গুমেন্ট আছে। এছাড়াও, অবশ্যই, বিবেচনা করার জন্য এই পোস্ট আছে।
আপনি যদি সত্যিই একক স্থানে রিসোর্সগুলি প্রকাশের জন্য উদাহরণস্বরূপ কোনও একক বহির্গমন (কোনও ব্যতিক্রম-অযোগ্য-সক্ষম ভাষায়) চান তবে আমি গোটার যত্ন সহকারে প্রয়োগটি ভাল হতে পারি; উদাহরণস্বরূপ দেখুন এটি বরং স্বীকৃত উদাহরণ (পর্দার রিয়েল এস্টেট সংরক্ষণের জন্য সংকুচিত):
int f(int y) {
int value = -1;
void *data = NULL;
if (y < 0)
goto clean;
if ((data = malloc(123)) == NULL)
goto clean;
/* More code */
value = 1;
clean:
free(data);
return value;
}
ব্যক্তিগতভাবে আমি সাধারণত একাধিক প্রস্থান-পয়েন্ট অপছন্দের চেয়ে অ্যারো প্রোগ্রামিংকে অপছন্দ করি না, যদিও সঠিকভাবে প্রয়োগ করার সময় উভয়ই কার্যকর। অবশ্যই সেরাটি হ'ল আপনার প্রোগ্রামটিকে কোনও প্রয়োজনের জন্যই গঠন করা। আপনার ফাংশনকে একাধিক অংশে ভাঙা সাধারণত সহায়তা করে :)
যদিও এটি করার পরে, আমি দেখতে পাই যে এই উদাহরণ হিসাবে যেমন আমি একাধিক প্রস্থান পয়েন্টগুলি শেষ করেছি, যেখানে কিছু বৃহত্তর ফাংশনটি কয়েকটি ছোট ফাংশনে বিভক্ত হয়ে গেছে:
int g(int y) {
value = 0;
if ((value = g0(y, value)) == -1)
return -1;
if ((value = g1(y, value)) == -1)
return -1;
return g2(y, value);
}
প্রকল্প বা কোডিং নির্দেশিকাগুলির উপর নির্ভর করে, বেশিরভাগ বয়লার-প্লেট কোড ম্যাক্রোগুলির দ্বারা প্রতিস্থাপিত হতে পারে। পার্শ্ব নোট হিসাবে, এইভাবে এটি ভাঙ্গা ফাংশনগুলি g0, g1, g2 স্বতন্ত্রভাবে পরীক্ষা করা খুব সহজ করে তোলে।
স্পষ্টতই, একটি ওও এবং ব্যতিক্রম-সক্ষম ভাষায়, আমি যদি এই জাতীয় বিবৃতিগুলি ব্যবহার করি না (তবে আমি যদি যথেষ্ট পরিমাণে চেষ্টা করেই এড়িয়ে যেতে পারি), এবং কোডটি আরও স্পষ্ট হবে। এবং তীরবিহীন। এবং চূড়ান্ত-অন-ফাইনাল রিটার্নগুলির বেশিরভাগ ব্যতিক্রম হবে।
সংক্ষেপে;
আপনি প্রবাদটি জানেন - সৌন্দর্য দর্শকের চোখে পড়ে ।
কিছু লোক নেটবিয়ান এবং কেউ ইন্টেলিজ আইডিইএ , কেউ পাইথনের এবং কেউ পিএইচপি-র কসম খায় ।
কিছু দোকানে আপনি যদি এই কাজটি করার জন্য জিদ করেন তবে আপনি আপনার চাকরি হারাতে পারেন:
public void hello()
{
if (....)
{
....
}
}
প্রশ্ন সমস্ত দৃশ্যমানতা এবং রক্ষণাবেক্ষণযোগ্যতা সম্পর্কে।
যুক্তি এবং রাষ্ট্রীয় মেশিনের ব্যবহারকে হ্রাস ও সরল করতে আমি বুলিয়ান বীজগণিত ব্যবহারে আসক্ত। তবে, এমন অতীতের সহকর্মীরা ছিলেন যারা বিশ্বাস করেছিলেন কোডিংয়ে আমার "গাণিতিক কৌশল" ব্যবহার করা অনুপযুক্ত, কারণ এটি দৃশ্যমান এবং রক্ষণাবেক্ষণযোগ্য হবে না। এবং এটি একটি খারাপ অভ্যাস হবে। দুঃখিত লোকেরা, আমি নিযুক্ত কৌশলগুলি আমার কাছে অত্যন্ত দৃশ্যমান এবং রক্ষণাবেক্ষণযোগ্য - কারণ যখন আমি ছয় মাস পরে কোডটিতে ফিরে আসি তখন প্রবাদ বাক্যটি স্প্যাগেটির জগাখিচুড়ি দেখে আমি কোডটি স্পষ্টভাবে বুঝতে পারি।
আরে বন্ধু (প্রাক্তন ক্লায়েন্টের মতো বলতেন) আপনি যা চান তা করুন যতক্ষণ আপনি জানেন যে এটি ঠিক করার দরকার যখন আমার দরকার হয় it
আমার মনে আছে 20 বছর আগে আমার এক সহকর্মীকে চাকরীর জন্য বরখাস্ত করা হয়েছিল যা আজকে চতুর বিকাশ কৌশল হিসাবে ডাকা হবে । তাঁর একটি ক্ষুদ্রতর ইনক্রিমেন্টাল পরিকল্পনা ছিল। তবে তার পরিচালক তাকে চিত্কার করে বললেন "আপনি ব্যবহারকারীদের জন্য ক্রমবর্ধমান বৈশিষ্ট্যগুলি প্রকাশ করতে পারবেন না! আপনাকে অবশ্যই জলপ্রপাতের সাথে লেগে থাকতে হবে ।" পরিচালকের প্রতি তার প্রতিক্রিয়া ছিল যে ক্রমবর্ধমান বিকাশ গ্রাহকের প্রয়োজনের জন্য আরও সুনির্দিষ্ট হবে। তিনি গ্রাহকদের প্রয়োজনের বিকাশে বিশ্বাসী, তবে ম্যানেজার "গ্রাহকের প্রয়োজন" কোডিংয়ে বিশ্বাসী।
ডেটা নরমালাইজেশন, এমভিপি এবং এমভিসি সীমানা ভঙ্গ করার জন্য আমরা প্রায়শই দোষী । আমরা কোনও ফাংশন নির্মাণের পরিবর্তে ইনলাইন করি। আমরা শর্টকাট নিই।
ব্যক্তিগতভাবে, আমি বিশ্বাস করি যে পিএইচপি খারাপ অভ্যাস, তবে আমি কী জানি। সমস্ত তাত্ত্বিক যুক্তি নিয়মের একটি সেট পূরণ করার চেষ্টা করে
গুণমান = নির্ভুলতা, রক্ষণাবেক্ষণযোগ্যতা এবং লাভজনকতা।
অন্যান্য সমস্ত নিয়মগুলি পটভূমিতে বিবর্ণ হয়। এবং অবশ্যই এই নিয়মটি কখনই ম্লান হয় না:
অলসতা একটি ভাল প্রোগ্রামারের গুণাবলী।
আমি প্রারম্ভিক ক্লজগুলি ব্যবহার শুরু করার দিকে ঝুঁকির সাথে তাড়াতাড়ি ফিরে আসুন এবং অন্যথায় কোনও পদ্ধতি শেষে প্রস্থান করুন। একক প্রবেশ এবং প্রস্থান নিয়মের historicalতিহাসিক তাত্পর্য রয়েছে এবং একাধিক রিটার্ন (এবং অনেকগুলি ত্রুটি) সহ একক সি ++ পদ্ধতির জন্য 10 A4 পৃষ্ঠাগুলিতে লিগ্যাসি কোড নিয়ে কাজ করার সময় বিশেষত সহায়ক ছিল। সাম্প্রতিককালে, গৃহীত ভাল অনুশীলন হ'ল পদ্ধতিগুলি ছোট রাখা যা একাধিক প্রস্থানকে বোঝার প্রতিবন্ধকতা তৈরি করে। নীচের ক্রোনোজ উদাহরণটি উপরে থেকে অনুলিপি করা হয়েছে, প্রশ্নটি হল // কোডের বাকী ... তে কী ঘটে ?
void string fooBar(string s, int? i) {
if(string.IsNullOrEmpty(s) || i == null) return null;
var res = someFunction(s, i);
foreach(var r in res) {
if(!r.Passed) return null;
}
// Rest of code...
return ret;
}
আমি বুঝতে পারছি উদাহরণ কিছুটা কল্পিত হয় কিন্তু আমি refactor টানতে হবে foreach একটি LINQ বিবৃতি যে তারপর গার্ড দফা বিবেচনা করা যেতে পারে বা লুপ। আবার, কল্পিত উদাহরণে কোডের অভিপ্রায় স্পষ্ট এবং নয় someFunction () কিছু অন্যান্য পার্শ্ব প্রতিক্রিয়া হয়ে থাকতে পারে বা ফলাফলে ব্যবহার করা যেতে পারে // কোডের বিশ্রাম ... ।
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
নিম্নলিখিত রিফ্যাক্টরড ফাংশন প্রদান:
void string fooBar(string s, int? i) {
if (string.IsNullOrEmpty(s) || i == null) return null;
if (someFunction(s, i).Any(r => !r.Passed)) return null;
// Rest of code...
return ret;
}
null
যুক্তিটি গ্রহণযোগ্য নয় বলে ইঙ্গিত দিয়ে ব্যতিক্রম ছুঁড়ে ফিরবেন কেন ?
একটি ভাল কারণ যা আমি ভাবতে পারি তা হল কোড রক্ষণাবেক্ষণ: আপনার একক বহির্গমন রয়েছে। আপনি যদি ফলাফলের ফর্ম্যাটটি পরিবর্তন করতে চান, ..., এটি বাস্তবায়ন করা সহজতর। এছাড়াও, ডিবাগিংয়ের জন্য, আপনি কেবল সেখানে ব্রেকআপপয়েন্টটি আটকে রাখতে পারেন :)
এটি বলার পরে, আমাকে একবার একটি লাইব্রেরিতে কাজ করতে হয়েছিল যেখানে কোডিং মানগুলি 'ফাংশন অনুসারে একটি রিটার্ন স্টেটমেন্ট' চাপিয়েছিল এবং আমি এটি বেশ শক্ত বলে মনে করেছি। আমি প্রচুর সংখ্যার কম্পিউটেশন কোড লিখি এবং প্রায়শই 'বিশেষ কেস' থাকে, তাই কোডটি অনুসরণ করা বেশ শক্ত হয়ে যায় ...
একাধিক প্রস্থান বিন্দু ছোট ছোট ফাংশনগুলির জন্য সূক্ষ্ম - এটি হ'ল এমন একটি ফাংশন যা পুরোপুরি এক পর্দার দৈর্ঘ্যে দেখা যায়। যদি একটি দীর্ঘ ক্রিয়ায় একইভাবে একাধিক প্রস্থান বিন্দু অন্তর্ভুক্ত থাকে তবে এটি একটি চিহ্ন যে ফাংশনটি আরও কাটা যাবে।
এটি বলেছে যে একেবারে প্রয়োজনীয় না হলে আমি একাধিক-প্রস্থান ফাংশন এড়াতে চাই । আমি আরও জটিল ফাংশনগুলিতে কিছু অস্পষ্ট লাইনে কিছু বিপথগামী ফিরে আসার কারণে এমন ব্যাগগুলির ব্যথা অনুভব করেছি।
আমি ভয়ানক কোডিং মানগুলির সাথে কাজ করেছি যা আপনার উপর একক প্রস্থান পথকে বাধ্য করেছিল এবং ফলাফলটি প্রায় সর্বদা অরক্ষিত স্প্যাগেটি হয় যদি ফাংশনটি তুচ্ছ কিছু না হলেও - আপনি প্রচুর বিরতি দিয়ে শেষ করেছেন এবং অবিরত পথে চলেছেন।
if
কথাটি প্রতিটি পদ্ধতির কলের সামনে বিবৃতিটি এড়াতে বলার অপেক্ষা রাখে না যা সাফল্য ফিরে আসে বা না :(
একক প্রস্থান বিন্যাস - অন্যান্য সমস্ত জিনিস সমান - কোডকে উল্লেখযোগ্যভাবে আরও পঠনযোগ্য করে তোলে। তবে একটি ধরা আছে: জনপ্রিয় নির্মাণ
resulttype res;
if if if...
return res;
একটি জাল, "রেস =" "রিটার্ন" এর চেয়ে বেশি ভাল নয়। এটির একক রিটার্নের বিবৃতি রয়েছে তবে একাধিক পয়েন্ট যেখানে ফাংশনটি আসলে শেষ হয়।
আপনার যদি একাধিক রিটার্ন (বা "রেস =" গুলি) নিয়ে ফাংশন থাকে তবে একক প্রস্থান পয়েন্ট সহ এটি বেশ কয়েকটি ছোট ফাংশনে বিভক্ত হওয়া প্রায়শই ভাল ধারণা।
আমার স্বাভাবিক নীতিটি কোনও ফাংশন শেষে কেবলমাত্র একটি রিটার্নের বিবৃতি দেওয়া উচিত যদি না কোডের জটিলতা আরও যোগ করে ব্যাপকভাবে হ্রাস পায়। আসলে, আমি বরং আইফেলের ভক্ত, যা কোনও একমাত্র রিটার্ন বিবৃতি না পেয়ে একমাত্র রিটার্ন বিধি প্রয়োগ করে (আপনার ফলাফলের জন্য কেবল একটি স্বয়ং-নির্মিত 'ফলাফল' পরিবর্তনশীল)।
অবশ্যই কিছু ক্ষেত্রে রয়েছে যেখানে কোডগুলি ছাড়াই সুস্পষ্ট সংস্করণের চেয়ে একাধিক রিটার্ন সহ পরিষ্কার করা যায়। যে কেউ তর্ক করতে পারে যে আপনার যদি এমন একটি ফাংশন থাকে যা একাধিক রিটার্নের বিবৃতি ব্যতীত বোধগম্য না হয় তবে এটি কখনও কখনও এই জাতীয় বিষয়গুলির জন্য ব্যবহারিক হওয়া ভাল।
যদি আপনি কয়েকটিরও বেশি রিটার্ন শেষ করেন তবে আপনার কোডে কিছু ভুল হতে পারে। অন্যথায় আমি সম্মত হব যে মাঝে মাঝে সাবরুটিনে একাধিক জায়গা থেকে ফিরে আসতে পেরে ভাল লাগবে, বিশেষত যখন কোডটি ক্লিনার করে তোলে।
sub Int_to_String( Int i ){
given( i ){
when 0 { return "zero" }
when 1 { return "one" }
when 2 { return "two" }
when 3 { return "three" }
when 4 { return "four" }
...
default { return undef }
}
}
ভাল এইভাবে লেখা হবে
@Int_to_String = qw{
zero
one
two
three
four
...
}
sub Int_to_String( Int i ){
return undef if i < 0;
return undef unless i < @Int_to_String.length;
return @Int_to_String[i]
}
দ্রষ্টব্য এটি কেবল একটি দ্রুত উদাহরণ ছিল
আমি গাইডলাইন হিসাবে শেষে সিঙ্গল রিটার্নের জন্য ভোট দিই। এটি একটি সাধারণ কোড সাফ আপ হ্যান্ডলিংয়ে সহায়তা করে ... উদাহরণস্বরূপ, নিম্নলিখিত কোডটি একবার দেখুন ...
void ProcessMyFile (char *szFileName)
{
FILE *fp = NULL;
char *pbyBuffer = NULL:
do {
fp = fopen (szFileName, "r");
if (NULL == fp) {
break;
}
pbyBuffer = malloc (__SOME__SIZE___);
if (NULL == pbyBuffer) {
break;
}
/*** Do some processing with file ***/
} while (0);
if (pbyBuffer) {
free (pbyBuffer);
}
if (fp) {
fclose (fp);
}
}
এটি সম্ভবত একটি অস্বাভাবিক দৃষ্টিভঙ্গি, তবে আমি মনে করি যে যে কেউ বিশ্বাস করে যে একাধিক রিটার্নের স্টেটমেন্ট গ্রহণ করা উচিত তাকে কখনও কোনও মাইক্রোপ্রসেসরে ডিবাগার ব্যবহার করতে হয়নি যা কেবলমাত্র 4 টি হার্ডওয়্যার ব্রেকপয়েন্টগুলিকে সমর্থন করে। ;-)
"তীর কোড" এর সমস্যাগুলি সম্পূর্ণরূপে সঠিক হলেও একাধিক রিটার্ন স্টেটমেন্ট ব্যবহার করার সময় যে সমস্যাটি চলে যাবে বলে মনে হচ্ছে আপনি সেই ডিবাগারটি ব্যবহার করছেন এমন পরিস্থিতিতে। আপনি প্রস্থানটি দেখতে পাচ্ছেন এবং অতএব প্রত্যাবর্তনের শর্তটি নিশ্চিত করার জন্য ব্রেকআপপয়েন্ট রাখতে আপনার কোনও সুবিধাজনক ক্যাচ-অল অবস্থান নেই।
কোনও ফাংশনে আপনার যত বেশি রিটার্ন স্টেটমেন্ট রয়েছে, সেই এক পদ্ধতিতে জটিলতা তত বেশি। যদি আপনি নিজেকে ভাবছেন যে যদি আপনার কাছে অনেকগুলি রিটার্নের বিবৃতি রয়েছে তবে আপনি নিজেকে জিজ্ঞাসা করতে চাইতে পারেন যে সেই ফাংশনে আপনার অনেক বেশি কোডের লাইন আছে কিনা।
তবে, না, এক / বহু রিটার্ন বিবৃতিতে কোনও ভুল নেই। কিছু ভাষায়, এটি অন্যদের (সি) এর চেয়ে ভাল অনুশীলন (সি ++)।