{"action":"opened","issue":{"url":"https://api.github.com/repos/smlsharp/smlsharp/issues/45","labels_url":"https://api.github.com/repos/smlsharp/smlsharp/issues/45/labels{/name}","comments_url":"https://api.github.com/repos/smlsharp/smlsharp/issues/45/comments","events_url":"https://api.github.com/repos/smlsharp/smlsharp/issues/45/events","html_url":"https://github.com/smlsharp/smlsharp/issues/45","id":125801586,"number":45,"title":"[機能要望] [FFI] unit ptrとSMLの型の相互運用","user":{"login":"KeenS","id":4434568,"avatar_url":"https://avatars.githubusercontent.com/u/4434568?v=3","gravatar_id":"","url":"https://api.github.com/users/KeenS","html_url":"https://github.com/KeenS","followers_url":"https://api.github.com/users/KeenS/followers","following_url":"https://api.github.com/users/KeenS/following{/other_user}","gists_url":"https://api.github.com/users/KeenS/gists{/gist_id}","starred_url":"https://api.github.com/users/KeenS/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/KeenS/subscriptions","organizations_url":"https://api.github.com/users/KeenS/orgs","repos_url":"https://api.github.com/users/KeenS/repos","events_url":"https://api.github.com/users/KeenS/events{/privacy}","received_events_url":"https://api.github.com/users/KeenS/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2016-01-10T05:44:17Z","updated_at":"2016-01-10T05:44:17Z","closed_at":null,"body":"# 問題\r\nCでは、多相型の代わりとして`void *`を使うことがありますが、それをSML#で使おうとした時にSML＃の値を渡せなくて困ることがあります。\r\n\r\n例えば`int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg)`の例だとSMLにインポートする時に\r\n\r\n```sml\r\nval pthread_create = _import \"pthread_create\" : (pthread_t ref,  pthread_attr_t ref, unit ptr -> unit ptr, unit ptr) -> int\r\n```\r\n\r\nとなりますが、unit ptrにSMLの型を渡せないので事実上第4引数の`arg`には何も渡せません。あるいは`pthread_join`も本来ならcreateの時に作った関数の返り値を受け取れる筈ですが、同様の理由で事実上何も受け取れません。\r\n\r\n# 提案\r\n* Cとの相互運用型について、`toUnitPointer`と`fromUnitPointer`を実装する\r\n* オーバーロードでそれらの関数を一纏めに扱えるようにする\r\n* 実体はただのキャスト\r\n* `unit ptr`型については幽霊型で型付けをして、型安全性を壊さないようにする\r\n\r\n## 例\r\n\r\n```sml\r\ntype pthread_t = unit ptr\r\ntype pthread_attr_t = unit ptr\r\nval pthread_create = _import \"pthread_create\" : (pthread_t ref, pthread_attr_t ref, 'a unit ptr -> 'b unit ptr, 'a unit ptr) -> int\r\nval pthread_join = _import \"pthread_join\": (pthread_t, 'a unit ptr ref) -> int\r\n\r\n(* val threadFunc: string unit ptr -> int unit ptr *)\r\nfun threadFunc arg  = let\r\n    val s = fromUnitPtr arg\r\n    val () = print s\r\n    val ret = (String.size s)\r\nin\r\n    toUnitPtr ret\r\nend\r\n                   \r\nval () = let\r\n    val thread_ref: pthread_t ref = ref _NULL\r\n    val attr_ref: pthread_attr_t ref = ref _NULL \r\n    val s = pthread_create(thread_ref, attr_ref, threadFunc, toUnitPointer \"Hello, World\\n\")\r\n    val t1 = !thread_ref\r\n    val () = if s <> 0\r\n             then OS.Process.exit OS.Process.failure\r\n             else ()\r\n    val () = print \"Message from main()\\n\";\r\n    val resRef: int unit ptr ref = ref _NULL\r\n    val s = pthread_join(t1, resRef)\r\n    val () = if s <> 0\r\n             then OS.Process.exit OS.Process.failure\r\n             else ()\r\n    val () = print (\"Thread returned\" ^ Int.toString  (fromUnitPointer (!resRef)) ^ \"\\n\")\r\nin\r\n    ()\r\nend\r\n```\r\n\r\nこの例ではあまり無理のないようにしましたがやろうと思えば`pthread_t`型にも幽霊型を付ければ`pthread_join`も正しく型付け出来る筈です。\r\n\r\n## 細かい部分\r\n* (C言語的には未規定動作ですが) intに対して`toUnitPtr`を呼ぶと`int unit ptr`になり、`int ptr`などにはならない。つまり、intのポインタを取るのではなく、intをそのまま(void *)にキャストする。\r\n* refも同じく。つまり、`int ref`を`toUnitPtr`するのはCでいえば`int *`を`void *`にキャストするのと同じ。\r\n\r\n\r\nSML#のC FFIはすごい面白い機能だと思っているのですが微妙にかゆいところに手が届かないので要望を上げさせて頂きました。型システムにどこまで影響するのか分かってないのですが可能そうなら実現していただけると幸いです。"}}