Skip to content

Commit be83ba1

Browse files
committed
Address review feedback
1 parent b6d9041 commit be83ba1

File tree

1 file changed

+43
-26
lines changed

1 file changed

+43
-26
lines changed

manual/LowLevel/Functions.md

Lines changed: 43 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,16 @@ conventions: `safe` and `unsafe`. The distinction is important:
1515
because they avoid this overhead, but using `unsafe` incorrectly can lead to
1616
undefined behavior.
1717

18-
Currently, `hs-bindgen` generates all function imports using the `safe` calling
19-
convention:
18+
To give users control over this choice, `hs-bindgen` generates two separate
19+
modules for function bindings:
2020

21-
```hs
22-
foreign import ccall safe "B_function_name"
23-
function_name :: CInt -> IO CInt
24-
```
21+
* `ModuleName.Safe` - contains all function imports using the `safe` calling
22+
convention
23+
* `ModuleName.Unsafe` - contains all function imports using the `unsafe`
24+
calling convention
2525

26-
This is a conservative choice that ensures correctness in all cases. While it
27-
means we pay the cost of the safe calling convention even for functions that
28-
do not need it, this cost is typically negligible unless the function is called
29-
in a tight loop. Users who require the performance of `unsafe` imports can
30-
manually wrap the generated bindings with their own `unsafe` imports after
31-
verifying that the C function does not call back into Haskell.
26+
Both modules export identical APIs, differing only in their calling convention.
27+
Users can import from whichever module best suits their needs.
3228

3329
## Function addresses
3430

@@ -280,10 +276,27 @@ instance FromFunPtr ProgressUpdate_Deref where
280276
A function pointer will have a `ToFunPtr` and `FromFunPtr` instance if at
281277
least one of its arguments contains at least one domain specific type. This
282278
check is done recursively so higher order functions will be inspected
283-
correctly. If the arguments for function pointer don't specify any domain
284-
specific type no instances are generated. This is done to avoid orphan
285-
instances and to avoid generating multiple instances for the same type
286-
signature.
279+
correctly.
280+
281+
For the purpose of instance generation, **domain-specific types** are types
282+
defined in the generated bindings for the specific C library being bound,
283+
such as:
284+
- Structs and their fields
285+
- Enums and typedefs
286+
- Function pointer wrapper types
287+
288+
Conversely, **non-domain-specific types** are standard FFI types from GHC's
289+
base libraries, such as `CInt`, `CDouble`, `Ptr a`, `IO ()`, etc.
290+
291+
For example:
292+
- `ProgressUpdate_Deref` with type `CInt -> IO ()` **will** get instances
293+
because `ProgressUpdate_Deref` itself is domain-specific.
294+
- A hypothetical function pointer type `CInt -> IO CInt` **will not** get
295+
instances because both `CInt` and `IO CInt` are non-domain-specific.
296+
297+
This distinction is important to avoid orphan instances and to prevent
298+
generating multiple instances for the same type signature when binding
299+
different C libraries.
287300
288301
#### Wrapping Haskell functions
289302
@@ -376,23 +389,27 @@ extend the set of supported function signatures beyond what GHC's `capi`
376389
provides. For instance, we can handle by-value struct arguments and return
377390
values, which `capi` does not support.
378391
379-
The generated wrappers are named with a prefix based on the Haskell module
380-
name. For example, a C function `foo` might have a wrapper `B_foo` that we
381-
import instead:
392+
The generated wrappers use hash-based names to prevent potential name
393+
collisions. For example, a C function `print_point` might have a wrapper named
394+
`hs_bindgen_test_example_a1b2c3d4e5f6g7h8`:
382395
383396
```c
384397
// Generated C wrapper
385-
void B_print_point ( struct point * arg1 ) {
398+
void hs_bindgen_test_example_a1b2c3d4e5f6g7h8 ( struct point * arg1 ) {
386399
print_point ( arg1 );
387400
}
388401
```
389402
390403
```hs
391404
-- Generated Haskell import
392-
foreign import ccall "B_print_point"
405+
foreign import ccall "hs_bindgen_test_example_a1b2c3d4e5f6g7h8"
393406
print_point :: Ptr Point → IO ()
394407
```
395408
409+
This hash-based naming ensures that even if multiple functions have similar
410+
names or signatures, their wrappers will have unique names, avoiding linker
411+
errors from symbol collisions.
412+
396413
This userland CAPI approach is used for all function imports in `hs-bindgen`,
397414
not just those with features GHC cannot handle directly. This provides a
398415
uniform interface and makes it straightforward to add support for additional
@@ -408,20 +425,20 @@ struct point byval ( struct point p );
408425
```
409426
410427
This function cannot be imported directly. Instead, `hs-bindgen` generates a C
411-
wrapper that accepts and return struct by pointer, performing the necessary
428+
wrapper that accepts and returns structs by pointer, performing the necessary
412429
conversions:
413430
414431
```c
415-
void B_byval ( struct point * arg
416-
, struct point * res ) {
432+
void hs_bindgen_example_9a8b7c6d5e4f3210 ( struct point * arg
433+
, struct point * res ) {
417434
* res = byval (* arg );
418435
}
419436
```
420437
421438
This wrapper is then imported in Haskell:
422439
423440
```hs
424-
foreign import ccall safe "B_byval"
441+
foreign import ccall safe "hs_bindgen_example_9a8b7c6d5e4f3210"
425442
byval_wrapper :: Ptr Point Ptr Point IO ()
426443
```
427444
@@ -433,7 +450,7 @@ byval :: Point → IO Point
433450
byval p =
434451
with p $ \ arg
435452
alloca $ \ res do
436-
B. byval_wrapper arg res
453+
byval_wrapper arg res
437454
peek res
438455
```
439456

0 commit comments

Comments
 (0)