# Good etiquette with wrapping a c-library

**URL:** <https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881>\
**Category:** General Usage\
**Created:** [June 30, 2026, 6:28pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881 "2026-06-30T18:28:49Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [June 30, 2026, 6:28pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/1 "2026-06-30T18:28:49Z")

</div>

I am slowly wrapping a [C-library](https://github.com/Spectrum-Tec/MccDaqHats.jl)in Julia. The [c-library](https://mccdaq.github.io/daqhats/c.html#c.mcc172_firmware_version) often gives a resultcode which indicates success or various problems. I am wondering what the preferred way of dealing with the resultcode is.

1. Pass the resultcode to the calling program for it to either ignore or deal with it.
2. If the resultcode indicates success, ignore it, otherwise print an error message
3. Both 1 & 2
4. Another option?

So far I have taken approach 2. I am wondering if I should transition to option 3 or a modified version of it. I suppose there may be times when the calling program might have logic that depends upon the resultcode.

Before going further, I though I would ask the community for which option is the best practice.

An example code snippet exhibiting option 3 behaviour follows:

```julia-auto
function mcc172_firmware_version(address::Integer)
	version = Ref{UInt16}()
	resultcode = ccall((:mcc172_firmware_version, libdaqhats), 
		Cint, (UInt8, Ref{Cushort}), address, version)
	printerror(resultcode)
	return (resultcode, version[])
end

```

with the printerror function causing an error if the resultcode is not successful, which may not be the ideal either.

```julia-auto
function printerror(resultcode)
	# map resultcode to descriptive string
	resultDict = Dict{Int32, String}(
		0 => "Success, no errors",
		-1 => "A parameter passed to the function was incorrect.",
		-2 => "The device is busy.",
		-3 => "There was a timeout accessing a resource.",
		-4 => "There was a timeout while obtaining a resource lock.",
		-5 => "The device at the specified address is not the correct type.",
		-6 => "A needed resource was not available.",
		-7 => "Could not communicate with the device.",
		-10 => "Some other error occurred.")
	if resultcode != 0
		# @show(resultcode)
		error(resultDict[resultcode])
	end
end

```

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [June 30, 2026, 6:54pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/2 "2026-06-30T18:54:49Z")

</div>

You could consider using an [Enum](https://docs.julialang.org/en/v1/base/base/#Base.Enums.@enum) or [CEnum](https://github.com/JuliaInterop/CEnum.jl):

```julia-repl
julia> @enum MCC172ErrorCode begin
           success = 0
           incorrect_parameter = -1
           device_busy = -2
           resource_timeout = -3
           resource_lock_timeout = -4
           device_not_correct_type = -5
           resource_not_available = -6
           no_device_communication = -7
           other_error = -10
       end

julia> success
success::MCC172Error = 0

```

Another idea would be to create your own error type.

```julia-auto
const MCC172ErrorDict = Dict{MCC172ErrorCode, String}(
		success => "Success, no errors",
		incorrect_parameter => "A parameter passed to the function was incorrect.",
		device_busy => "The device is busy.",
		resource_timeout => "There was a timeout accessing a resource.",
		resource_lock_timeout => "There was a timeout while obtaining a resource lock.",
		device_not_correct_type => "The device at the specified address is not the correct type.",
		resource_not_available => "A needed resource was not available.",
		no_device_communication => "Could not communicate with the device.",
		other_error => "Some other error occurred."
)

struct MCC172Error <: Exception
    id::MCC172Error
end

function Base.showerror(io::IO, e::MCC172Error)
	# map resultcode to descriptive string
	if resultcode != success
		print(io, MCC172ErrorDict[e.id])
	end
end

```

```julia-repl
julia> throw(MCC172Error(incorrect_parameter))
ERROR: A parameter passed to the function was incorrect.
Stacktrace:
 [1] top-level scope
   @ REPL[39]:1

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [June 30, 2026, 6:59pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/3 "2026-06-30T18:59:37Z")

</div>

> [@Jake](#):
>
> 1. If the resultcode indicates success, ignore it, otherwise print an error message

Don’t print a message, throw an exception, but it looks like that’s what your `printerror` function actually does.

A useful tweak is to not pay the price of constructing the error string unless the error is printed, by throwing a custom exception type.

Something like:

```julia-auto
struct MyError <: Exception
    code::Cint
end
const myerror_message = Dict{Cint, String}(... #= error messages =# ...)
function Base.showerror(io::IO, e::MyError)
    print(io, "MyError: ", myerror_message[e.code])
end

my_error(code::Integer) = code != 0 && throw(MyError(code))

```

and then call `my_error(resultcode)` whenever you have a result code.

For example, Julia uses a similar mechanism for [`libuv`](https://en.wikipedia.org/wiki/Libuv) errors: [julia/base/libuv.jl at fcc4213c488a1fa3b88271776636d45fc1ca42c7 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/blob/fcc4213c488a1fa3b88271776636d45fc1ca42c7/base/libuv.jl#L86-L114)

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [June 30, 2026, 7:28pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/4 "2026-06-30T19:28:41Z")

</div>

In my opinion, if the result code indicates that something actually exceptional has happened, throw an exception. But if it’s something that can be more or less expected to happen, don’t force the user to try/catch, pass on the result code instead.

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [June 30, 2026, 7:51pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/5 "2026-06-30T19:51:55Z")

</div>

I appreciate the more elegant methods of error handling. The C-program places the responsibility of dealing with the result code with the calling program. I have the option of putting this in the function that contains the ccall or I can push it off to the calling program.

Unless there is a preferred convention within the Julia community, I think what I will do is if the action to take with the result code is ambiguous I will pass on the result code, and if it is unambiguously an error, I will throw an exception like Gunnar suggests.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [June 30, 2026, 7:59pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/6 "2026-06-30T19:59:10Z")

</div>

It may be useful to see an example at scale. HDF5 has some error handling API. We wrap that into a macro.

> <https://github.com/JuliaIO/HDF5.jl/blob/8874dcd978ba731efc8f3ffbff6ccd3fe1a35c65/src/api/error.jl#L7-L23>

We have some code generation scripts which generate code that generates direct wrappers for each C binding:

> <https://github.com/JuliaIO/HDF5.jl/blob/8874dcd978ba731efc8f3ffbff6ccd3fe1a35c65/src/api/functions.jl#L83-L92>

We then have a second layer which creates helpers around a direct wrappings to make the functions more Julian. In this case, we want to return the version numbers directly rather than requiring that they be passed by reference.

> <https://github.com/JuliaIO/HDF5.jl/blob/8874dcd978ba731efc8f3ffbff6ccd3fe1a35c65/src/api/helpers.jl#L22-L26>

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [June 30, 2026, 11:10pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/7 "2026-06-30T23:10:08Z")

</div>

> [@stevengj](#):
>
> `my_error(code::Integer) = code != 0 && throw(MyException(code))`

I am not sure what MyException is here?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [July 1, 2026, 12:06am UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/8 "2026-07-01T00:06:49Z")

</div>

> [@Jake](#):
>
> I am not sure what MyException is here

Sorry, that should have been MyError. Fixed.

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [July 1, 2026, 2:01am UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/9 "2026-07-01T02:01:42Z")

</div>

That helps but now it does not display the error message. MWE

```julia-auto
struct MyError <: Exception
	code::Cint
end
const myerror_message = Dict{Cint, String}(
		0 => "Success, no errors",
		-1 => "A parameter passed to the function was incorrect.",
		-2 => "The device is busy.",
		-3 => "There was a timeout accessing a resource.",
		-4 => "There was a timeout while obtaining a resource lock.",
		-5 => "The device at the specified address is not the correct type.",
		-6 => "A needed resource was not available.",
		-7 => "Could not communicate with the device.",
		-10 => "Some other error occurred.")
function Base.showerror(io::IO, e::MyError)
	print(io, "MyError: ", myerror_message[e.code])
end
my_error(code::Integer) = code != 0 && throw(MyError(code))

```

With the error message

```julia-auto
julia> my_error(-5)
ERROR:
Stacktrace:
 [1] my_error(code::Int64)
   @ Main .\REPL[6]:1
 [2] top-level scope
   @ REPL[7]:1
SYSTEM (REPL): showing an error caused an error
ERROR: MethodError: objects of type Dict{Int32, String} are not callable
The object of type `Dict{Int32, String}` exists, but no method is defined for this combination of argument types when trying to treat it as a callable object.
Stacktrace:

```

---

<div class="post-metadata">

**Author:** ![danielmatz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielmatz/32/2285_2.png) [@danielmatz](https://discourse.julialang.org/u/danielmatz)\
**Post date:** [July 1, 2026, 2:04am UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/10 "2026-07-01T02:04:40Z")

</div>

> [@Jake](#):
>
> ```julia-auto
> function Base.showerror(io::IO, e::MyError)
> print(io, "MyError: ", myerror_message(e.code))
> end
> 
> ```

You are trying to call the `Dict` of messages as if it were a function. You need to index into it instead:

```julia-auto
function Base.showerror(io::IO, e::MyError)
	print(io, "MyError: ", myerror_message[e.code])
end

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [July 1, 2026, 11:43am UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/11 "2026-07-01T11:43:40Z")

</div>

> [@Jake](#):
>
> `print(io, "MyError: ", myerror_message(e.code))`

That should be `myerror_message[e.code]`, sorry. (I corrected the typo in my post, above.)

---

<div class="post-metadata">

**Author:** ![Jake](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jake/32/46007_2.png) [@Jake](https://discourse.julialang.org/u/Jake)\
**Post date:** [July 1, 2026, 12:12pm UTC](https://discourse.julialang.org/t/good-etiquette-with-wrapping-a-c-library/137881/12 "2026-07-01T12:12:40Z")

</div>

> [@stevengj](#):
>
> That should be `myerror_message[e.code]`, sorry. (I corrected the typo in my post, above.)

Thanks, I also corrected it in my example code so that now it works.
