<div dir="ltr">-1 from me.<div><br></div><div>Your first example even provides a counter-example.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
<font face="courier new, monospace"><span style="font-size:12.727272033691406px">    typedef enum {<br></span><span style="font-size:12.727272033691406px">        IMG_INIT_JPG = 0x00000001,<br></span><span style="font-size:12.727272033691406px">        IMG_INIT_PNG = 0x00000002,<br>
</span><span style="font-size:12.727272033691406px">        IMG_INIT_TIF = 0x00000004,<br></span><span style="font-size:12.727272033691406px">        IMG_INIT_WEBP = 0x00000008<br></span><span style="font-size:12.727272033691406px">    } IMG_InitFlags;</span></font></blockquote>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">Those are defined as powers of two because they are a bit mask you have to be able to (</span><span style="font-size:12.727272033691406px"><font face="courier new, monospace">.|.)</font></span><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"> together.</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">This is the sort of thing people write .hsc files for, so they can include the appropriate header directly and resolve the constants.</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">Maintaining a separate copy of an enum that goes out of date with the C version is a recipe for breaking on future versions of the dependency, and in my experience the majority of cases where the range is discontinuous arise from when the thing in question is a mask, like this very case.</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">The remaining cases where you really want to incur all those obligations are few enough and far enough between that going through a quasiquoter seems to be the right solution.</span></div>
<div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px"><br></span></div><div><span style="font-family:arial,sans-serif;font-size:12.727272033691406px">-Edward</span></div></div><div class="gmail_extra">
<br><br><div class="gmail_quote">On Thu, Apr 17, 2014 at 10:19 AM, Merijn Verstraaten <span dir="ltr"><<a href="mailto:merijn@inconsistent.nl" target="_blank">merijn@inconsistent.nl</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Cross-post to haskell-prime in case there's any interest for including this into the report's FFI specification.<br>
<br>
Proposal - Foreign enum support<br>
===============================<br>
<br>
At the moment the FFI does not have a convenient way with interacting enums<br>
(whether proper enums or CPP defines) in C (like languages). Both enums and CPP<br>
defined enums are major parts of large C APIs and they are thus crucial to<br>
writing foreign bindings. A few examples:<br>
<br>
SDL_image defines the following enum:<br>
<br>
    typedef enum {<br>
        IMG_INIT_JPG = 0x00000001,<br>
        IMG_INIT_PNG = 0x00000002,<br>
        IMG_INIT_TIF = 0x00000004,<br>
        IMG_INIT_WEBP = 0x00000008<br>
    } IMG_InitFlags;<br>
<br>
OpenCL specifies the following typedefs + CPP defined enum:<br>
<br>
    typedef uint32_t  cl_uint     __attribute__((aligned(4)));<br>
    typedef cl_uint   cl_platform_info;<br>
<br>
    /* cl_platform_info */<br>
    #define CL_PLATFORM_PROFILE                         0x0900<br>
    #define CL_PLATFORM_VERSION                         0x0901<br>
    #define CL_PLATFORM_NAME                            0x0902<br>
    #define CL_PLATFORM_VENDOR                          0x0903<br>
    #define CL_PLATFORM_EXTENSIONS                      0x0904<br>
<br>
OpenCL functions will return the above CPP defines as return values of type<br>
cl_platform_info.<br>
<br>
Current Solutions<br>
-----------------<br>
<br>
In many cases someone wrapping such a C library would like to expose these<br>
enums as a simple sum type as this has several benefits: type safety, the<br>
ability to use haskell constructors for pattern matching, exhaustiveness<br>
checks.<br>
<br>
Currently the GHC FFI, as specified by Haskell2010, only marshalls a small set<br>
of foreign types and newtypes with exposed constructors of these types. As such<br>
there seem two approaches to wrap these enums:<br>
<br>
 1. Implement an ADT representing the enum and write a manual conversion<br>
    function between the ADT and the corresponding C type (e.g. CInt -> Foo and<br>
    Foo -> CInt).<br>
<br>
 2. Use a tool like c2hs to automatically generate the ADT and conversion<br>
    function.<br>
<br>
In both cases the foreign functions are imported using the corresponding C type<br>
in their signature (reducing type safety) and the user is forced write trivial<br>
wrappers for every imported function to convert the ADT to the relevant C type<br>
and back.<br>
<br>
This is both tedious to write and costly in terms of code produced, in case of<br>
c2hs one calls "toEnum . fromIntegral" and "fromIntegral . fromEnum" for every<br>
argument/result even though this could trivially be a no-op.<br>
<br>
Worse, since c2hs uses the Enum class for it's conversion to/from C types it<br>
generates Enum instances like:<br>
<br>
    instance Enum Foo where<br>
        fromEnum Bar = 1<br>
        fromEnum Baz = 1337<br>
<br>
        toEnum 1 = Bar<br>
        toEnum 1337 = Baz<br>
        toEnum unmatched = error ("PlatformInfo.toEnum: Cannot match " ++ show unmatched)<br>
<br>
Since succ/pred and enumFromTo's default implementations assume enums convert<br>
to continuous sequence of Int this means the default generated enum instances<br>
crash. This problem could be overcome by making c2hs' code generation smarter,<br>
but this does not eliminate the tediousness of wrapping all foreign imported<br>
functions with marshalling wrappers, NOR does it eliminate the overhead of all<br>
this useless marshalling.<br>
<br>
Proposal<br>
--------<br>
<br>
Add a new foreign construct for enums, the syntax I propose below is rather<br>
ugly and ambiguous and thereforeopen to bikeshedding, but I prefer explaining<br>
based on a concrete example.<br>
<br>
    foreign enum CInt as Foo where<br>
        Bar = 1<br>
        Baz<br>
        Quux = 1337<br>
        Xyzzy = _<br>
<br>
This would introduce a new type 'Foo' with semantics approximately equivalent<br>
too "newtype Foo = Foo CInt" plus the pattern synonyms "pattern Bar = Foo 1;<br>
pattern Baz = 2; pattern Quux = 1337; pattern Xyzzy = Foo _".<br>
<br>
Explicit listing of the value corresponding to a constructor should be<br>
optional, missing values should just increment by one from the previous (like<br>
C), if the initial value is missing, it should assume to start from 0. Values<br>
do not need to be contiguous.<br>
<br>
Users should be able to use these constructors as normal in pattern match<br>
(really, this mostly follows to semantics of the above pattern synonyms).<br>
<br>
The foreign import/export functionality should invisibly marshall Foo to the<br>
underlying foreign type (as is done for newtypes).<br>
<br>
I'm unsure about the support for a wildcard constructor like Xyzzy. If there is<br>
support for a wildcard, it should be optional. On the upside a wildcard means<br>
the marshalling is no longer a partial function. The downside is that it makes<br>
desugaring the use of enums in patterns harder. It seems clear that<br>
<br>
    f Xyzzy = {- ... -}<br>
    f Bar = {- ... -}<br>
    f Baz = {- ... -}<br>
    f Quux = {- ... -}<br>
<br>
Should not have the same semantics as:<br>
<br>
    f (Foo _) = {- ... -}<br>
    f (Foo 1) = {- ... -}<br>
    f (Foo 2) = {- ... -}<br>
    f (Foo 1337) = {- ... -}<br>
<br>
So in the presence of wildcards, the Foo enum can't trivially be desugared into<br>
pattern synonyms after checking exhaustiveness.<br>
<br>
Pros:<br>
 1. Foreign imports are slightly more type safe, as one can now write:<br>
<br>
        foreign import ccall "someFoo.h" someFoo :: Foo -> Ptr () -> IO ()<br>
<br>
    Preventing users from passing an arbitrary CInt to an argument expecting a<br>
    specific enum.<br>
<br>
 2. No need to write marshalling functions to/from ADT to obtain exhaustiveness<br>
    checks and pattern matching<br>
<br>
 3. Cheaper as marshalling Foo to CInt is a no-op<br>
<br>
 4. toEnum/fromEnum can simply map to contiguous sequence of Int as this Int<br>
    mapping is no longer used for marshalling<br>
<br>
Cons:<br>
 1. Non-standard extension of the FFI<br>
<br>
 2. Someone has to implement it<br>
<br>
 3. Wildcards constructors would present difficulties desugaring pattern<br>
    matches to a simple newtype.<br>
<br>
 4. ??<br>
<br>
What Would Need to be Done?<br>
---------------------------<br>
<br>
1. Parser needs to be extended to deal with parsing of enum declarations.<br>
2. Pattern matches of an enum type need to be checked for exhaustiveness and<br>
   desugared to the underlying type's representation.<br>
3. Extend foreign imports/exports to marshall enums properly.<br>
<br>
If there's no objections I'm willing to take a stab at implementing this,<br>
although I'd probably need some help with GHC's internals (although I could bug<br>
#ghc for that).<br>
<br>
Cheers,<br>
Merijn<br>
<br>_______________________________________________<br>
ghc-devs mailing list<br>
<a href="mailto:ghc-devs@haskell.org">ghc-devs@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/ghc-devs" target="_blank">http://www.haskell.org/mailman/listinfo/ghc-devs</a><br>
<br></blockquote></div><br></div>