Question. When using external libraries, is there the same pointer! in Rebol2 as there is in Red/System?
If the c declaration were:
void f (int* i);
How would I define the routine!?
f: make routine! [
"Does Something"
int [pointer! [integer!]]
return: [char!]
] lib "f"
I see http://rebol.com/docs/library.html#section-25
"External library functions that are passed pointers, generally expect
the pointers to be char or void datatypes. Currently, REBOL routines
do not support the void datatype. In most cases, you can safely pass
char instead of void. For return values, use long instead of void."
However, just a little confused. What is the correct way to define the routine for f?
as the link states
f: make routine! [
"Does Something"
pInt [char*]
return: [long]
] lib "f"
worked for me a few years ago
Related
I'm am trying to declare the following C struct in Perl 6:
struct myStruct
{
int A[2]; //<---NEED to declare this
int B;
int C;
};
My problem is that I don't know how to declare the int A[2]; part using the built in NativeCall api.
So for what I have is:
class myStruct is repr('CStruct') {
has CArray[int32] $.A;
has int32 $.B;
has int32 $.C;
};
However, I know that the has CArray[int32] $.A; part is wrong as it does not declare a part in my struct that takes up ONLY 2 int32 sizes.
Update 2: It turned out that this didn't work at the time I first posted this answer, hence the comments. I still haven't tested it but it must surely work per Tobias's answer to Passing an inlined CArray in a CStruct to a shared library using NativeCall. \o/
I haven't tested this, but this should work when using Rakudo compiler release 2018.05:
use NativeCall;
class myStruct is repr('CStruct') {
HAS int32 #.A[2] is CArray;
has int32 $.B;
has int32 $.C;
}
HAS instead of has causes the attribute to be inline rather than a pointer;
int32 instead of int is because the Perl 6 int type isn't the same as C's int type but is instead platform specific (and usually 64 bit);
# instead of $ marks the attribute as being Positional ("supports looking up values by index") instead of scalar (which gets treated as a single thing);
[2] "shapes" the Positional data to have 2 elements;
is CArray binds a CArray as the Positional data's container logic;
This commit from April this year wired up the is repr('CStruct') to use the declared attribute information to appropriately allocate memory.
Fwiw I found out about this feature from a search of the #perl6 logs for CArray and found out it had landed in master and 2018.05 from a search of Rakudo commits for the commit message title.
See Declaring an array inside a Perl 6 NativeCall CStruct
There are other ways, but the easiest is instead of an array, just declare each individual item.
class myStruct is repr('CStruct') {
has int32 $.A0;
has int32 $.A1;
... as many items as you need for your array ...
has int32 $.B;
has int32 $.C;
};
So I've done some experimentation on this and taken a look at the docs and it looks like the CArray type doesn't handle shaping the same way as Perl6 Arrays.
The closest thing you've got it the allocate constructor that preallocates space in the array but it doesn't enforce the size so you can add more things.
Your class definition is fine but you'd want to allocate the array in the BUILD submethod.
https://docs.raku.org/language/nativecall#Arrays
(Further thought)
You could have two objects. One internal and one for the struct.
The Struct has a CArray[int32] array. The internal data object has a shaped int32 cast array my int3 #a[2]. Then you just need to copy between the two.
The getters and setter live on the main object and you use the struct object just when you want to talk to the lib?
This does not really declare an array of fixed size, but puts a constraint on the size of its value: You can try and use where to constraint the size of the array. CArray is not a positional (and thus cannot be declared with the # sigil) but it does have the elems method.
use NativeCall;
my CArray[int32] $A where .elems < 2
That is, at least, syntactically correct. Whether that breaks the program in some other place remains to be seen. Can you try that?
I wondered what slices were in Rust. As it turned out, it's just a struct with a data pointer and the size inside. I've looked at the source for indexing and I've found this:
impl<T> ops::Index<usize> for [T] {
type Output = T;
fn index(&self, index: usize) -> &T {
// NB built-in indexing
&(*self)[index]
}
}
I'm not a Rust expert but &(*self) seems like a pointer for me and there is no pointer indexing in Rust as far as I know. So how does this indexing thing work? Is it just a compiler built-in thing?
Is it just a compiler built-in thing?
Yes. The source code comment also says that same. [T] is an unsized type and needs some extra rules anyway. For example, unsized types can't live on the stack (are pretty difficult to handle). But references to unsized types consist of a pointer and a size (specifically "something that completes the type").
Note, however, that the expression is evaluated like this: &((*self)[index]). This means that self (type &[T]) is dereferenced to be type [T] and then indexed. This returns a T, but we only want a reference to it, thus the &.
I can document a function like this:
f: func [
"a description"
arg1 [string!] "a description of an argument 1"
][
arg1
]
I can use ?/help in order to retrieve informations about the the function (a description, a usage, the argument list, a description of each argument and it's type)
? f
USAGE:
F arg1
DESCRIPTION:
a description
F is a function value.
ARGUMENTS:
arg1 -- a description of an argument 1 (Type: string)
I cannot document dialects like this. Is there an automatic way to document dialects (like func does)? Do I have to do this manually?
There's nothing for it currently, but it's a good idea. So good that someone has suggested it before. :-)
Do I have to do this manually?
You can manually write a new generator which defines your "dialect spec" format. Then either do something like give it a HELP command, or extend HELP to recognize it.
Very short example to demonstrate a group of techniques which may come in handy in doing something like this (not all expected to be obvious, rather to hint at the flexibility):
make-dialect: function [spec [block!] body [block!]] [
return function ['arg [block! word!]] compose/deep/only [
case [
arg = 'HELP [
foreach keyword (spec/keywords) [
print [keyword "-" {your help here}]
]
]
block? arg [
do func [arg] (body) arg
]
'default [
print "Unrecognized command. Try HELP."
]
]
]
]
So there's your function that takes a dialect spec and makes a function. Once you've got your generator, using it can be less manual:
mumble: make-dialect [keywords: [foo baz bar]] [
print ["arg is" mold arg]
]
>> mumble help
foo - your help here
baz - your help here
bar - your help here
>> mumble [<some> [dialect] {stuff}]
arg is [<some> [dialect] {stuff}]
The techniques used here are:
Soft Quoting - Usually you would have to say mumble 'help to "quote" the help as a lit-word! to get it to pass the word! to mumble (as opposed to running the default HELP command). But because arg was declared in the generated function as 'arg it was "soft quoted"...this means that words and paths will not be evaluated. (Parens, get-words, and get-paths still will be.) It's a tradeoff because it means that if someone has a variable they want to pass you they have to say :var or (var) as the argument instead of just var (imagine if the block to pass the dialect is in a variable) so you don't necessarily want to use it...but I thought it an interesting demo to make mumble help work without the lit-word!
Deep Composition - The spec and the body variables which are passed to make-dialect only exist as long as make-dialect is running. Once it's over, they'll be gone. So you can't leave those words in the body of the function you are generating. This uses COMPOSE/DEEP to evaluate parens in the body before the function generator runs to make the result, effectively extracting the data for the blocks and stitching them into the function's body structure.
Reusing Function's Binding Work - The generated function has a spec with a parameter arg that didn't exist at the call site of make-dialect. So arg has to be rebound to something, but what? It's possible to do it manually, but one easy way is to let FUNC do the work for you.
Those are some of the techniques that would be used in the proposed solution, which seeks to not only document dialects but provide an easy method by which their keywords might be remapped (e.g. if one's Rebol system has been configured for another spoken language).
Is it possible to call a function by name in Objective C? For instance, if I know the name of a function ("foo"), is there any way I can get the pointer to the function using that name and call it? I stumbled across a similar question for python here and it seems it is possible there. I want to take the name of a function as input from the user and call the function. This function does not have to take any arguments.
For Objective-C methods, you can use performSelector… or NSInvocation, e.g.
NSString *methodName = #"doSomething";
[someObj performSelector:NSSelectorFromString(methodName)];
For C functions in dynamic libraries, you can use dlsym(), e.g.
void *dlhandle = dlopen("libsomething.dylib", RTLD_LOCAL);
void (*function)(void) = dlsym(dlhandle, "doSomething");
if (function) {
function();
}
For C functions that were statically linked, not in general. If the corresponding symbol hasn’t been stripped from the binary, you can use dlsym(), e.g.
void (*function)(void) = dlsym(RTLD_SELF, "doSomething");
if (function) {
function();
}
Update: ThomasW wrote a comment pointing to a related question, with an answer by dreamlax which, in turn, contains a link to the POSIX page about dlsym. In that answer, dreamlax notes the following with regard to converting a value returned by dlsym() to a function pointer variable:
The C standard does not actually define behaviour for converting to and from function pointers. Explanations vary as to why; the most common being that not all architectures implement function pointers as simple pointers to data. On some architectures, functions may reside in an entirely different segment of memory that is unaddressable using a pointer to void.
With this in mind, the calls above to dlsym() and the desired function can be made more portable as follows:
void (*function)(void);
*(void **)(&function) = dlsym(dlhandle, "doSomething");
if (function) {
(*function)();
}
I am trying to implement a JSON-RPC solution, using a server connector object which obtains a list of available functions from a server somehow like
NSDictionary *functions = [server
callJSONFunction: #"exposedFunctions" arguments: nil];
which is a simplified description, since callJSONFunction actually triggers an asynchronous NSURLConnection.
An element of the function list consists of a string describing the objective c selector, the original function name which will be called using the mechanism mentioned above, the function signature and an optional array of argument names.
So for example a function list could look like this:
(
#"someFunctionWithArgumentOne:argumentTwo:" =
{
signature = #"##:##",
functionName = #"someFunction",
arguments = ( #"arg_one", #"arg_two" )
},
#"anotherFunction" =
{
signature = #"##:",
functionName = #"anotherFunction"
}
)
As soon as the function list was successfully retrieved, the selectors are added to the server connector instance using class_addMethod in a loop:
for ( NSString *selectorName in functions ) {
SEL aSelector = NSSelectorFromString ( selName );
IMP methodIMP = class_getMethodImplementation (
[ self class ], #selector ( callerMethod: ) );
class_addMethod ( [ self class ], aSelector, methodIMP, "v#:####" );
}
where callerMethod: is a wrapper function used to compose the actual request, consisting of the function name as a NSString and an NSDictionary of the form
{ #"argument1_name" = arg1, #"argument2_name" = arg2, ... }
hence the signature "v#:##". The callerMethod then invokes callJSONFunction on the server.
After this exhausting introduction (my bad, I just did not know, how to shorten it) I'll finally get to the point: to cover the possibility of different numbers of arguments,
I defined the callerMethod like
- (void) callerMethod: (id)argument, ... { }
wherein I use the va_* macros from stdarg.h to obtain the passed arguments. But when I test the mechanism by invoking
[serverConnector someFunctionWithArgumentOne: #"Argument 1"
argumentTwo: #"Argument 2" ];
the first argument returned by id arg = va_arg ( list, id); is always #"Argument 2"!
I'd really appreciate all theories and explanations on why that happens. This thing is really driving me nuts!
Var-args do not map to regular argument passing quite so neatly. Encoding of arguments is actually quite architecture specific and rife with highly entertaining details that sometime seem like they are self-conflicting (until you discover the note about the one exception to the rule that makes the whole thing coherent). If you really want a good read [sarcasm intended], go have a look at how ppc64 handles long doubles sometime; there are cases where half of the double will be in a register and the other half on the stack. Whee!
The above long, and slightly frothy due to scarring, paragraph is to say that you can't transparently forward a call from one function to another where the two functions take different arguments. Since an Objective-C method is really just a function, the same holds true for methods.
Instead, use NSInvocation as it is designed to hide all of the esoteric details of argument encoding that comprises any given platforms ABI.
In your case, though, you might be able to get away with class_addMethod() by defining a set of functions that define all possible combinations of argumentation. You don't even really need to make a dictionary as you can use the dlsym() function to look up the correct function. I.e.
id trampolineForIdIdSELIdIdInt(id self, SEL _cmd, id obj1, id obj2, int) {
... your magic here ...
}
Then, you could translate the type string "##:##i" into that function name and pass it to dlsym, grab the result and use class_addMethod()....
I do feel an obligation to also mention this book as it is a sort of "whoah... man... if we represent classes as objects called meta classes that are themselves represented as classes then we can, like, redefine the universe as metaclasses and classes" ultimate end of this line of thinking.
Also see this unfinished book by Gregor Kiczales and Andreas Paepcke.