From: josephoswald+gg on
On Aug 6, 9:12 am, "Frode V. Fjeld" <fr...(a)netfonds.no> wrote:
> "josephoswald...(a)gmail.com" <josephosw...(a)gmail.com> writes:
> > [...] Requiring a programmer to use a completely different syntax to
> > *turn on* a low-level optimization is backward.  Having control over
> > how the compiler weights various trade-offs is good.
>
> I find this completely backwards. If your code depends on TCO, then by
> definition it is not a low-level optimization, it is rather the required
> semantics of your code.
>
> >  Having to formally request help from the compiler with a "yes-I-
> > the-programmer-can-see-this-is-a-tail-call" form is a pain.
>
> Again, if your program requires TCO then the programmer must know and
> see that "this is a tail call". See any introductory textbook on "tail
> call style" iteration and you know that the programmer must be painfully
> aware of whether a particular call is a tail call or not, sometimes
> twisting the code inside out to make it so. The only difference is
> whether this required aspect of the program's semantics will be explitly
> manifested in the program text or not. For the maintainer of said
> program, having these required semantics explicitly and plainly
> expressed would be a pleasure, I'm sure.
>
> --
> Frode V. Fjeld

I'm aware of the distinct shape of code that fully exploits TCO, and
as a CL programmer, I've basically decided I don't want to write my
programs that way. (And, as PJB noted, TCO is harder to exploit in
CL.)

I still feel that marking tail calls taking advantage of TCO with a
distinct marker is silly. To me, it is as silly as marking functions
using recursion with a special (defun-recursive fib (n) ...) because,
after all, maybe we want to reserve DEFUN for Fortran IV calling
conventions, and if we require our function to work when called
recursively, we ought to mark it as so in the program text.

Programmers implicitly require LOTS of assumptions; TCO is just one
possible example. Every CL programmer who writes a recursive call has
to understand what it would take to blow up the stack, and deals with
it. One way is to avoid TCO-breaking CL features, use a tail-call
optimizing compiler, and put a comment in the code ";; Depends on
compiling the tail-call as a jump"

Unmarked TCO can make my stack use more efficient, for free, without
my program depending on it for survival. Why should I explicitly have
to baptize my program in the TCO church to get that benefit?

If the TCO is silently defeated because I add a dynamic binding
somewhere, or move to a different implementation, then maybe that
recursive iteration on my 1-million CONS backbone breaks. My program
also breaks if the /tmp partition fills up or any number of other
problems that I decide to live with or figure out how to avoid. If I
had to convert my program, the compiler would additionally complain at
me, reject my code, and I would still have the same problem. This kind
of "improved" compiler diagnostic is what people think is great about C
++. No thanks.
From: Pascal Costanza on
On 06/08/2010 20:39, josephoswald+gg(a)gmail.com wrote:
> On Aug 6, 9:12 am, "Frode V. Fjeld"<fr...(a)netfonds.no> wrote:
>> "josephoswald...(a)gmail.com"<josephosw...(a)gmail.com> writes:
>>> [...] Requiring a programmer to use a completely different syntax to
>>> *turn on* a low-level optimization is backward. Having control over
>>> how the compiler weights various trade-offs is good.
>>
>> I find this completely backwards. If your code depends on TCO, then by
>> definition it is not a low-level optimization, it is rather the required
>> semantics of your code.
>>
>>> Having to formally request help from the compiler with a "yes-I-
>>> the-programmer-can-see-this-is-a-tail-call" form is a pain.
>>
>> Again, if your program requires TCO then the programmer must know and
>> see that "this is a tail call". See any introductory textbook on "tail
>> call style" iteration and you know that the programmer must be painfully
>> aware of whether a particular call is a tail call or not, sometimes
>> twisting the code inside out to make it so. The only difference is
>> whether this required aspect of the program's semantics will be explitly
>> manifested in the program text or not. For the maintainer of said
>> program, having these required semantics explicitly and plainly
>> expressed would be a pleasure, I'm sure.
>>
>> --
>> Frode V. Fjeld
>
> I'm aware of the distinct shape of code that fully exploits TCO, and
> as a CL programmer, I've basically decided I don't want to write my
> programs that way. (And, as PJB noted, TCO is harder to exploit in
> CL.)
>
> I still feel that marking tail calls taking advantage of TCO with a
> distinct marker is silly. To me, it is as silly as marking functions
> using recursion with a special (defun-recursive fib (n) ...) because,
> after all, maybe we want to reserve DEFUN for Fortran IV calling
> conventions, and if we require our function to work when called
> recursively, we ought to mark it as so in the program text.
>
> Programmers implicitly require LOTS of assumptions; TCO is just one
> possible example. Every CL programmer who writes a recursive call has
> to understand what it would take to blow up the stack, and deals with
> it. One way is to avoid TCO-breaking CL features, use a tail-call
> optimizing compiler, and put a comment in the code ";; Depends on
> compiling the tail-call as a jump"

I think a good option would be to have a declaration for "proper" tail
calls. Something like (declare (optimize (tail-calls 3))). The different
optimization levels could tell the compiler how hard it should try to
optimize tail calls. A global (declaim (optimize (tail-calls 3))) would
allow writing programs where the tail calls are not explicitly marked,
and macros expanding to (locally (declare (optimize (tail-calls 3)))
....) could be used for marking tail calls.

I'm not 100% sure if this could actually work, but it might...


Pascal


--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Frode V. Fjeld on
"josephoswald+gg(a)gmail.com" <josephoswald(a)gmail.com> writes:

> I'm aware of the distinct shape of code that fully exploits TCO, and
> as a CL programmer, I've basically decided I don't want to write my
> programs that way.

Me too, FWIW.

> Programmers implicitly require LOTS of assumptions; TCO is just one
> possible example.

Yes. I am of the conviction that the more assumptions that can be
succinctly and explicitly stated in the code, the better.

> Every CL programmer who writes a recursive call has to understand what
> it would take to blow up the stack, and deals with it. One way is to
> avoid TCO-breaking CL features, use a tail-call optimizing compiler,
> and put a comment in the code ";; Depends on compiling the tail-call
> as a jump"

So if you download some software from somewhere and want to compile it,
you need to first scan for such comments to see if it's compatible with
your compiler?

>
> Unmarked TCO can make my stack use more efficient, for free, without
> my program depending on it for survival. Why should I explicitly have
> to baptize my program in the TCO church to get that benefit?

There are two completely separate issues: Calls that are such that TCO
is required (or otherwise the stack will blow up), and calls that may or
may not be optimized by the compiler and the programmers doesn't mostly
care. If explicit TCO were to be introduced, it would be to address the
former. This would not preclude the latter.

> If the TCO is silently defeated because I add a dynamic binding
> somewhere, or move to a different implementation, then maybe that
> recursive iteration on my 1-million CONS backbone breaks. My program
> also breaks if the /tmp partition fills up or any number of other
> problems that I decide to live with or figure out how to avoid.

In my book, this mode of argumentation is just invalid. You can use it
to argue against any (language) feature.

> If I had to convert my program, the compiler would additionally
> complain at me, reject my code, and I would still have the same
> problem. This kind of "improved" compiler diagnostic is what people
> think is great about C ++. No thanks.

There's one valid argument along these lines against having explicit TCO
that I can see: If it is to be well-defined (per spec) whether
(explicit) TCO is allowed in every code position, then we're back to the
problem of having to define precisely where TCO is allowed. That's very
problematic.

--
Frode V. Fjeld

From: Pascal Costanza on
On 07/08/2010 17:11, Frode V. Fjeld wrote:
> "josephoswald+gg(a)gmail.com"<josephoswald(a)gmail.com> writes:
>
>> I'm aware of the distinct shape of code that fully exploits TCO, and
>> as a CL programmer, I've basically decided I don't want to write my
>> programs that way.
>
> Me too, FWIW.

I encountered a situation where the most elegant way to implement a
piece of software was by way of continuation-passing style for
expressing a loop, and the lack of reliable TCO was a slight problem. It
was not insurmountable, but I would have preferred a more elegant
solution...


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Frode V. Fjeld on
Pascal Costanza <pc(a)p-cos.net> writes:

> I encountered a situation where the most elegant way to implement a
> piece of software was by way of continuation-passing style for
> expressing a loop, and the lack of reliable TCO was a slight
> problem. It was not insurmountable, but I would have preferred a more
> elegant solution...

Yes, I have also encountered some very few cases where I'd have liked to
have (explicit) TCO. But I'm rather sceptical that--when all things
consideded--it can be added to CL in a reasonable fashion.

--
Frode V. Fjeld