# Is it possible to splat into ccall?

**URL:** <https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761>\
**Category:** General Usage\
**Tags:** ccall\
**Created:** [March 8, 2023, 7:49pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761 "2023-03-08T19:49:46Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 10, 2023, 7:47pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/21 "2023-03-10T19:47:44Z")

</div>

No, that’s all understood. For some reason, I just got the idea at some point that `@ccall` defers to `ccall` (instead of making an `Expr(:foreigncall)` directly). Perhaps because of statements like these:

> [@Why is ccall syntax?](https://discourse.julialang.org/t/why-is-ccall-syntax/72427/3):
>
> `@ccall` is a more recent and much more attractive syntax for the same thing which doesn’t need special support from the parser or lowering.

> [@Sukera](#):
>
> Like I said, `@ccall` is the same as `ccall`, just in macro form.

But they’re not the same! `@ccall` can call varargs functions with arbitrary (mixed) types, whereas varargs arguments must all be of the same type with `ccall`. These are equivalent:

```julia
julia> ccall(:printf, Cint, (Cstring, Cint...), "%d %d %d\n", 1, 2, 3);
1 2 3

julia> @ccall printf("%d %d %d\n"::Cstring; 1::Cint, 2::Cint, 3::Cint)::Cint;
1 2 3

```

But there’s no way to express the following using `ccall`:

```julia
julia> @ccall printf("%d %f %s\n"::Cstring; 1::Cint, 2.0::Cdouble, "abc"::Cstring)::Cint;
1 2.000000 abc

```

([This is also stated in the documentation.](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#man-bits-types))

**Edited to add:** I just realized there does seem to be one thing that `ccall` can do and `@ccall` can’t, which is specifying a calling convention? (Seems to be hard-coded to `:ccall`, if I understand the code correctly.) Should be straightforward to add, but it’s not in the current implementation.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 10, 2023, 10:50pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/22 "2023-03-10T22:50:51Z")

</div>

> [@lmtzx9h4qqnt](#):
>
> ([This is also stated in the documentation.](https://docs.julialang.org/en/v1/manual/calling-c-and-fortran-code/#man-bits-types))

Not sure I follow - which part of that link are you referring to?

> [@lmtzx9h4qqnt](#):
>
> But there’s no way to express the following using `ccall`:

```julia
julia> ccall(:printf, Cint, (Cstring, Cint, Cdouble, Cstring), "%d %f %s\n", 1, 2.0, "Hello");
1 2.000000 Hello

```

Maybe that’s illegal and a bug, maybe everything is passed as a `*void`, I don’t know 🤷 Could also just be working due to `printf` taking its type information from the format string and not needing the “”“type safety”“” that a same-typed `va_list` would provide.

Anyway, like I said, they’re the same. They lower to the same `Expr(:foreigncall)` machinery. The only difference is in who ends up building that `Expr`, the parser directly or the `@ccall` macro on its own.

I did find these while looking for a PR that made this work, if that exists. I am on the [side of Jeff](https://github.com/JuliaLang/julia/issues/1315#issuecomment-8952797) here though, so… 🤷

> <https://github.com/JuliaLang/julia/issues/6661>
>
> proposal: introduce \`va\_list\` type for \`ccall\` / \`cfunction\`
> 
> usage:
> 
> \`\`\` julia
> …ccall(:abc, Int, (A, B, va\_list{(C,D,E)}), a,b,c,d,e)
> \# int abc(A, B, ...) {}
> \# {
> \# abc(a,b,c,d,e);
> \# }
> 
> va = va\_list(c,d,e)
> ccall(:abc, Int, (A, B, va\_list), a, b, va)
> ccall(:abc, Int, (A, B, va\_list{()}), a, b, va)
> \# int abc(A, B, va\_list) {}
> \# {
> \# va\_list ap;
> \# va\_start(ap, X);
> \# abc(A,B, ap);
> \# }
> \`\`\`
> 
> definitions:
> 
> \`\`\` julia
> immutable va\_list{T\<:Tuple}
> # opaque
> va\_list(args...) = (T == () ? new(magic...) : error("cannot construct a typed va\_list"))
> end
> va\_list(values...) = va\_list{()}(values...)
> \`\`\`
> 
> thoughts? improvements? should I make a pull request?

> <https://github.com/JuliaLang/julia/issues/1315>
>
> Conceptually related to #1313.
> 
> If I try defining a function this way:
> 
> \`\`\` juli…a
> @eval begin
> function mylseek(args...)
> cpos = ccall(:lseek, FileOffset, (Int32, FileOffset, Int32), args...)
> end
> end
> \`\`\`
> 
> then I get:
> 
> \`\`\`
> julia\> s = open("h5test.c")
> IOStream(\<file h5test.c\>)
> 
> julia\> mylseek(fd(s), 5, 0)
> error compiling mylseek: ccall: wrong number of arguments to C function
> \`\`\`
> 
> One workaround is the following:
> 
> \`\`\` julia
> ccallargs = Any\[:(:lseek), FileOffset, expr(:tuple, Any\[Int32, FileOffset, Int32\]), :(args\[1\]), :(args\[2\]), :(args\[3\])\]
> ex = expr(:ccall, ccallargs)
> @eval begin
> function mylseek(args...)
> $ex
> end
> end
> 
> julia\> mylseek(fd(s), 11, 0)
> 11
> \`\`\`
> 
> Perhaps there is a less-awkward syntax? If not, should we add a \`ccallexpr\` function to the library that would build those expressions?

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [March 11, 2023, 1:00am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/23 "2023-03-11T01:00:34Z")

</div>

> [@Sukera](#):
>
> ```julia
> julia> ccall(:printf, Cint, (Cstring, Cint, Cdouble, Cstring), "%d %f %s\n", 1, 2.0, "Hello");
> 1 2.000000 Hello
> 
> ```
> 
> Maybe that’s illegal and a bug, maybe everything is passed as a `*void`, I don’t know 🤷

I’m moderately sure that won’t work on Windows, and it “accidentally” works on Linux because it uses a different calling convention, but it can’t be relied upon. The `@ccall`macro has a much nicer interface, on the other hand there are things that you can’t do with that instead you can with `ccall` (e.g. specifying the calling convention).

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [March 11, 2023, 2:42am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/24 "2023-03-11T02:42:52Z")

</div>

> [@giordano](#):
>
> I’m moderately sure that won’t work on Windows

Indeed, this is what I get:

```julia
julia> ccall(:printf, Cint, (Cstring, Cint, Cdouble, Cstring), "%d %f %s\n", 1, 2.0, "Hello");
1 0.000000 Hello

```

This problem unfortunately extends to my `ccaller` code above; we’d want a mechanism for specifying where the variadic arguments begin.

My `ccaller` code also has no provisions for specifying calling convention—although it seems like the place to start is putting it in the `@ccall` macro. If that is done, afaict `@ccall`’s functionality would be a strict superset of `ccall`, without requiring such weird hacks to the language semantics.

---

<div class="post-metadata">

**Author:** ![c42f](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/c42f/32/52842_2.png) [@c42f](https://discourse.julialang.org/u/c42f)\
**Post date:** [March 11, 2023, 4:24am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/25 "2023-03-11T04:24:26Z")

</div>

Yes, we could have added support for other calling conventions in the original `@ccall` PR. But we skipped that because it was a lot of discussion already to get to the point of merging the current version. And it seemed better to merge it than to get stuck working out notation for calling conventions or other attributes ([Ccallmacro by ninjaaron · Pull Request #32748 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/pull/32748#issuecomment-590634077))

If someone wanted to figure out the nitty gritty detail of calling convention for FFI calls, I’m sure that would be a great PR. Last time we weren’t sure if we needed a general annotations syntax for defining side effects, but now we have `@assume_effects ... @ccall`. I’m still not sure whether there’s other annotations which might be needed.

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 11, 2023, 6:11am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/26 "2023-03-11T06:11:42Z")

</div>

> [@Sukera](#):
>
> Not sure I follow - which part of that link are you referring to?

Sorry, it can’t be linked to directly. I meant this part:

> **System Independent Types**
> 
> | C name | Fortran name | Standard Julia Alias | Julia Base Type |
> | --- | --- | --- | --- |
> | … | … | … | … |
> | `va_arg` | | | Not supported |
> | `...` (variadic function specification) | | | `T...` (where `T` is one of the above types, when using the `ccall` function) |
> | `...` (variadic function specification) | | | `; va_arg1::T, va_arg2::S, etc.` (only supported with `@ccall` macro) |

> [@Sukera](#):
>
> ```julia
> julia> ccall(:printf, Cint, (Cstring, Cint, Cdouble, Cstring), "%d %f %s\n", 1, 2.0, "Hello");
> 1 2.000000 Hello
> 
> ```
> 
> Maybe that’s illegal and a bug, maybe everything is passed as a `*void`, I don’t know 🤷 Could also just be working due to `printf` taking its type information from the format string and not needing the “”“type safety”“” that a same-typed `va_list` would provide.

As others have pointed out, some calling conventions differentiate between varargs and “normal” args. The difference is in the `nreq` field in the `Expr(:foreigncall)`:

```julia
julia> @macroexpand @ccall printf("%d %f %s\n"::Cstring; 1::Cint, 2.0::Cdouble, "Hello"::Cstring)::Cint
quote
    local var"#44#arg1root" = Base.cconvert(Cstring, "%d %f %s\n")
    local var"#45#arg1" = Base.unsafe_convert(Cstring, var"#44#arg1root")
    local var"#46#arg2root" = Base.cconvert(Cint, 1)
    local var"#47#arg2" = Base.unsafe_convert(Cint, var"#46#arg2root")
    local var"#48#arg3root" = Base.cconvert(Cdouble, 2.0)
    local var"#49#arg3" = Base.unsafe_convert(Cdouble, var"#48#arg3root")
    local var"#50#arg4root" = Base.cconvert(Cstring, "Hello")
    local var"#51#arg4" = Base.unsafe_convert(Cstring, var"#50#arg4root")
    $(Expr(:foreigncall, :(:printf), :Cint, :(Core.svec(Cstring, Cint, Cdouble, Cstring)), 1, :(:ccall), Symbol("#45#arg1"), Symbol("#47#arg2"), Symbol("#49#arg3"), Symbol("#51#arg4"), Symbol("#44#arg1root"), Symbol("#46#arg2root"), Symbol("#48#arg3root"), Symbol("#50#arg4root")))
end

julia> Meta.@lower ccall(:printf, Cint, (Cstring, Cint, Cdouble, Cstring), "%d %f %s\n", 1, 2.0, "Hello")
:($(Expr(:thunk, CodeInfo(
    @ none within `top-level scope`
1 ─ %1 = Base.cconvert(Cstring, "%d %f %s\n")
│ %2 = Base.cconvert(Cint, 1)
│ %3 = Base.cconvert(Cdouble, 2.0)
│ %4 = Base.cconvert(Cstring, "Hello")
│ %5 = Base.unsafe_convert(Cstring, %1)
│ %6 = Base.unsafe_convert(Cint, %2)
│ %7 = Base.unsafe_convert(Cdouble, %3)
│ %8 = Base.unsafe_convert(Cstring, %4)
│ %9 = $(Expr(:foreigncall, :(:printf), :Cint, :(Core.svec(Cstring, Cint, Cdouble, Cstring)), 0, :(:ccall), :(%5), :(%6), :(%7), :(%8), :(%4), :(%3), :(%2), :(%1)))
└── return %9
))))

```

> [@Sukera](#):
>
> I did find these while looking for a PR that made this work, if that exists. I am on the [side of Jeff](https://github.com/JuliaLang/julia/issues/1315#issuecomment-8952797) here though, so… 🤷

Well, his suggestion doesn’t work when the number of arguments is unknown and can be arbitrary, which kind of defeats the whole point of varargs functions.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [March 11, 2023, 8:33am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/27 "2023-03-11T08:33:11Z")

</div>

> [@giordano](#):
>
> I’m moderately sure that won’t work on Windows

Yes, that makes sense - good to know that my gut feel about this being dangerous was right 🙂 I don’t think there’s a (cross platform) way of checking preemptively whether what we want to call is variadic, right? Aaah, the perils of C ABIs…

> [@lmtzx9h4qqnt](#):
>
> Sorry, it can’t be linked to directly. I meant this part:

Gotcha - I took that part of the docs as a “this is how we support it” and not as a “other ways don’t work”. Maybe the difference in calling conventions should be added here as a warning, to make it clear that just passing the extra vararg arguments as regular arguments does not work?

> [@lmtzx9h4qqnt](#):
>
> Well, his suggestion doesn’t work when the number of arguments is unknown and can be arbitrary, which kind of defeats the whole point of varargs functions.

Yeah, I was more referring to the “can’t be done portably” part 🙂

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 11, 2023, 3:54pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/28 "2023-03-11T15:54:33Z")

</div>

> [@Sukera](#):
>
> Yeah, I was more referring to the “can’t be done portably” part 🙂

Ah OK – I actually didn’t understand that part. What would the portability issue be? As far as I can tell, the [original issue](https://github.com/JuliaLang/julia/issues/1315) was just asking about turning a Julia tuple into the arguments to a `ccall`, i. e. exactly the same as my original question, which is all just a matter of syntax.

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 26, 2023, 6:17pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/29 "2023-03-26T18:17:20Z")

</div>

Alright, I’ve now created [Ccalls.jl](https://gitlab.com/Socob/Ccalls.jl) as package implementing the `@generated` approach!

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [March 28, 2023, 4:35am UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/30 "2023-03-28T04:35:34Z")

</div>

A couple notes and ideas, fwiw

1. For separating args from varargs, I see appeal in using `…`, but it seems like `:` would be more ergonomic. Subjective of course. You could use any other operator too, like `|`, `>`, etc, or maybe wrap the varargs in their own tuple.
2. For the method using `Pair`s like `2=>Cint`, it feels a bit backwards; `Cint=>2` feels more natural to me. Another idea would be to use `Cint: 2`, though that’s likely to get pushback as it would entail [type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy), but that could be solved by getting it into `Base`.
3. As discussed in [this thread](https://discourse.julialang.org/t/why-are-generated-functions-maybe-impossible-to-statically-compile/96366), there might be difficulties in getting some programs that use such a generated function to compile statically. That said, `ccall` already seems to [cause trouble](https://discourse.julialang.org/t/about-static-compilation-and-static-analysis/87492/6) for static compilation. I haven’t dug in to understand why.

If we’re willing to diverge from existing semantics a bit more, maybe something like this becomes compelling:

```julia
Ccall(Cdouble: :pow, Cdouble: 2, Cdouble: 10)
Ccall(Cint: :printf, Cstring: "%d %f %s\n", (Cint: 1, Cdouble: 2.0, Cstring: "Hello"))

```

or maybe:

```julia
Ccaller(Cdouble, :pow, Cdouble, Cdouble)(2, 10)
Ccaller(Cint, :printf, Cstring, (Cint, Cdouble, Cstring))("%d %f %s\n", (1, 2.0, "Hello"))

```

Chef’s choice.

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 28, 2023, 6:57pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/31 "2023-03-28T18:57:49Z")

</div>

Thanks for the feedback!

> [@uniment](#):
>
> For separating args from varargs, I see appeal in using `…`, but it seems like `:` would be more ergonomic. Subjective of course. You could use any other operator too, like `|`, `>`, etc, or maybe wrap the varargs in their own tuple.

I already have `..` as an alias for `…` (apparently forgot to document it, though). `:` would be another option, but `..` seems clearer to me.

> [@uniment](#):
>
> For the method using `Pair`s like `2=>Cint`, it feels a bit backwards; `Cint=>2` feels more natural to me. Another idea would be to use `Cint: 2`, though that’s likely to get pushback as it would entail [type piracy](https://docs.julialang.org/en/v1/manual/style-guide/#Avoid-type-piracy), but that could be solved by getting it into `Base`.

I agree that it can seem strange because of the “arrow” syntax, but I found it important to keep the same order as in other Julia syntax, which is `value::Type`. I think of it as “2 is converted to `Cint`”, which is true!

I wanted to keep it simple since the whole `@generated` construction is already somewhat obscure, so I didn’t think about stuff like hijacking `:`.

> [@uniment](#):
>
> ```julia
> Ccaller(Cdouble, :pow, Cdouble, Cdouble)(2, 10)
> Ccaller(Cint, :printf, Cstring, (Cint, Cdouble, Cstring))("%d %f %s\n", (1, 2
> 
> ```

I do like this! Hm, so many options. It seems more confusing than anything else to have 4 different ways of writing the same thing, but on the other hand, this is a bit of an experiment, so I guess it wouldn’t hurt trying it?

---

<div class="post-metadata">

**Author:** ![lmtzx9h4qqnt](https://avatars.discourse-cdn.com/v4/letter/l/74df32/32.png) [@lmtzx9h4qqnt](https://discourse.julialang.org/u/lmtzx9h4qqnt)\
**Post date:** [March 28, 2023, 7:15pm UTC](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761/32 "2023-03-28T19:15:52Z")

</div>

There’s also `∷` (`\Colon`) which is tempting and wouldn’t be type piracy, but it probably looks too close to `::` to avoid confusion.

[Previous page](https://discourse.julialang.org/t/is-it-possible-to-splat-into-ccall/95761.md?page=1)
