Skip to content

No default marshallers for Char #98

Closed
@RyanGlScott

Description

@RyanGlScott

Currently, C's char types can be marshalled to and from Integral types via the default marshaller fromIntegral. Unfortunately, this makes it difficult to use Haskell's own Char type alongside C's, since Char is not an instance of Integral. For example,

/* foo.h */
#ifndef FOO_H
#define FOO_H

char identichar(char c);
unsigned char identiuchar(unsigned char c);
signed char identischar(signed char c);

#endif
/* foo.c */
#include "foo.h"

char identichar(char c) {
    return c;
}

unsigned char identiuchar(unsigned char c) {
    return c;
}

signed char identischar(signed char c) {
    return c;
}
-- Main.chs
{-# LANGUAGE ForeignFunctionInterface #-}
module Main where

import Foreign.C.String

#include "foo.h"

{#fun pure identichar  as ^ { `Char' } -> `Char' #}
{#fun pure identiuchar as ^ { `Char' } -> `Char' #}
{#fun pure identischar as ^ { `Char' } -> `Char' #}

main :: IO ()
main = print $ map ($ 'A') [identichar, identiuchar, identischar]

Preprocessing this with c2hs reveals this:

c2hs: Errors during expansion of binding hooks:

./Main.chs:9: (column 43) [ERROR]  >>> Missing "out" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CSChar
./Main.chs:8: (column 43) [ERROR]  >>> Missing "out" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CUChar
./Main.chs:7: (column 43) [ERROR]  >>> Missing "out" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CChar

So one must manually provide out marshallers:

import Foreign.C.String
import Foreign.C.Types

{#fun pure identichar  as ^ { `Char' } -> `Char' castCCharToChar  #}
{#fun pure identiuchar as ^ { `Char' } -> `Char' castCUCharToChar #}
{#fun pure identischar as ^ { `Char' } -> `Char' castCSCharToChar #}

This, in turn, reveals the lack of in marshallers for Char:

c2hs: Errors during expansion of binding hooks:

./Main.chs:11: (column 31) [ERROR]  >>> Missing "in" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CSChar
./Main.chs:10: (column 31) [ERROR]  >>> Missing "in" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CUChar
./Main.chs:9: (column 31) [ERROR]  >>> Missing "in" marshaller!
  There is no default marshaller for this combination of Haskell and C type:
  Haskell type: Char
  C type      : CChar

So the final workaround ends up being pretty verbose:

{#fun pure identichar  as ^ { castCharToCChar  `Char' } -> `Char' castCCharToChar  #}
{#fun pure identiuchar as ^ { castCharToCUChar `Char' } -> `Char' castCUCharToChar #}
{#fun pure identischar as ^ { castCharToCSChar `Char' } -> `Char' castCSCharToChar #}

Is it possible to have these marshallers be the defaults for Haskell's Char?

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions