there isn't any difference, is there, with unboxed tuples?

--> unboxed types in function results are automatically "lifted"... or what was the term meaning they could be _|_, failing to terminate, (because of the function-ness)? --> unboxed tuples are specially restricted to be only allowed, among useful places, in function results. Therefore (... -> ( a, b, c ) ) and (... -> (# a, b, c #)) are identical, assuming both are kind-correct (identical in terms of optimization and semantics, not type equality, of course). Is that right? If so, there's never an excuse to use unboxed tuples except to contain unboxed values (because then you don't have the choice of using boxed tuples, which can only contain boxed values of kind *). ~Isaac

On Fri, Jan 04, 2008 at 09:36:33PM -0500, Isaac Dupree wrote:
--> unboxed types in function results are automatically "lifted"... or what was the term meaning they could be _|_, failing to terminate, (because of the function-ness)?
--> unboxed tuples are specially restricted to be only allowed, among useful places, in function results.
Therefore (... -> ( a, b, c ) ) and (... -> (# a, b, c #)) are identical, assuming both are kind-correct (identical in terms of optimization and semantics, not type equality, of course). Is that right? If so, there's never an excuse to use unboxed tuples except to contain unboxed values (because then you don't have the choice of using boxed tuples, which can only contain boxed values of kind *).
Semantically, you are absolutely correct. However, there is a very subtle difference in sharing. Consider these two functions: foo (a,b) = (a,b) bar tuple = tuple These two functions are denotationally identical, but at runtime one performs more allocations. If we use unboxed tuples, then the caller must always allocate if a tuple is needed; thus effectively we always get the allocation behavior of foo. That is, return unboxing is not always an optimization! However, it *is* always safe if the tuple is constructed in the function itself, for then it could not possibly be shared with anything. Having explicit unboxed tuples in the language allows this complexity to be moved out of the code generator, which is a Good Thing. (Incidentally, this is what the CPR analysis is all about - identifying places where a Constructed Product is Returned.) Stefan

Stefan O'Rear wrote:
Semantically, you are absolutely correct. However, there is a very subtle difference in sharing.
Consider these two functions:
foo (a,b) = (a,b) bar tuple = tuple
These two functions are denotationally identical, but at runtime one performs more allocations. If we use unboxed tuples, then the caller must always allocate if a tuple is needed; thus effectively we always get the allocation behavior of foo. That is, return unboxing is not always an optimization! However, it *is* always safe if the tuple is constructed in the function itself, for then it could not possibly be shared with anything. Having explicit unboxed tuples in the language allows this complexity to be moved out of the code generator, which is a Good Thing. (Incidentally, this is what the CPR analysis is all about - identifying places where a Constructed Product is Returned.)
hmm. so it might have to be some hypothetical syntax like (... -> {-#UNPACK#-} (a, b)) when in a data type (for some monad definition in GHC's code, so I don't want to lose performance by boxing it). (Either that or it might actually be more efficient if it were boxed!) Am I right that CPR analysis can look at particular functions, but there's no way for it to change the representation of a function stored in a data/newtype? ~Isaac
participants (2)
-
Isaac Dupree
-
Stefan O'Rear