From df09a3075c22999c8031669c9f9b94ad96ec029e Mon Sep 17 00:00:00 2001
From: Martin Goik <goik@hdm-stuttgart.de>
Date: Sat, 15 Sep 2018 10:27:23 +0200
Subject: [PATCH] New Timeperiod exercise, better explanations

---
 Doc/Sd1/coreClasses.xml          |  40 +++--
 Doc/Sd1/languageFundamentals.xml | 271 ++++++++++++++++++++++++++++---
 Doc/Sd1/objectsClasses.xml       | 196 +++++++++++++++++++++-
 3 files changed, 467 insertions(+), 40 deletions(-)

diff --git a/Doc/Sd1/coreClasses.xml b/Doc/Sd1/coreClasses.xml
index a4e54ec58..99d8e2f2d 100644
--- a/Doc/Sd1/coreClasses.xml
+++ b/Doc/Sd1/coreClasses.xml
@@ -73,26 +73,35 @@
     <title>Operator == and <methodname>equals()</methodname></title>
 
     <informaltable border="0">
+      <colgroup width="38%"/>
+
+      <colgroup width="62%"/>
+
       <tr>
-        <td valign="top"><programlisting language="java">String s1 = new String("Kate");
-String s2 = new String("Kate");
+        <th>Primitive type</th>
 
-System.out.println("==: " + (s1 == s2));
-System.out.println("equals: " + s1.equals(s2));</programlisting></td>
+        <th>Object</th>
+      </tr>
 
-        <td valign="top"><programlisting language="java">int a = 12;
-int b = 12;
+      <tr>
+        <td valign="top"><programlisting language="java">int a = 12, b = 12;  // equal values
 
 System.out.println("==: " + (a == b));
-// No equals(...) equivalent for
-// primitive types</programlisting></td>
+// No equals(...) method equivalent 
+// for primitive types</programlisting></td>
+
+        <td valign="top"><programlisting language="java">String s1 = new String("Kate"),
+       s2 = new String("Kate");
+
+System.out.println("    ==: " + (s1 == s2));
+System.out.println("equals: " + s1.equals(s2));</programlisting></td>
       </tr>
 
       <tr>
-        <td valign="top"><screen>==: false
-equals: true</screen></td>
-
         <td valign="top"><screen>==: true</screen></td>
+
+        <td valign="top"><screen>    ==: false
+equals: true</screen></td>
       </tr>
     </informaltable>
   </figure>
@@ -109,7 +118,14 @@ equals: true</screen></td>
 
       <listitem>
         <para>The <code language="java">==</code> operator acting on objects
-        compares for object identity.</para>
+        compares for equality of reference values and thus for object
+        identity.</para>
+      </listitem>
+
+      <listitem>
+        <para>The <code language="java">==</code> operator acting on objects
+        does <emphasis role="red">not</emphasis> check whether two objects
+        carry semantically equal values.</para>
       </listitem>
 
       <listitem>
diff --git a/Doc/Sd1/languageFundamentals.xml b/Doc/Sd1/languageFundamentals.xml
index 17f555452..7d7cfa441 100644
--- a/Doc/Sd1/languageFundamentals.xml
+++ b/Doc/Sd1/languageFundamentals.xml
@@ -4266,16 +4266,56 @@ short sum = a + 7; <co linkends="sd1_co_expressionTypeIntToShort-2"
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-B">short</code>.</para>
 
             <para>The very same argument seems to apply for the expression
-            <code language="java">4 + 7</code> even better: This time the plus
-            operator acts on two <code language="java"
+            <code language="java">4 + 7</code> even more: This time the plus
+            operator acts on even two <code language="java"
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code>
-            operands. However the <xref linkend="glo_Java"/> compiler is
-            <quote>clever</quote> enough casting the <code language="java"
-            xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code>
-            result 11 to the <code language="java"
+            operands. However in contrast to the former assignment this time
+            <emphasis>both</emphasis> operands are static. The 4 + 7
+            expression's value of 11 is being calculated at compile time.
+            Since 11 of type <code language="java">int</code> is within
+            <inlineequation>
+                <m:math display="inline">
+                  <m:mrow>
+                    <m:mo>[</m:mo>
+
+                    <m:mrow>
+                      <m:mrow>
+                        <m:mo>-</m:mo>
+
+                        <m:msup>
+                          <m:mi>2</m:mi>
+
+                          <m:mi>15</m:mi>
+                        </m:msup>
+                      </m:mrow>
+
+                      <m:mo>,</m:mo>
+
+                      <m:mrow>
+                        <m:mrow>
+                          <m:mo>-</m:mo>
+
+                          <m:msup>
+                            <m:mi>2</m:mi>
+
+                            <m:mi>15</m:mi>
+                          </m:msup>
+                        </m:mrow>
+
+                        <m:mo>-</m:mo>
+
+                        <m:mi>1</m:mi>
+                      </m:mrow>
+                    </m:mrow>
+
+                    <m:mo>]</m:mo>
+                  </m:mrow>
+                </m:math>
+              </inlineequation> the compiler will safely cast this value to
+            the <code language="java"
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-B">short</code>
-            variable <code language="java">sum</code> without any loss of
-            information.</para>
+            variable <code language="java">sum</code> without information
+            loss.</para>
           </answer>
         </qandaentry>
       </qandadiv>
@@ -4300,7 +4340,8 @@ short sum = a + 7; <co linkends="sd1_co_expressionTypeIntToShort-2"
             <para>The divide operator acts on two <code language="java"
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.2.1-100-C">int</code>
             literal values 8 an 9. Thus irrespective of the possibly intended
-            floating point result the resulting type is int .</para>
+            floating point result the resulting type is <code
+            language="java">int</code> .</para>
 
             <para>According to <uri
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-300-A-2">https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.1.3-300-A-2</uri>
@@ -4841,8 +4882,8 @@ System.out.println("Difference: " + difference);</programlisting><screen>Differe
    double radius = 2.31;   // A circle having a radius (given e.g. in mm).
    double pi = 3.1415926;  // Constant relating a circle's radius,
                            //perimeter and area.
-
-   // TODO: Write the circle's area to standard output
+ 
+  System.out.println( <emphasis role="red">/* TODO: Write the circle's area to standard output */</emphasis>);
 }</programlisting>
 
             <tip>
@@ -4950,36 +4991,212 @@ System.out.println("A circle of radius " + radius + " will cover an area of " +
           </question>
 
           <answer>
-            <para>The solution is straightforward. We add the <code
+            <para>The solution is straightforward. We just add a <code
             language="java"
             xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code>
             modifier to the definition of our variable <code
-            language="java">pi</code>. In addition we use capital letters
-            <code language="java">PI</code> reflecting the naming convention
-            for constants:</para>
+            language="java">pi</code>:</para>
 
-            <programlisting language="java" linenumbering="numbered">final double PI = 3.141592653589793;
+            <programlisting language="none" linenumbering="numbered"><emphasis
+                role="red">final</emphasis> <co
+                linkends="sd1_listing_final_guard_pi-1"
+                xml:id="sd1_listing_final_guard_pi-1-co"/> double <emphasis
+                role="red">pi</emphasis> = 3.141592653589793;
+...
+<emphasis role="red">pi</emphasis> = -4; <co
+                linkends="sd1_listing_final_guard_pi-2"
+                xml:id="sd1_listing_final_guard_pi-2-co"/>
+...</programlisting>
+
+            <calloutlist>
+              <callout arearefs="sd1_listing_final_guard_pi-1-co"
+                       xml:id="sd1_listing_final_guard_pi-1">
+                <para>A <code language="java"
+                xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code>
+                modifier prohibits subsequent variable assignments thus
+                keeping its initially assigned value constant.</para>
+              </callout>
+
+              <callout arearefs="sd1_listing_final_guard_pi-2-co"
+                       xml:id="sd1_listing_final_guard_pi-2">
+                <para>The assignment attempt is being flagged as a compile
+                time error:</para>
+
+                <para><computeroutput>Cannot assign a value to final variable
+                'PI'</computeroutput></para>
+              </callout>
+            </calloutlist>
+
+            <para>As a rule of thumb: Whenever you intend a variable not to
+            change after an initial assignment use <code language="java"
+            xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code>
+            declaring it to remain constant.</para>
+
+            <para>In addition we may refactor our variable <code
+            language="java">pi</code> to use capital letters reflecting the
+            naming convention for constants. This is does not change program
+            execution in any way but enhances code readability:</para>
+
+            <programlisting language="java" linenumbering="numbered">final double <emphasis
+                role="red">PI</emphasis> = 3.141592653589793;
 double radius = 2.3; // Computing a circle's area
 System.out.println("A circle of radius " + radius + " will cover an area of " +
-  PI * radius * radius);
+  <emphasis role="red">PI</emphasis> * radius * radius);
 
-PI = -4;
+<emphasis role="red">PI</emphasis> = -4;
 
 radius = 1.8;
 
 System.out.println("A circle of radius " + radius + " will cover an area of " +
-   PI * radius * radius);</programlisting>
+   <emphasis role="red">PI</emphasis> * radius * radius);</programlisting>
+          </answer>
+        </qandaentry>
+      </qandadiv>
+    </qandaset>
 
-            <para>Now our flawed assignment at line 6 will be flagged as a
-            compile time error:</para>
+    <qandaset defaultlabel="qanda" xml:id="sd1_qanda_weeks2seconds">
+      <title>Turning weeks into seconds</title>
 
-            <para><computeroutput>Cannot assign a value to final variable
-            'PI'</computeroutput></para>
+      <qandadiv>
+        <qandaentry>
+          <question>
+            <para>Consider:</para>
 
-            <para>As a rule of thumb: Whenever you intend a variable not to
-            change after an initial assignment use <code language="java"
-            xlink:href="https://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.12.4">final</code>
-            declaring it to remain constant.</para>
+            <programlisting language="java">final short
+  weeks = 2,
+  days = 3,
+  hours = 14,
+  minutes = 32,
+  seconds = 55;
+
+final int secondsElapsed = ...; // TODO: assign elapsed seconds corresponding to previous time frame.
+
+System.out.println(secondsElapsed);</programlisting>
+
+            <para>Create an expression based on the variables <code
+            language="java">weeks</code>, <code language="java">days</code>,
+            <code language="java">hours</code>, <code
+            language="java">minutes</code> and <code
+            language="java">seconds</code> to calculate the number of seconds
+            elapsed for the given time period of two weeks, three days and so
+            on.</para>
+
+            <para>After you have completed this task read about <link
+            xlink:href="https://eli.thegreenplace.net/2010/03/30/horners-rule-efficient-evaluation-of-polynomials#horner-s-rule">Horner's
+            rule</link> and try to improve your solution with respect to
+            execution time.</para>
+          </question>
+
+          <answer>
+            <para>A straightforward solution reads:</para>
+
+            <programlisting language="java">final short
+  weeks = 2,
+  days = 3,
+  hours = 14,
+  minutes = 32,
+  seconds = 55;
+
+final int secondsElapsed =
+  seconds + 60 * minutes + 60 * 60 * hours + 60 * 60 *  24 * days + 60 * 60 *  24 * 7 * weeks;
+
+System.out.println(secondsElapsed);</programlisting>
+
+            <para>This requires four additions and 10 multiplications. We may
+            use:</para>
+
+            <programlisting language="java">...
+final int secondsElapsed =
+  seconds + 60 * (minutes + 60 * (hours + 24 * (days + 7 * weeks)));
+...</programlisting>
+
+            <para>This leaves us with four additions but just 4 instead of 10
+            multiplications.</para>
+
+            <para>Within the given context the difference in execution time
+            can be neglected. But in a different application the calculation
+            in question might have to be repeated millions of times giving
+            rise to a substantial gain with respect to total execution
+            time.</para>
+          </answer>
+        </qandaentry>
+      </qandadiv>
+    </qandaset>
+
+    <qandaset defaultlabel="qanda" xml:id="sd1_qanda_seconds2weeks">
+      <title>Turning seconds into weeks</title>
+
+      <qandadiv>
+        <qandaentry>
+          <question>
+            <para>This exercise is about reversing <xref
+            linkend="sd1_qanda_weeks2seconds"/> namely decomposing a given
+            value of elapsed seconds into weeks, days, hours, minutes and
+            seconds:</para>
+
+            <programlisting language="java">final int secondsElapsed = 1521175;
+
+final int weeks = ...; // TODO
+final int days = ...;// TODO
+final int hours = ...;// TODO
+final int minutes = ...;// TODO
+final int seconds = ...;// TODO
+
+System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);</programlisting>
+
+            <tip>
+              <para>As an example consider decomposing 192 seconds into
+              minutes and seconds:</para>
+
+              <itemizedlist>
+                <listitem>
+                  <para>Integer division 192 / 60 seconds yields 3
+                  minutes.</para>
+                </listitem>
+
+                <listitem>
+                  <para>We get the remaining seconds by virtue of the
+                  remainder operator 192 % 60.</para>
+                </listitem>
+              </itemizedlist>
+
+              <para>Thus 192 seconds equal 3 minutes and 12 seconds</para>
+            </tip>
+          </question>
+
+          <answer>
+            <para>We extend the given minute calculation example to all 5
+            desired values. For the sake of convenience the number of seconds
+            per minute, per hour and so on are being calculated
+            beforehand:</para>
+
+            <programlisting language="java">final int secondsElapsed = 1521175;
+
+// Defining helpful constants
+//
+final int
+  secondsPerMinute = 60,                    // 60 minutes per hour
+  secondsPerHour =   60 * secondsPerMinute, // 3600 seconds per hour
+  secondsPerDay =    24 * secondsPerHour,   // 86400 seconds per day
+  secondsPerWeek =    7 * secondsPerDay;    // 604800 seconds per week
+
+int remainingSeconds = secondsElapsed;
+
+final int weeks = remainingSeconds / secondsPerWeek;
+remainingSeconds = remainingSeconds % secondsPerWeek;
+
+final int days = remainingSeconds / secondsPerDay;
+remainingSeconds %= secondsPerDay;
+
+final int hours = remainingSeconds / secondsPerHour;
+remainingSeconds %= secondsPerHour;
+
+final int minutes = remainingSeconds / secondsPerMinute;
+remainingSeconds %= secondsPerMinute;
+
+final int seconds = remainingSeconds;
+
+System.out.println(weeks + ", " + days + ", " + hours + ", " + minutes + ", " + seconds);</programlisting>
           </answer>
         </qandaentry>
       </qandadiv>
diff --git a/Doc/Sd1/objectsClasses.xml b/Doc/Sd1/objectsClasses.xml
index fcb37c0c2..4a94f0eff 100644
--- a/Doc/Sd1/objectsClasses.xml
+++ b/Doc/Sd1/objectsClasses.xml
@@ -50,7 +50,7 @@
       </listitem>
 
       <listitem>
-        <para>typically hide their implementation.</para>
+        <para>allow for implementation hiding.</para>
       </listitem>
 
       <listitem>
@@ -3314,6 +3314,200 @@ public class Circle {
           </imageobject>
         </mediaobject>
       </figure>
+
+      <qandaset defaultlabel="qanda" xml:id="sd1_qanda_seconds2weeks_Class">
+        <title>Turning seconds into weeks part 2</title>
+
+        <qandadiv>
+          <qandaentry>
+            <question>
+              <para>This is a follow-up exercise to <xref
+              linkend="sd1_qanda_seconds2weeks"/> implementing a corresponding
+              <classname>Timeperiod</classname> class. Consider the subsequent
+              example demonstrating both its constructor and
+              <methodname>toString()</methodname> method:</para>
+
+              <informaltable border="0">
+                <tr>
+                  <td valign="top"><programlisting language="java">final Timeperiod t = new Timeperiod(112223);
+System.out.println(92 + " seconds are equal to " + t);</programlisting></td>
+
+                  <td valign="top"><screen>92 seconds are equal to 1 day, 7 hours, 10 minutes and 23 seconds</screen></td>
+                </tr>
+              </informaltable>
+
+              <para>Since the <methodname>toString()</methodname> method may
+              not be called at all it shall be implemented on demand. Tip:
+              create a suitable attribute being <code
+              language="java">null</code> initially. If
+              <methodname>toString()</methodname> is being called, first check
+              for <code language="java">null</code> and initialize it on
+              demand only.</para>
+
+              <para>Furthermore the individual weeks, days, hours, minutes and
+              seconds should be implemented as readonly values using <code
+              language="java">final</code>:</para>
+
+              <informaltable border="0">
+                <tr>
+                  <td valign="top"><programlisting language="java">final Timeperiod t = new Timeperiod(2310983);
+System.out.print("weeks = "     + t.weeks +
+                 "\ndays = "    + t.days +
+                 "\nhours = "   + t.hours +
+                 "\nminutes = " + t.minutes +
+                 "\nseconds = " + t.seconds);</programlisting></td>
+
+                  <td valign="top"><screen>weeks = 3
+days = 5
+hours = 17
+minutes = 56
+seconds = 23</screen></td>
+                </tr>
+              </informaltable>
+
+              <para>In other words: The <classname>Timeperiod</classname>
+              class should be implemented as an <link
+              xlink:href="https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html">immutable</link>.
+              Thus once a <classname>Timeperiod</classname> instance has been
+              created it shall be impossible to alter the instance
+              <abbrev>i.e.</abbrev> changing its state.</para>
+
+              <para>Use the following tests to check your implementation:
+              </para>
+
+              <programlisting language="java">public class TimeperiodTest {
+
+    // Helper methods for real tests.
+    static void assertPeriodEqualImplement(final int expectedSeconds,
+                          final int expectedMinutes,
+                          final int expectedHours,
+                          final int expectedDays,
+                          final int expectedWeeks,
+                          final String expectedToString,
+                          final Timeperiod period) {
+        Assert.assertEquals(expectedSeconds, period.seconds);
+        Assert.assertEquals(expectedMinutes, period.minutes);
+        Assert.assertEquals(expectedHours, period.hours);
+        Assert.assertEquals(expectedDays, period.days);
+        Assert.assertEquals(expectedWeeks, period.weeks);
+
+        Assert.assertEquals(expectedToString, period.toString());
+
+    }
+
+    static void assertPeriodEqual(final int expectedSeconds,
+                          final int expectedMinutes,
+                          final int expectedHours,
+                          final int expectedDays,
+                          final int expectedWeeks,
+                          final String expectedToString,
+                          final Timeperiod period) {
+
+        // Testing period in question
+        assertPeriodEqualImplement(
+                expectedSeconds, expectedMinutes, expectedHours, expectedDays, expectedWeeks, expectedToString,
+                period);
+
+        // Also testing copy constructor
+        assertPeriodEqualImplement(
+                expectedSeconds, expectedMinutes, expectedHours, expectedDays, expectedWeeks, expectedToString,
+                new Timeperiod(period));
+    }
+
+    /**
+     * Test constructor zero seconds.
+     */
+        @Test
+        public void testZero() {
+            assertPeriodEqual(
+                    0,0,0,0,0,
+                    "0 seconds",
+                    new Timeperiod(0));
+        }
+
+    @Test
+    public void testMinute() {
+        assertPeriodEqual(0,1,0,0,0,
+                "1 minute and 0 seconds",
+                new Timeperiod(60));
+        assertPeriodEqual(50,0,0,0,0,
+                "50 seconds",
+                new Timeperiod(50));
+        assertPeriodEqual(12,1,0,0,0,
+                "1 minute and 12 seconds",
+                new Timeperiod(72));
+        assertPeriodEqual(2,5,0,0,0,
+                "5 minutes and 2 seconds",
+                new Timeperiod(302));
+    }
+
+    @Test
+    public void testHour() {
+        assertPeriodEqual(0,0,2,0,0,
+                "2 hours, 0 minutes and 0 seconds",
+                new Timeperiod(7200));
+        assertPeriodEqual(59,59,0,0,0,
+                "59 minutes and 59 seconds",
+                new Timeperiod(3599));
+        assertPeriodEqual(40,1,1,0,0,
+                "1 hour, 1 minute and 40 seconds",
+                new Timeperiod(3700));
+    }
+
+    @Test
+    public void testVarious() {
+        assertPeriodEqual(1,3,4,1,6,
+                "6 weeks, 1 day, 4 hours, 3 minutes and 1 second",
+                new Timeperiod(3729781));
+
+        assertPeriodEqual(23,56,17,5,3,
+                "3 weeks, 5 days, 17 hours, 56 minutes and 23 seconds",
+                new Timeperiod(2310983));
+    }
+}</programlisting>
+            </question>
+
+            <answer>
+              <para>Our implementation basically reads:</para>
+
+              <programlisting language="java">public <link
+                  xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/P/Sd1/Timeperiod/src/main/java/de/hdm_stuttgart/mi/sd1/Timeperiod.java">Timeperiod</link>(final Timeperiod timeperiod) {
+
+    public final int seconds, minutes, hours, days, weeks;
+    // Constructors and toString() ...
+
+}</programlisting>
+
+              <para>The <code language="java">final</code> modifier ensures
+              instances to be immutable requiring all values to be set within
+              any constructor. We thus decompose the desired number of seconds
+              into weeks, days, hours, minutes and remaining seconds:</para>
+
+              <programlisting language="java">public <link
+                  xlink:href="https://gitlab.mi.hdm-stuttgart.de/goik/GoikLectures/blob/master/P/Sd1/Timeperiod/src/main/java/de/hdm_stuttgart/mi/sd1/Timeperiod.java#L65">Timeperiod</link>(int seconds) {
+
+  weeks = seconds / SECONDS_PER_WEEK;
+  seconds = seconds % SECONDS_PER_WEEK;        // remaining seconds without weeks
+
+  days = seconds / SECONDS_PER_DAY;
+  seconds %= SECONDS_PER_DAY;                  // remaining seconds without days
+
+  hours = seconds / SECONDS_PER_HOUR;
+  seconds %= SECONDS_PER_HOUR;                 // remaining seconds without minutes
+
+  minutes = seconds / SECONDS_PER_MINUTE;
+  this.seconds = seconds % SECONDS_PER_MINUTE; // remaining seconds
+}</programlisting>
+
+              <para>Notice the <code language="java">this.seconds</code>
+              qualification being required to disambiguate the constructor
+              parameter variable <code language="java">Timeperiod(int
+              seconds)</code> from <code
+              language="java">Timeperiod.seconds</code>.</para>
+            </answer>
+          </qandaentry>
+        </qandadiv>
+      </qandaset>
     </section>
   </section>
 
-- 
GitLab