14

My primary programming language, , was recently open-sourced. In order to improve it, I'm studying the source, which is written in C.

But it's been a long (!) time since I've read or written C, and I wasn't even good at it then. And the way this particular codebase is written is ... idiosyncratic (many APL interpreters, J among them, have their source written in high-level "APL style", even when written in a low-level language; very terse, redundancy eschewed, heavy macro use, etc.)

At the moment, I'm trying to understand the fundamental data structures it employs. The most fundamental one is the typedef A ("A" is for "array"):

typedef struct {I k,flag,m,t,c,n,r,s[1];}* A;

which I understand fine. But I'm struggling to wrap my head around what AF is, two lines later:

typedef A (*AF)();

What does this syntax mean? In particular, what does it mean when things are later declared as "type AF"? Is an AF simply a pointer to an A?

My immediate goal is to interpret memory dumps which include things of type V (for "verb"), whose first two members are AFs:

typedef struct {AF f1,f2;A f,g,h;I flag,mr,lr,rr,fdep;C id;} V;

but my overall goal is larger than that, so please elaborate on the syntax employed in the definition of AF.

Dan Bron
  • 2,313
  • 1
  • 22
  • 35
  • 5
    `AF` is a pointer to a function that takes no parameters and returns `A`. – Sergey Kalinichenko Aug 11 '15 at 17:39
  • 8
    @dasblinkenlight: That's true in C++. In C, it's a typedef for a function with an unspecified but fixed number and type(s) of parameters and returns `A`. Very likely it *should* be defined as `typedef A (*AF)(void);`. If it's really meant to take an arbitrary number of arguments, then you can very easily have undefined behavior by calling a function incorrectly, with no diagnostic from the compiler. – Keith Thompson Aug 11 '15 at 17:42
  • 8
    This code base is horrible. You should run screaming. – Hogan Aug 11 '15 at 17:44
  • @KeithThompson Worth pointing out that in J, functions can accept either one argument (both of type A) or two arguments (of type A) and always return an A. There's no such thing as function with zero or more than two arguments, or a function which takes arguments of anything except type A. So what's weird to me is that you say AF can take a fixed number of arguments: seems to me that it should be able to take one or two. – Dan Bron Aug 11 '15 at 17:46
  • 4
    There's no way **in C** to specify that a function can take one or two arguments. Most functions take a fixed number of arguments, determined when the function is declared/defined; that number can be anywhere from 0 to whatever absurdly large number the compiler supports. A function declared with `()` takes a fixed but unspecified number of arguments. The corresponding *definition* determines the actual number and type(s) of the parameters. This is an obsolescent feature. A *variadic* function, like `printf`, is declared/defined with `, ...`, and takes N fixed arguments plus 0 or more ... – Keith Thompson Aug 11 '15 at 17:57
  • 1
    ... additional arguments. In C++, you could *overload* a function so there are two versions, `A func(A)` and `A func(A, A)`; these would be two distinct functions that happen to have the same name. C doesn't have overloading, but you could define `A func1(A)`, and `A func2(A, A)`. (I don't know J, so I can't comment on how it works.) – Keith Thompson Aug 11 '15 at 17:59
  • It means you're using the wrong language! – Dov Aug 11 '15 at 20:27
  • The succinctness of J apparently worked its way into the implementation, with terrible results. – Paul Draper Aug 11 '15 at 20:49
  • For an example where "fixing" what some people call "horrible" would result in something far worse consider [FARPROC](https://github.com/openj/core/blob/81c529206591f36bf79f248cfaf7b72d06019d55/x15.c#L89) which is a pointer to a function in a dynamically linked library (where the number and types of args is specified as the left argument to [cd](http://www.jsoftware.com/help/user/call_procedure.htm) ). – rdm Aug 11 '15 at 21:51
  • @rdm I'm pretty much ignorant of C: can you elaborate on why "fixing" FARPROC would make the situation worse, and why some people might consider FARPROC to be "horrible" in the first place? – Dan Bron Aug 11 '15 at 21:55
  • 3
    Some people claim the "unspecified number of arguments" aspect of the typedef is an obsolete feature of C, so that's one source of "horrible". Meanwhile, "fixing" it would probably mean eliminating the ability to call arbitrary dynamically linked functions. (Or it would mean replacing it with something far more verbose which would probably smash L1 cache). – rdm Aug 11 '15 at 22:26
  • For the comment of "horrible": Here is a Q&A from the author: Q How do conventional C Programmers react to this? A: With Horror! ---Roger Hui presentation to the British APL Association on 12 Feb 1993. – ahala Aug 12 '15 at 15:11

3 Answers3

13

AF is a typedef for a function pointer. Specifically, AF refers to a pointer to a function that takes an unspecified number of parameters and return a result of type A.

dbush
  • 205,898
  • 23
  • 218
  • 273
  • Ah, of course. That makes sense in the context of `V`s, too, which are functions which process `A`s (and return `A`s). Thanks. I'll accept this when the system lets me. – Dan Bron Aug 11 '15 at 17:41
  • This is a pointer to a function with 0 arguments. Pointers to functions with variable numbers of arguments use `...` syntax. – rlbond Aug 11 '15 at 17:44
  • @rlbond No, a function with 0 arguments has `(void)` as parameters list; that would be `typedef A (*AF)(void)`. The answer is correct: it's unspecified number of parameters. – Filipe Gonçalves Aug 11 '15 at 17:45
  • @rlbond: Functions declared with `()` are very different from variadic functions declared with `, ...`. The former means you still must pass arguments matching the definition, but the compiler won't detect errors (it's an obsolescent feature). The latter means the function can legitimately take a varying number and type(s) of arguments; `printf` is the most common example. – Keith Thompson Aug 11 '15 at 18:03
  • 1
    `AF` is not a "*pointer*" but a type. Please try to stay accurate. – alk Aug 11 '15 at 18:14
  • @alk Thanks. Changed "is a pointer" to "refers to a pointer" – dbush Aug 11 '15 at 18:18
13

As already answered, an AF (Array Function) is a pointer to a function that returns an A (Array object pointer).

In the definition of V (Verb, ie. function object), there are two AFs. v1 is a pointer to the monadic function implementation, and v2 is the pointer to the dyadic function. If the V represents an operator (adverb), then v1 and v2 are still the monadic and dyadic implementations respectively, but also f g and h may be used to hold (curried) left and/or right arguments. mr lr and rr are monadic-rank, left-rank, and right-rank respectively. And id holds an opcode so a printable representation can still be recovered from the structure.

If any of the operands in f g or h are themselves verbs, their V struct will be at f->k bytes past *f, respectively for g and h, like all "payload data".

A very useful link I found for understanding the basic types in the J implementation is Roger Hui BAA talk notes (2.69M scanned pdf). And the full write-up is at Implementation of J (html).

You might also find my primitive clone instructive. See also my questions here and here.

Tikkanz
  • 2,398
  • 15
  • 21
luser droog
  • 18,988
  • 3
  • 53
  • 105
  • Awesome, very specific to my needs (I was wondering about `f`, `g`, `h`). Thanks. I'll take a look at the BAA notes and your clone. Appreciate the help. – Dan Bron Aug 11 '15 at 18:41
  • I accepted your answer, though it was later than others, because it contains the most detail specific to my project (worth mentioning that I did upvote all the posted answers). – Dan Bron Aug 11 '15 at 19:05
12

Let us ignore what A actually is. You then have

typedef int (*AF)();

AF is a pointer to function (aka function pointer) which takes any number of arguments and returns an int. Clearly, by substituting int with A, the content is essentially the same except the return type; the final result therefore qualifies AF as a pointer to function taking any number of arguments and returning A, an alias for a pointer to an anonymous struct.

There's an interesting site that could help converting complex declarations in human-readable text.

edmz
  • 8,220
  • 2
  • 26
  • 45
  • Nice. Thanks in particular for the link to cdecl.org: I will probably need it for this project. – Dan Bron Aug 11 '15 at 17:51
  • 4
    @DanBron: There's also a `cdecl` program you can install. For Linux, just install the `cdecl` package. For other OSs, you can probably build it from source. – Keith Thompson Aug 11 '15 at 18:00