From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Thread: 103376,21960280f1d61e84 X-Google-Attributes: gid103376,public X-Google-Language: ENGLISH,ASCII-7-bit Path: g2news2.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newscon06.news.prodigy.net!prodigy.net!newsfeed-00.mathworks.com!nntp.TheWorld.com!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: in defense of GC Date: Mon, 05 Feb 2007 19:01:53 -0500 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <1169531612.200010.153120@38g2000cwa.googlegroups.com> <1mahvxskejxe1$.tx7bjdqyo2oj$.dlg@40tude.net> <2tfy9vgph3.fsf@hod.lan.m-e-leypold.de> <1g7m33bys8v4p.6p9cpsh3k031$.dlg@40tude.net> <14hm72xd3b0bq$.axktv523vay8$.dlg@40tude.net> <4zwt33xm4b.fsf@hod.lan.m-e-leypold.de> <1j7neot6h1udi$.14vp2aos6z9l8.dlg@40tude.net> <1pzx3y7d2pide.y744copm0ejb$.dlg@40tude.net> <2pabzt1kzw.fsf@hod.lan.m-e-leypold.de> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls4.std.com 1170720128 21611 192.74.137.71 (6 Feb 2007 00:02:08 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Tue, 6 Feb 2007 00:02:08 +0000 (UTC) User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.3 (irix) Cancel-Lock: sha1:cabCOJVT9JOqqhVgXIKGHDuMX0k= Xref: g2news2.google.com comp.lang.ada:8985 Date: 2007-02-05T19:01:53-05:00 List-Id: Markus E Leypold writes: > Robert A Duff writes: > >> Markus E Leypold >> writes: >> >>> I do need that >>> >>> function Make_a_Stepper (K:Integer) return ... is >>> >>> N : Integer := Complicated_Function(K); >>> >>> function Stepper(F:Foo) return Foo is >>> >>> begin >>> >>> return Foo + N; >>> >>> end; >>> >>> begin >>> return Stepper; >>> end; >>> >>> would work. And no nitpicking, please, if I made syntax error here: The >>> intention should be clear. >> >> I don't think this is nitpicking: >> >> I'm not sure what you mean by the above example. Is N intended to be >> constant or variable (in Ada terms -- that's immutable/immutable in FP >> terms)? > > Ah, you see, that is the point with closures. If we were talking about > closures, N would be different for every invocation of Make_Stepper > but every Stepper returned would refer to a constant N during its > livetime. The VALUE of N is different for every.... >... THis is why they are called closure (they enclose their > environment at the instance of their instantiation which in this case > would be (in a sense) between the invocation of Make_Stepper and > before the body of Make_Stepper is executed. Agreed. >> Do you mean this: >> >> function Make_a_Stepper (K:Integer) return ... is >> N : constant Integer := Complicated_Function(K); -- I added "constant" here! **************** >> function Stepper(F:Foo) return Foo is >> begin >> return Foo + N; >> end; >> begin >> return Stepper; >> end; >> >> Or this: >> >> function Make_a_Stepper (K:Integer) return ... is >> N : Integer := Complicated_Function(K); >> function Stepper(F:Foo) return Foo is >> begin >> N := N + 1; -- I added a modification of N here! **************** >> return Foo + N; >> end; >> begin >> return Stepper; >> end; >> >> ? >> >> These two cases of so-called "upward closure" seem very different to me. > > Ah, yes, I see how that comes about, since we are not talking names > and their bindings to values here, but variables in Ada. Actually I'd > say both. The last case is no pure functional programming (just for > the record) and in OCaml would b expressed like this: > > let make_stepper k = > let n = ref (complicated k) > in > (fun f -> n := !n + 1; f + !n) > > and in the first case (just to show the difference) > > let make_stepper k = > let n = (complicated k) > in > (fun f -> f + n) > > So in (impure) FP both cases are possible and if we go back to Ada > syntax from that: Why not use the constant keyword to distinguish the > cases? Because in Ada I want local variables (local in visibility and local and lifetime). I think the Ada equivalent of OCaml's non-functional "let n = ref (complicated k)" would be: type Ref_Integer is access Integer; N: constant Ref_Integer := new Integer'(Complicated_Function(K)); That makes it clear that the integer variable we're talking about is an object allocated on the heap and therefore has who-knows-what lifetime. I have no problem with forming a closure that can see N (a constant) and passing that closure outward. My point is: I want to understand the lifetime of a variable (Ada term) by looking at its declaration. I don't care about the lifetimes of constants/values -- they can be copied willy-nilly anyway. >> (Both are of course illegal in Ada, but we're discussing what "ought" to be.) > > Ehm. And I'm thankful for you rather insightful input :-). Thanks for saying so. And I'm thankful to you for helping me understand these conceptual issues. :-) >> In the former case, we're returning a function that looks at some local >> value (the value of N). In this case, you comment about returning >> integer values is quite correct: >> >>>> Closure don't "make things global". They do it as much as returning an >>>> Integer, makes, GOD FORBID!, a value global (don't return Integers >>>> people, that makes a value global and we all know, global is bad -- >>>> how nonsensical is that?). >> >> Right. What's the big deal? Returning a function that looks at integer >> values is no worse than returning integer values. Integer values live >> forever, and the value of N is certainly not tied to the lifetime of N. > > >> But in the latter, case, the return of Stepper is causing the lifetime >> of an integer VARIABLE (i.e. mutable) to be longer than one might >> suspect for a local variable of Make_A_Stepper. That seems like a >> problem to me. > > It's still only encapsulated _state_, the visibility of indentifiers > (scope) is not extended by that. Right. We're talking about lifetimes. Some folks in this thread may have said "scope" when they meant "lifetime". >...Outsiders can't look into the > closure. And we already have encapsulate state like this, in tagged > objects. Closure differ from objects only in 2 points: (1) they have > only one method (apply) and (2) they can take (implicitely) values > from their whole environment at the place of instantiation. > > Indeed the more I think about it, a bit compiler support (which knows > which parts of the environment are actually used in the closures > body), a new keyword (closure to distinguis them from ordinary > procedures) and all the mechanisms already present in tagged types > should be quite enough implement closure in Ada. (Well, OK, there are > problems with sharing N in the non-constant case with other closures > and other procedure which can see N, but in the constant case (which > is perhaps in the presence of object the mor important one), 'constant > N' can be just copied into a implementation object of the type > > tagged record > N : Integer; > end record; > > > >> You (Markus) seem to be an advocate of (possibly-upward) closures. > > Certainly. As I said in another post of the recent article storm, I > _think_ (think, mind you, no hard data) that if too much thinks > (narrowing of type w/o RTTI during method invocation, scope of access > types and passing procedural parameters can only be "done downwards", > some desirable structures become impossible. > >> And also an advocate of function programming. > > 'functional'. :-). Sorry, that was a typo. I meant "functional". >> So how would you like a rule that says the former example is OK, but >> the latter is illegal? > > I'd weep silently :-). > >> (That is, upward closures are allowed only when you're doing functional >> (no side-effects) programming). > > >> Note that the latter is not functional -- a call to the function that >> Make_A_Stepper returns modifies N, which is the key difference! > > Yes. That is so. But Ada is not functional any way and impure closures > have their value. This is the key point I'm interested in: why do impure outward closures have value? We can emulate that via tagged types, as you say: >...Nonetheless: Since the encapsulation of mutable > state can be done in tagged types forbidding the latter would probably > not hurt as much as in languages w/o OO. Still, that requires further > analysis of the most frequent use cases. And it seems to me there's some value in knowing that a local variable of a procedure has local lifetime. And if it doesn't, the extra syntactic baggage of tagged types or access types or whatever seems like a benefit (i.e. warning: this thing lives longer). - Bob