Ticket #1311 (new feature request)

Opened 6 years ago

Last modified 5 years ago

newtypes of unboxed types disallowed - documentation bug and/or feature request

Reported by: Isaac Dupree Owned by:
Priority: low Milestone: _|_
Component: Compiler Version: 6.6.1
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: Difficulty: Unknown
Test Case: Blocked By:
Blocking: Related Tickets:

Description

Tested in 6.6.1 and today's 6.7 (which claims to be version 6.7.20070418),

newtype FastBool = FastBool Int#

doesn't work. However this is not documented in the unboxed-types documentation in the User's Guide that lists similar restrictions http://www.haskell.org/ghc/docs/latest/html/users_guide/primitives.html

Similarly (maybe), in phantom type arguments, even in GADTs where kind inference could be at work

data Boo a where Boo :: Int# -> Boo Int#

doesn't work.

I tried newtype ( FastBool :: # ) = ... , and data Boo ( a :: # ) where... , which just confused GHC.

Is there a reason that coercions of unlifted types shouldn't work, or is it just unimplemented? (inspired by looking at GHC's compiler/utils/FastTypes.lhs and thinking that using newtypes instead of type synonyms in places like that would improve type-safety)

Change History

Changed 6 years ago by brian@…

I think newtype FastBool = FastBool Int# could potentially work. There are a bunch of places where the compiler assumes newtypes are lifted but that could be fixed. The newtype would have all the limitations of unlifted types though. You still couldn't use it in polymorphic functions or anything (which might be somewhat surprising to users of your code). Probably a better use of time would be to make SpecConstr turn enumeration types into Int#s, thus eliminating the need for FastBool? altogether.

As a side note, isn't FastBool? kind of broken by design? You can't really do anything useful with it other than turning it back into a plain old Bool. and#/or# don't make sense as they must be strict in both of their arguments (which probably isn't what you want).

The GADT example can't really work as you can't forall over unboxed tyvars. You can't write:

unBoo :: forall (a::#) . Boo a -> a

as a could have a completely different representation depending on how it was instantiated. You could probably make it so

unBoo :: Boo Int# -> Int#

would work but why not just write BooInt = BooInt Int# at that point.

-Brian

Changed 6 years ago by Isaac Dupree

I'm not seeing a way it would actually be useful for GADTs either, since you can't do anything with a general value of kind '#'.

It would be nice to be able to do enumerations more cleanly than that numerical way, but... As far as I have been able to figure out, the advantage of using unboxed values is that the compiler enforces that you can't use them in a non-strict way, potentially making code more efficient (versus the compiler guessing what places to unbox data implicitly) (and having less strictness annotations in the source code, even where it is effectively strict [function arguments, data members, let-bound variables], which has its pros and cons). The trouble with enumeration types is that they are boxed normally: a function can take a Bool thunk that, iff the function decides to evaluate it, will raise an exception.

Being able to newtype for FastInt? makes sense, though, for the same abstraction reason of all newtypes - of course with the odd property of it being unlifted and not type-equal to any of the standard unlifted types.

(what if we could declare data ( FastBool :: # ) = FastTrue | FastFalse, or even allow different data sizes and it takes up an amount of space equal to any necessary tag plus the maximum member: data ( FastEither a b :: # ) = FastLeft a | FastRight !b {-members may or may not be strict-} , data ( FastTuple a b :: # ) = FastTuple a b {- would this be equivalent to (# #) ? -} ? Probably at least some of that is a foolish idea... Let's performance-test GHC with/without using those unboxed, maybe)

Changed 6 years ago by simonpj

  • priority changed from normal to low
  • type changed from bug to feature request
  • milestone set to _|_

I can't see any reason this would be impossible in principle, but my brain is too small to figure out all the ramifications of dropping the "newtypes are always boxed" assumption that GHC currently makes.

So for now I have simply added the restriction to the user manual, and I'll leave this suggestion as a feature request.

Simon

Changed 5 years ago by simonmar

  • architecture changed from Unknown to Unknown/Multiple

Changed 5 years ago by simonmar

  • os changed from Unknown to Unknown/Multiple
Note: See TracTickets for help on using tickets.