comp.lang.ada
 help / color / mirror / Atom feed
From: bobduff@world.std.com (Robert A Duff)
Subject: Re: Q: access to subprogram
Date: 1996/07/11
Date: 1996-07-11T00:00:00+00:00	[thread overview]
Message-ID: <DuDwA9.99F@world.std.com> (raw)
In-Reply-To: 4rre7j$pv7@watnews1.watson.ibm.com


In article <4rre7j$pv7@watnews1.watson.ibm.com>,
Norman H. Cohen <ncohen@watson.ibm.com> wrote:
[... stuff about closures]

Norman gave a couple of nice examples illustrating how closures work
Thank you.  But I was hoping for something more about what makes
closures so great (as opposed to how they work).  I'm still unsure why
closures are such a wonderful thing.  Some comments:

Ackermann's function isn't something I want to calculate very often.
Is there a more "practical" example?

One can represent closures explicitly using heap-allocated tagged
objects.  A closure in a language that supports full closures is
represented by the address of the function, plus some representation of
the environment in which that function is called.  And this stuff has to
be allocated in the heap, since it can live essentially forever.  One
can do the same thing *explicitly* in Ada, by putting the "environment"
stuff into an object, and allocating it on the heap.  I show a different
version of package body Ackermann_Computation below, that works this
way.

Doing this requires the data that's in the closure to be explicitly
marked as such (by being components of the tagged type(s)).  In Norm's
"true closures" solution, it's implicit -- that is, whatever Norm's
Next_Row function happens to reference is what needs to be packaged up
in the closure.  Is there some advantage to that implicitness?  Does it
make things more substantially more convenient in some way that I don't
understand?  It seems to me that it's an *advantage* to make things
explicit -- it seems nice that a local variable (or parameter) in Ada
doesn't live longer than the containing scope -- it makes it easier to
understand what the purpose of that local is.  And if you want it to
live longer, you *explicitly* put it in the heap.

The solution below explicitly creates heap objects representing
closures, whereas Norman's solution implicitly allocates some stack
frames in the heap.

The "closures by hand" solution is approximately the same size as (a
little bigger than) Norm's solution.

Norman's solution is perhaps more elegant.  But it doesn't seem that
full closures make the grass greener and the sky bluer and the birds
sing more sweetly and all the other wonderfulness that some people seem
to like so much.  And of course there's a cost -- stack frames would
have to be heap-allocated in general, and a good compiler would want to
do all kinds of fancy analysis to avoid that when possible.

So, I guess my question is, "Yeah, it's nice, but what's the big deal?"

(By the way, surely the *simplest* solution is just a direct translation
from the definition:

   function Ackermann (M, N: Unbounded_Natural) return Unbounded_Natural is
   begin
      if M = 0 then
         return N+1;
      elsif N = 0 then
         return Ackermann(M-1, 1);
      else
         return Ackermann(M-1, Ackermann(M, N-1));
      end if;
   end Ackermann;

)

What's the most *efficient* method for calculating Ackermann's?

OK, here's my "closures-by-hand" solution:

package body Ackermann_Computation is

   package Container is
      -- We need to put Ackermann_Row_Type in a package, so
      -- Invoke will be primitive.

      type Ackermann_Row_Type is abstract tagged limited null record;
      -- Six reserved words in a row!

      function Invoke(R: Ackermann_Row_Type; N: Unbounded_Natural) return Unbounded_Natural is abstract;
      -- Invokes the closure represented by R, with parameter N.

      type Ackermann_Row_Ptr is access Ackermann_Row_Type'Class;
   end Container;
   use Container;

   type Row_Zero_Type is new Ackermann_Row_Type with null record;
   function Invoke(R: Row_Zero_Type; N: Unbounded_Natural) return Unbounded_Natural;

   function Invoke(R: Row_Zero_Type; N: Unbounded_Natural) return Unbounded_Natural is
   begin
      return N + 1;
   end Invoke;

   type Successor_Row_Type(Pred: access Ackermann_Row_Type'Class;
                           Row_Num: Natural) is new Ackermann_Row_Type with null record;
   -- Pred points to the predecessor row of this row.  This is analogous
   -- to the parameter F in Norman's Successor_Row function.

   function Invoke(R: Successor_Row_Type; N: Unbounded_Natural) return Unbounded_Natural;

   function Invoke(R: Successor_Row_Type; N: Unbounded_Natural) return Unbounded_Natural is
      Counter : Unbounded_Natural := N + 1;
      Result  : Unbounded_Natural := 1;
   begin
      while Counter /= 0 loop
         Result := Invoke(R.Pred.all, Result);
         Counter := Counter - 1;
      end loop;
      return Result;
   end Invoke;

   function Ackermann (M, N: Natural) return Unbounded_Natural is
      Row: Ackermann_Row_Ptr := new Row_Zero_Type;  -- R[0]
   begin
      for I in 1 .. M loop
         Row := new Successor_Row_Type(Pred => Row, Row_Num => I);
            -- Compute R[1] from R[0], R[2] from R[1], ...
      end loop;
      return Invoke(Row.all, To_Unbounded_Natural(N));  -- i.e., R[m](n)
   end Ackermann;

end Ackermann_Computation;

And here's Norm's solution using closures, for comparison:

package body Ackermann_Computation is

   type Ackermann_Row_Type is
      access function (N: Unbounded_Natural) return Unbounded_Natural;

   function Row_Zero (N: Unbounded_Natural) return Unbounded_Natural is
   begin
      return N + 1;
   end Row_Zero;

   function Successor_Row
      (F: Ackermann_Row_Type) return Ackermann_Row_Type is

      function Next_Row (N: Unbounded_Natural) return Unbounded_Natural is
         Counter : Unbounded_Natural := N + 1;
         Result  : Unbounded_Natural := 1;
      begin
         while Counter /= 0 loop
            Result := F(Result);
               -- F is the parameter of the surrounding function
            Counter := Counter - 1;
         end loop;
         return Result;
      end Result;

   begin

      return Next_Row'Access;  -- Illegal in Ada 95

   end Successor_Row;

   function Ackermann (M, N: Integer) return Unbounded_Natural is
      Row: Ackermann_Row_Type := Row_Zero'Access;  -- R[0]
   begin
      for I in 1 .. M loop
         Row := Successor_Row(Row);
            -- Compute R[1] from R[0], R[2] from R[1], ...
      end loop;
      return Row ( To_Unbounded_Natural(N) );  -- i.e., R[m](n)
   end Ackermann;

end Ackermann_Computation;

- Bob




  parent reply	other threads:[~1996-07-11  0:00 UTC|newest]

Thread overview: 133+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1996-07-02  0:00 Q: access to subprogram tmoran
1996-07-02  0:00 ` Robert A Duff
1996-07-02  0:00   ` Robert Dewar
1996-07-03  0:00   ` Fergus Henderson
1996-07-03  0:00     ` Robert A Duff
1996-07-03  0:00       ` Adam Beneschan
1996-07-03  0:00         ` Robert Dewar
1996-07-03  0:00         ` Robert A Duff
1996-07-09  0:00         ` Thomas Wolff
1996-07-03  0:00       ` Robert Dewar
1996-07-03  0:00   ` Jon S Anthony
1996-07-03  0:00     ` Robert A Duff
1996-07-08  0:00       ` Norman H. Cohen
1996-07-09  0:00         ` Robert A Duff
1996-07-03  0:00     ` Mark A Biggar
1996-07-03  0:00       ` Robert Dewar
1996-07-06  0:00         ` Robert A Duff
1996-07-08  0:00           ` Norman H. Cohen
1996-07-08  0:00             ` Robert Dewar
1996-07-11  0:00             ` Robert A Duff [this message]
1996-07-12  0:00               ` Robert A Duff
1996-07-14  0:00               ` Norman H. Cohen
1996-07-03  0:00       ` Robert A Duff
1996-07-03  0:00         ` Robert Dewar
1996-07-09  0:00         ` Thomas Wolff
1996-07-09  0:00           ` Robert Dewar
1996-07-10  0:00           ` Robert A Duff
1996-07-10  0:00             ` Richard A. O'Keefe
1996-07-10  0:00               ` Robert Dewar
1996-07-10  0:00               ` Robert A Duff
1996-07-10  0:00                 ` Thomas Wolff
1996-07-10  0:00                   ` Robert Dewar
1996-07-10  0:00                   ` Robert A Duff
1996-07-03  0:00     ` Robert Dewar
1996-07-19  0:00     ` Brian Rogoff
1996-07-22  0:00       ` Richard A. O'Keefe
1996-07-23  0:00       ` Brian Rogoff
1996-07-23  0:00         ` Robert A Duff
1996-07-26  0:00         ` Brian Rogoff
1996-07-28  0:00           ` Robert A Duff
1996-07-22  0:00     ` Brian Rogoff
1996-07-23  0:00       ` Robert A Duff
1996-07-24  0:00       ` Richard A. O'Keefe
1996-07-26  0:00         ` Ken Garlington
1996-07-30  0:00           ` Richard A. O'Keefe
1996-07-24  0:00       ` Brian Rogoff
1996-07-26  0:00         ` Robert A Duff
1996-07-30  0:00         ` Brian Rogoff
1996-07-24  0:00     ` Brian Rogoff
1996-07-26  0:00     ` Richard A. O'Keefe
1996-07-28  0:00       ` Fergus Henderson
1996-07-28  0:00       ` Robert A Duff
1996-07-29  0:00         ` Richard A. O'Keefe
1996-07-29  0:00           ` Robert A Duff
1996-07-29  0:00     ` Richard A. O'Keefe
1996-07-30  0:00     ` Jon S Anthony
1996-07-05  0:00   ` Jon S Anthony
1996-07-06  0:00     ` Robert Dewar
1996-07-06  0:00     ` Robert A Duff
1996-07-06  0:00       ` Robert Dewar
1996-07-08  0:00         ` Robert A Duff
1996-07-08  0:00       ` Richard A. O'Keefe
1996-07-08  0:00         ` Robert Dewar
1996-07-10  0:00           ` Richard A. O'Keefe
1996-07-10  0:00             ` Robert Dewar
1996-07-19  0:00               ` Richard A. O'Keefe
1996-07-08  0:00         ` Robert A Duff
1996-07-08  0:00           ` Robert Dewar
1996-07-07  0:00   ` Mark Eichin
1996-07-08  0:00     ` Richard Kenner
1996-07-07  0:00   ` Ronald Cole
1996-07-07  0:00     ` Richard Kenner
1996-07-07  0:00     ` Robert Dewar
1996-07-07  0:00       ` Richard Kenner
1996-07-07  0:00         ` Robert Dewar
1996-07-14  0:00       ` Ronald Cole
1996-07-14  0:00         ` Richard Kenner
1996-07-15  0:00           ` Fergus Henderson
1996-07-15  0:00             ` Robert Dewar
1996-07-17  0:00               ` Fergus Henderson
1996-07-17  0:00                 ` Richard Kenner
1996-07-17  0:00               ` Adam Beneschan
1996-07-20  0:00               ` Michael Feldman
1996-07-20  0:00                 ` Robert Dewar
1996-07-16  0:00             ` Richard Kenner
1996-07-08  0:00   ` Brian Rogoff
1996-07-11  0:00     ` Norman H. Cohen
1996-07-11  0:00       ` Magnus Kempe
1996-07-11  0:00         ` Robert Dewar
1996-07-09  0:00   ` Jon S Anthony
1996-07-09  0:00     ` Robert Dewar
1996-07-09  0:00     ` Robert Dewar
1996-07-09  0:00   ` Jon S Anthony
1996-07-09  0:00     ` Robert Dewar
1996-07-10  0:00   ` Ronald Cole
1996-07-11  0:00     ` Robert Dewar
1996-07-11  0:00     ` Richard Kenner
1996-07-11  0:00   ` Jon S Anthony
1996-07-11  0:00   ` Jon S Anthony
1996-07-11  0:00     ` Robert Dewar
1996-07-11  0:00   ` Jon S Anthony
1996-07-11  0:00     ` Robert Dewar
1996-07-15  0:00       ` Mark A Biggar
1996-07-15  0:00         ` Robert Dewar
1996-07-11  0:00     ` Tucker Taft
1996-07-17  0:00       ` Brian Rogoff
1996-07-12  0:00     ` Jon S Anthony
1996-07-12  0:00       ` Robert Dewar
1996-07-15  0:00     ` Jon S Anthony
1996-07-15  0:00       ` Robert Dewar
1996-07-12  0:00   ` Brian Rogoff
1996-07-16  0:00     ` Magnus Kempe
1996-07-14  0:00   ` Ronald Cole
1996-07-14  0:00     ` Robert Dewar
1996-07-15  0:00   ` Jon S Anthony
1996-07-15  0:00     ` Robert Dewar
1996-07-16  0:00   ` Brian Rogoff
1996-07-24  0:00 ` Jon S Anthony
1996-07-25  0:00 ` Jon S Anthony
1996-07-25  0:00 ` Fergus Henderson
1996-07-25  0:00   ` David Kristola
1996-07-26  0:00     ` Robert A Duff
1996-07-30  0:00       ` David Kristola
1996-07-30  0:00       ` Thomas Wolff
1996-07-30  0:00         ` Robert A Duff
1996-07-26  0:00   ` Robert A Duff
1996-07-26  0:00     ` Fergus Henderson
1996-07-28  0:00       ` Robert A Duff
1996-07-28  0:00         ` Fergus Henderson
  -- strict thread matches above, loose matches on Subject: below --
1996-07-05  0:00 tmoran
1996-07-06  0:00 ` Robert A Duff
1996-07-15  0:00 tmoran
1996-07-15  0:00 ` Robert Dewar
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox