[bitc-dev] Opinions wanted: Infix shift operators
Jonathan S. Shapiro
shap at eros-os.org
Mon Aug 9 11:30:45 PDT 2010
I want to thank you first for sticking with this discussion. Your comments
have been very helpful, and I greatly appreciate them.
On Sat, Aug 7, 2010 at 5:22 PM, wren ng thornton <wren at freegeek.org> wrote:
> Jonathan S. Shapiro wrote:
> > When the uncurrying is mandatory (that is:
> > prescriptive), it is an *error* for the compiler to *ever* emit the
> > uncurried form. When this is the case, the two types
> > int -> int -> int
> > int X int -> int
> No, it's not an error, because it's trivial to define the higher-order
> functions necessary to coerce between them; if functions can return
> functions, then any time you define one of those functions the other is
> guaranteed to be definable....
Believe it or not, I think this example lies at the heart of how we are
talking past each other in the present discussion. It also speaks to your
earlier question about why arity has special meaning in BitC.
Before I try to explain, let me begin by acknowledging that the current
position in BitC may be the result of a cascade of poor decisions, so the
net outcome of the present discussion may simply be that we made a design
mistake by replacing tuples with pairs. Humorously, I had a draft message
planned that contained several points you have since made here.
So let's talk about why, *in BitC*, it is an error to do curried application
in the int X int -> int case. Semantically, I agree with your statement
about coercion functions. The problem arises because BitC is a systems
programming language, and is consequently very concerned about effects on
the heap. Given a definition like:
def add x y = x + y;
and a partial application "add x", I must form a closure. This has an effect
on the heap, which is something that we want to have be very explicit in a
systems language. By contrast, the application that provides
*both*arguments can form a frame on the stack directly.
So the two are semantically inter-convertable, but not semantically the
same. And the problem with the currying syntax from the standpoint of a
systems language is that it obscures when heap allocation may occur.
And the problem with relying on arity-lifting for this is that it's an
optimization, and it is sometimes (and from the programmer perspective,
unpredictably) forced to fall back on the closure construction. Further,
much of the success of arity lifting appears to rely on cross-module
analysis, so there is a modularity concern at compile time in relying on
> It's perfectly fine for the FFI to use uncurried types in order to
> support direct linking against foreign code. But arity is no more a
> special part of the type here than it is for the curried form. You're
> just passing in a tuple instead of passing arguments individually; the
> number of arguments passed is the same regardless. And you always have
> all the arguments by the time the function is executed (unless you plan
> to support partial evaluation).
Yes. One of the points that I made in my pending draft, and that you also
made, is that tuples can be defined as unboxed. If they are, then we can
adopt a calling convention in which a function taking a single argument of
tuple type will have the tuple elements allocated to registers *as if* we
had performed the corresponding higher arity call in C. That is:
def add_curried x y = x + y // behavior depends on lifting
def add (x,y) = x + y // guaranteed to register allocate
what is modestly ironic about this is that it brings us full circle; in
order to obtain register allocation guarantees, systems programs will always
use the tupleized form, with the result that we will not achieve the *
syntactic* sparsity that people here seem to be wanting.
And it raises another, unfortunate complication: in order to use tuples as
parameters in this way, we need to be able to form tuples over non-escaping
references, which *may* mean that we need to deal with non-escaping tuples
and non-escaping aggregates in general. This requirement is introduced by
the presence of by-reference parameter passing in BitC.
In the special case of function parameters, the tuple is anonymous and
thereby non-escaping, so we may be okay there.
> Whether we choose to call a type C<A,B> vs (C A B) should not have any
> impact whatsoever on native calling conventions....
I agree. This is purely a syntactic matter, and one that needs to be decided
as a matter of comprehension by the programmer.
-------------- next part --------------
An HTML attachment was scrubbed...
More information about the bitc-dev