التوابع المجردة

يتم اعتبار العملية تابعاً مجرداً إذا اعتمدت نتيجتها على المتحولات فقط، ولم تكن للعملية أية تأثيرات جانبية مثل تعديل أحد المتحولات، أو طباعة شيء ما. إن النتيجة الوحيدة المترتبة على استدعاء تابع مجرد هي القيمة المعادة.
من الأمثلة على التوابع المجردة isAfter، التي تقارن بين زمنين (كائنين من الصنف Time) وتعيد قيمة بوليانية تبين فيما إذا كان المعامل الأول يتأخر عن الثاني أو لا:
كود:
public static boolean isAfter(Time time1, Time time2) {
   if (time1.hour > time2.hour) return true;
   if (time1.hour < time2.hour) return false;
   if (time1.minute > time2.minute) return true;
   if (time1.minute < time2.minute) return false;
   if (time1.second > time2.second) return true;
   return false;
}
ما هي نتيجة هذه العملية لو كان الوقتان متساويين؟ هل تبدو تلك النتيجة ملائمة لهذه العملية؟ لو كنت تكتب وثائق هذه العملية، فهل كنت لتذكر تلك الحالة بشكل محدد؟
ومن الأمثلة الأخرى addTime، التي تحسب مجموع زمنين. مثلاً، إذا كانت الساعة 9:14:30، وكانت آلة تحميص الخبز عندك تستغرق 3 ساعات و35 دقيقة، يمكنك استخدام addTime لمعرفة الوقت الذي سيجهز فيه الخبز.
إليك مسوّدة أولية لهذه العملية وهي ليست مضبوطة تماماً:
كود:
public static Time addTime(Time t1, Time t2) {
   Time sum = new Time();
   sum.hour = t1.hour + t2.hour;
   sum.minute = t1.minute + t2.minute;
   sum.second = t1.second + t2.second;
   return sum;
}
بما أن هذه العملية تعيد كائن Time، فقد تظن أنها عملية بناء، إلا أنها ليست كذلك. عليك العودة والتحقق من بنية العمليات العادية (مثل هذه) والعمليات البانية، لأنك قد تخلط بينهما بسهولة.
إليك مثالاً عن كيفية استعمال هذه العملية. إذا احتوى currentTime على الوقت الحالي وbreadTime على الزمن اللازم لتحميص الخبز، فعندئذ يمكنك استعمال addTime لمعرفة الوقت الذي سيكون الخبز فيه جاهزاً.
كود:
Time currentTime = new Time(9, 14, 30.0);
Time breadTime = new Time(3, 35, 0.0);
Time doneTime = addTime(currentTime, breadTime);
printTime(doneTime);
إن خرج هذا البرنامج هو 12:49:30.0، وهو صحيح. من ناحية أخرى، توجد حالات تكون فيها الإجابة خاطئة. هل يمكنك التفكير في واحدة منها؟
المشكلة هي أن هذه العملية لا تعالج الحالات التي يصبح فيها عدد الثواني أو الدقائق أكبر من 60 بعد عملية الجمع. في تلك الحالة، علينا "حمل" الثواني الزائدة إلى عمود الدقائق، أو الدقائق الزائدة إلى عمود الساعات.
ها هي النسخة الصحيحة من العملية.
كود:
public static Time addTime(Time t1, Time t2) {
  Time sum = new Time();
  sum.hour = t1.hour + t2.hour;
  sum.minute = t1.minute + t2.minute;
  sum.second = t1.second + t2.second;
 
  if (sum.second >= 60.0) {
       sum.second -= 60.0;
       sum.minute += 1;
  }
  if (sum.minute >= 60) {
       sum.minute -= 60;
       sum.hour += 1;
  }
  return sum;
}
ومع أنها صحيحة، إلا أنها بدأت تكبر. سأقترح بدائل أقصر لها لاحقاً.
تشرح هذه الشفرة عمليتين لم نرهما من قبل، وهما =+ و=-. هذان العاملان يوفران طريقة مختصرة لزيادة أو إنقاص المتغيرات. وهما يشبهان ++ و-- في عملهما، عدا (1) يمكن أن يعملا على الأعداد العشرية بالإضافة إلى الأعداد الصحيحة، و(2) ليس بالضرورة أن تكون الزيادة أو النقصان بمقدار 1. التعليمة sum.second -= 60.0; مكافئة للتعليمة sum.second = sum.second – 60.0;.