Talk:Use another language to call a function

From Rosetta Code

I am unsure if this is same as C FFI, or not. If yes, then merge. --Dmitry-kazakov 13:57, 11 August 2009 (UTC)

It's not. Call foreign language function and C FFI are the same task in essence though (and there are other closely related ones too; this is an area needing some rationalization). —Donal Fellows 11:46, 17 August 2009 (UTC)

Task needs work/splitting?

While writing the Tcl implementation, it occurred to me that a number of languages might want to deal with the cases where a parameter is an ‘in’ parameter differently from the case given (really a single ‘out’ parameter, plus a bit of metadata to describe the buffer size). No time to work on this now though. —Donal Fellows 13:10, 18 August 2009 (UTC)

C code is wrong

#include <stdio.h>

extern int Query (char * Data, size_t * Length);

int main (int argc, char * argv [])
{
   char     Buffer [1024];
   unsigned Size = sizeof (Buffer);
   
   if (0 == Query (Buffer, &Size))
   {
      printf ("failed to call Query\n");
   }
   else
   {
      char * Ptr = Buffer;
      while (Size-- > 0) putchar (*Ptr++);
      putchar ('\n');
   }
}
#include <stdio.h>

int Query (char * Data, size_t * Length)
{
   printf("Length = %zu, 0x%zx\n", *Length, *Length);
   return 0;
}
$ cc -v
Reading specs from /usr/lib/gcc-lib/amd64-unknown-openbsd4.8/4.2.1/specs
Target: amd64-unknown-openbsd4.8
Configured with: OpenBSD/amd64 system compiler
Thread model: posix
gcc version 4.2.1 20070719 
$ cc -o main main.c query.c
main.c: In function 'main':
main.c:10: warning: passing argument 2 of 'Query' from incompatible pointer type
$ ./main 
Length = 7971459302400, 0x74000000400
failed to call Query

It should say 'Length = 1024', not 'Length = 7971459302400'. The problem is that main() passed an unsigned * but Query() expects size_t *. On my machine, unsigned is 4 bytes but size_t is 8 bytes.

I would like to fix the C code (by changing unsigned Size to size_t Size, and while there, by adding to main() some return statements), but I worry that if I fix the C code, then I will destroy all the examples that use the old C code. --Kernigh 15:45, 12 February 2011 (UTC)

I'd say fix it. Go saw that as a problem too. —Sonia 23:35, 12 February 2011 (UTC)
+1 on fix. There is a template to warn others to review their entries too, but I can't remember what it is ... ... nope, still can't remember. --Paddy3118 06:02, 13 February 2011 (UTC)
clarified-review? I made the change and added that template. I hope I did it right! —Sonia 07:48, 13 February 2011 (UTC)

Task focus and name?

This might be better named as "Demonstrate how a provided function can be called from a foreign language". --Markhobley 14:57, 5 June 2011 (UTC)

Task names should generally be short and sweet. A task summary might be appropriate. (Especially if we could implement something like task summaries as semantic properties) --Michael Mol 15:20, 6 June 2011 (UTC)
What about "Demonstrate a function call from a foreign language"? --Markhobley 17:44, 6 June 2011 (UTC)
Near as I can figure, the task title is about as good as it can be. It's an inverse of Call foreign language function, so if anything, it ought to be renamed Call function from foreign language, removing the article 'a'. It seems good enough to not warrant that kind of redirect, though. --Michael Mol 04:57, 7 June 2011 (UTC)
The current title can be read one of two ways:
  • Call (a function from a foreign language)
  • (Call a function) from a foreign language

- Hence I suggested renaming this task. --14:10, 7 June 2011 (UTC)

Hm. I see your point. I don't like the full-sentence approach for task names, though. Other ideas? --Michael Mol 16:24, 7 June 2011 (UTC)
Maybe we could reverse the phrasing somehow: "Use a foreign language to call a function". --18:58, 7 June 2011 (UTC)

I don't know why we chose that particular function for the task description. Couldn't we have just done something that produces a result from a couple of numbers? The example in the task description requires an unnecessary amount of work to demonstrate something that could in essence be much simpler. --Markhobley 14:57, 5 June 2011 (UTC)

I think the reason in this case was to intentionally call out a non-trivial area of language compatibility. Being able to pass strings back and forth between languages (especially where some of the languages have very different ways of exposing strings to programmers) is a touchy subject. That said, it may be appropriate to split the task between trivial and non-trivial scenarios. --Michael Mol 15:20, 6 June 2011 (UTC)

Is the pipe option of pico lisp fair play? It's a ubiquitous, and easy solution.--Dave 04:43, 14 March 2012 (UTC)

Trying to build the Ada solution fails, perhaps I am doing something stupid.

I get a run-time error: raised INTERFACES.C.STRINGS.UPDATE_ERROR : i-cstrin.adb:260

cat ./test_it.bash

  1. !/bin/bash

gcc -v -c ./main.c gnatmake -v -c ./exported.adb gnatbind -v -n ./exported.ali gnatlink -v ./exported.ali ./main.o -o ./main ./main 2>&1 | tee ./NOTE.txt gnatclean ./exported rm ./main ./main.o


cat ./exported.ads

with Interfaces.C;          use Interfaces.C;
with Interfaces.C.Strings;  use Interfaces.C.Strings;

package Exported is
   function Query (Data : chars_ptr; Size : access size_t)
      return int;
   pragma Export (C, Query, "Query");
end Exported;


cat ./exported.adb

package body Exported is
   function Query (Data : chars_ptr; Size : access size_t)
      return int is
      Result : char_array := "Here am I";
   begin
      if Size.all < Result'Length then
         return 0;
      else
         Update (Data, 0, Result);
         Size.all := Result'Length;
         return 1;
      end if;
   end Query;
end Exported;


cat ./main.c

#include <stdio.h>

extern int Query (char * Data, size_t * Length);

int main (int argc, char * argv [])
{
   char     Buffer [1024];
   size_t   Size = sizeof (Buffer);

   if (0 == Query (Buffer, &Size))
   {
      printf ("failed to call Query\n");
   }
   else
   {
      char * Ptr = Buffer;
      while (Size-- > 0) putchar (*Ptr++);
      putchar ('\n');
   }
}


I have a lot of output (as I used the verbose flag on all of the build commands)...but none of it seems to point to a make and/or link error...I can provide the output if desired.

Environment: MacOS 14.6.1 M1 chip (arm64) gnatmake -v

GNATMAKE 14.1.0 Copyright (C) 1992-2024, Free Software Foundation, Inc.


Thanks, Retired Build Engineer

I'm not that knowledgeable of Ada, but Googling ada update_error found this:
https://comp.lang.ada.narkive.com/EzyUTCFS/interfaces-c-string-update
which suggests you need to null terminate the string (which C would expect in general but probably not in this example) and probably set Check to false in the Update call.
--Tigerofdarkness (talk) 07:48, 14 September 2024 (UTC)

Changing the calling function

I didn't change the calling function in my example and my function worked just fine. Just sayin'. The task is to write a function that works with an existing calling function, not to rewrite someone elses code to work with your function. Superstitionfreeblog (talk) 20:44, 10 October 2024 (UTC)

There's no argument from me that FASM has some pretty neat features like that, otoh that code snippet (unalterered/shimless) would probably be rather tricky to invoke from the majority of other languages on this page.. --Petelomax (talk) 14:05, 14 October 2024 (UTC)
If you are referring to my reply to Retired Build Engineer, I meant that the changes would be needed to the Ada code, not the C code. I meant that he would need to null-terminate the string in the Ada code, not the C code. As you note, the C code is fixed by the task. --Tigerofdarkness (talk) 20:54, 10 October 2024 (UTC)
I wasn't. I just noticed that several coders took it on themselves to rewrite the calling program for some reason, some for no apparent reason. Superstitionfreeblog (talk) 01:26, 11 October 2024 (UTC)
Ah yes, sorry. I hadn't noticed but you are right! A surprising number of samples modify the C code - if their language solution can't be called from the supplied C code, perhaps it would have been better to write a Query function in C that could be called from the supplied code and then call the other language? It would still be a problem though, for languages like Go where the main routine has to be in Go (according to sample's the blurn). --Tigerofdarkness (talk) 18:31, 11 October 2024 (UTC)
Hmm, expecting full interop without modifying the C code at all is just insanely optimistic, imo. A (rewritten) Query function that accepts a callback should't be a problem for Go, surely. |Erm, "the blurn"?| --Petelomax (talk) 13:47, 14 October 2024 (UTC)
Aha - you spotted my inability to type "blurb" :)
I see you managed to solve the task without modifying the C.
What I meant was, if you had to modify it, you could write a Query in C that then called the other language routine, so you would have:
main C routine unchanged - as per the task that calls
Query function written in C that calls
LQuery function written in the other language
It occured to me that if the C code was part of a commercial product, a) it probably wouldn't be the main routine and b) you probably wouldn't have the source to change.
--Tigerofdarkness (talk) 18:50, 14 October 2024 (UTC)