Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

inca: a hacked-up apl in c based on the J incunabulum

195 views
Skip to first unread message

luser- -droog

unread,
Mar 27, 2014, 3:53:42 AM3/27/14
to
compiles without warnings (if you don't ask for warnings) with gcc. currently 313 terse lines.

https://github.com/luser-dr00g/inca

Questions? Improvements? Style-bashing?

inca
====

based on the J-incunabulum,
http://www.jsoftware.com/jwiki/Essays/Incunabulum
lightly extended to allow propagating specifications "a+2+a=3",
new functions minus,times,unbox. multi-digit integers.
identity element for monadic use of minus,times,cat.

Implements monadic functions

+ identity
{ size
~ iota
< box
# shape
> unbox
| absolute
! not
' transpose
@ reverse

dyadic functions

+ plus
{ from
~ find
< assign (not really a function, but an interpreter action)
# reshape
, cat
- minus
. times
* power
% divide
| modulus
& and
^ or
= equals?

monadic operator

/ reduce f/X => x0 f (x1 f (x2 f ( ... xn-2 f xn-1)))

dyadic operator

. matrix product Af.gW => f/Ag'W

over multidigit numbers and variables
'_'(underscore), '`'(backtick), and a-z
`'_'`(underscore) is set to the result of the previous line.

The interpreter also implements a non-greedy "cat" for
number vectors separated by spaces. Hence `1 2 3+~3` => `1 3 5`
where `~` is the zero-based iota.

If the length of the command string exceeds 98 characters,
the behavior is undefined.

If array operands have incompatible sizes, the behavior
is undefined.

Tonton Th

unread,
Mar 27, 2014, 4:08:03 AM3/27/14
to
On 2014-03-27, luser- -droog <mij...@yahoo.com> wrote:

> If the length of the command string exceeds 98 characters,
> the behavior is undefined.

$ man realloc

--
http://la.buvette.org/photos/communards/

jacob navia

unread,
Mar 27, 2014, 4:51:04 AM3/27/14
to
gcc -g miniapl.c
[ many warnings ellided ]
gdb ./a.out
warning: this program uses gets(), which is unsafe.
1 + 1

Program received signal EXC_BAD_ACCESS, Could not access memory.
Reason: KERN_PROTECTION_FAILURE at address: 0x00000005
0x00003524 in cat (a=0x17ff10, w=0x1) at miniapl.c:107
107 V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;
(gdb) print *a
$1 = {
t = 0,
r = 0,
d = {0, 0, 0},
p = {1, 0}
}
Current language: auto; currently minimal
(gdb) quit
The program is running. Exit anyway? (y or n) y

Obviously I am too stupid to understand

V2(cat){I an=tr(a->r,a->d),wn=tr(w->r,w->d),n=an+wn;

1) You use "P" for printf
2) You use "R" instead of return
3) C for "char"
4) "I" for int
5) No identifier name is longer than two letters
6) The result of a function is never declared. Implicit int for all
functions
7) The type of variables is never declared. Implicit int for all variables.

So, you publish code that only you can read. GREAT!

luser- -droog

unread,
Mar 27, 2014, 5:06:43 AM3/27/14
to
On Thursday, March 27, 2014 3:51:04 AM UTC-5, jacob navia wrote:
>
> So, you publish code that only you can read. GREAT!

Perhaps a select few others across this wide globe.

It's definitely a hornet's nest of a pile of code droppings.
But it kinda all works, if you type the syntax right.

In your attempt, the spacing was off.

1+1
should work. A space following a number must be
followed by another number, and it concatenates
the two into a list terminated by the first
operator/function.

1 1 1+3 => 4 4 4

It took me weeks poring over that original J
incunabulum. Then learning more apl for context,
then going back to the incunabulum.

The "byte"-code (actually, integer-code) format
distinguishes between types by ranges.
x < 16ish : it's a function or operator
x >= '_' && x <= 'z' : it's a variable
x > 'z' : it's a pointer

This makes the assumption that pointer values
in the ascii range are never returned by malloc.

BartC

unread,
Mar 27, 2014, 5:30:10 AM3/27/14
to
"luser- -droog" <mij...@yahoo.com> wrote in message
news:0d58b53e-4b47-462b...@googlegroups.com...
> compiles without warnings (if you don't ask for warnings) with gcc.
> currently 313 terse lines.

> https://github.com/luser-dr00g/inca
>
> Questions? Improvements? Style-bashing?

The C code very cleverly resembles APL too.

> If the length of the command string exceeds 98 characters,
> the behavior is undefined.

Can't you just increase the s[99] in main() to something less likely to be
exceeded? Such as s[999]. It will still be 313 lines (or 314 as it appears
to be now).

--
Bartc

luser- -droog

unread,
Mar 27, 2014, 5:36:27 AM3/27/14
to
On Thursday, March 27, 2014 4:30:10 AM UTC-5, Bart wrote:
> "luser- -droog" <mij...@yahoo.com> wrote in message
>
> news:0d58b53e-4b47-462b...@googlegroups.com...
>
> > compiles without warnings (if you don't ask for warnings) with gcc.
>
> > currently 313 terse lines.
> > https://github.com/luser-dr00g/inca
> >
> > Questions? Improvements? Style-bashing?
>
>
> The C code very cleverly resembles APL too.

That part comes from the original source,
but I've tried to stay true to the original style.
But there are numerous //commented printfs where
I've needed to probe what it was doing.

>
> > If the length of the command string exceeds 98 characters,
> > the behavior is undefined.
>
>
> Can't you just increase the s[99] in main() to something less likely to be
> exceeded? Such as s[999]. It will still be 313 lines (or 314 as it appears
> to be now).
>

Certainly that can be done, but it still needs the scary
warning, I think.

luser- -droog

unread,
Mar 27, 2014, 5:40:39 AM3/27/14
to
The part I'm really proud of is getting it to do a
matrix product:
86400 3600 60 1+..0 2 1 18
=> 7278 .

The first dot is "dot-product", the second dot is "product".

I thought about making "power" an operator instead of a function, but it got too weird to think about.

or never got weird enough, maybe.


In order to do "base" and "encode" like the APL book describes, I'll need to generate a triangular matrix. And probably a whole prototype matrix family.

So I'm thinking that'll be a dyadic operator, similar to the circle functions, and maybe I can do rotation/transposition the same way.

And at some point, I'll want to extend it to handle floating-point numbers and character strings.

With strings, it can invoke execute as a function, and then variables can hold code.

Unfortunately, I can't use "dot" as a floating-point notation if it's overloaded already as a function and an operator. :(

David Brown

unread,
Mar 27, 2014, 7:23:20 AM3/27/14
to
I guess the original author wanted to write something akin to APL, but
which could be accepted by a C compiler.



David Brown

unread,
Mar 27, 2014, 7:25:08 AM3/27/14
to
An APL program that exceeds 98 characters is scary - one that exceeds
998 characters would be terrifying. I don't think a warning is needed!


jacob navia

unread,
Mar 27, 2014, 9:06:34 AM3/27/14
to
I have programmed in APL for years. I worked in STSC, the main APL
provider in the 80s, and always my variable names were clear mnemonic
names. APL is succint, yes, but if you use it correctly you can write
quite readable software.

Besides, there is no point in using gets() for a fixed length line.
lcc-win provides "getline()" and many other compilrs do that too.



David Brown

unread,
Mar 27, 2014, 11:11:21 AM3/27/14
to
On 27/03/14 14:06, jacob navia wrote:
> Le 27/03/2014 12:23, David Brown a écrit :
>> On 27/03/14 09:51, jacob navia wrote:
>>> So, you publish code that only you can read. GREAT!
>>>
>>
>> I guess the original author wanted to write something akin to APL, but
>> which could be accepted by a C compiler.
>>
> I have programmed in APL for years. I worked in STSC, the main APL
> provider in the 80s, and always my variable names were clear mnemonic
> names. APL is succint, yes, but if you use it correctly you can write
> quite readable software.

APL is only readable if you have learned to understand the symbols, and
if you have learned to understand the way of thinking (right-to-left
parsing without operator precedence, so that 4 * 2 + 3 is 20 in APL).
So you need to reach a higher level of understanding in APL than many
other languages before anything is comprehensible. Personally, I never
got anywhere near that stage when I played a little with APL some 25
years ago.

But of course you can write more or less readable code in APL, just as
you can in C and any other language. It is just that with APL, you can
take compact and virtually incomprehensible code to new heights that
would make any IOCC winner cry. You can also write code that /looks/
like it is a compact and incomprehensible collection of symbols, while
it is actually perfectly readable to APL experts - you can't do that with C.

Keith Thompson

unread,
Mar 27, 2014, 11:28:04 AM3/27/14
to
luser- -droog <mij...@yahoo.com> writes:
> compiles without warnings (if you don't ask for warnings) with
> gcc. currently 313 terse lines.
>
> https://github.com/luser-dr00g/inca
>
> Questions? Improvements? Style-bashing?
[...]

typedef char C;
typedef intptr_t I;
typedef struct a{I t,r,d[3],p[2];} *A;
[...]

#define P printf
#define R return

And that's where I stopped reading.

I'm curious, though. Why would you write code like that? Is it
deliberately obfuscated?

Oh, and inca.c will not compile, since the name intptr_t is not visible.
(This isn't just an error in the current versions; all 27 versions in
your repository have the same problem.) If it compiles without error
for you, there may be something wrong with your C implementation.

Once you fix that, try compiling on a 64-bit system.

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Javier Lopez

unread,
Mar 27, 2014, 1:30:49 PM3/27/14
to
El 27/03/2014 8:53, luser- -droog escribió:
> compiles without warnings (if you don't ask for warnings) with gcc. currently 313 terse lines.
>
> https://github.com/luser-dr00g/inca
>
> Questions? Improvements? Style-bashing?
Good for IOCCC ;)
http://www.ioccc.org/

Keith Thompson

unread,
Mar 27, 2014, 2:04:18 PM3/27/14
to
Not really. IOCCC requires more creative obfuscation than hacks like
"#define R return" that can be resolved just by running the code through
the preprocessor (which the judges will do).

luser- -droog

unread,
Mar 27, 2014, 2:27:16 PM3/27/14
to
On Thursday, March 27, 2014 10:28:04 AM UTC-5, Keith Thompson wrote:
> luser- -droog <mij...@yahoo.com> writes:
>
> > compiles without warnings (if you don't ask for warnings) with
> > gcc. currently 313 terse lines.
> >
> > https://github.com/luser-dr00g/inca
> >
> > Questions? Improvements? Style-bashing?
>
> [...]
>
> typedef char C;
> typedef intptr_t I;
> typedef struct a{I t,r,d[3],p[2];} *A;
> [...]
>
> #define P printf
> #define R return
>
> And that's where I stopped reading.
>
> I'm curious, though. Why would you write code like that? Is it
> deliberately obfuscated?
>

As you've commented elsewhere in this thread, it is
/obscure/ but not very /obfuscated/, per se.

The goal I think, is compactness. I've lost some
of that while adding extensions, but I'm still trying
to keep it "tight", while removing limitations and
errant behavior.

> Oh, and inca.c will not compile, since the name intptr_t is not visible.
> (This isn't just an error in the current versions; all 27 versions in
> your repository have the same problem.) If it compiles without error
> for you, there may be something wrong with your C implementation.

Cygwin gcc (GCC) 4.5.3 let me get away with it.
But I've added <stdint.t>.

> Once you fix that, try compiling on a 64-bit system.
>

{shudder}. Touché.

BartC

unread,
Mar 27, 2014, 2:50:36 PM3/27/14
to


"luser- -droog" <mij...@yahoo.com> wrote in message
news:7ba39a50-f4bf-42de...@googlegroups.com...
> On Thursday, March 27, 2014 10:28:04 AM UTC-5, Keith Thompson wrote:

>> I'm curious, though. Why would you write code like that? Is it
>> deliberately obfuscated?
>>
>
> As you've commented elsewhere in this thread, it is
> /obscure/ but not very /obfuscated/, per se.
>
> The goal I think, is compactness. I've lost some
> of that while adding extensions, but I'm still trying
> to keep it "tight", while removing limitations and
> errant behavior.

Why is it necessary to keep it tight?

(I had a look earlier with a view to expanding it to 'normal' C. But after
about thirty seconds I gave up! It would be easier to rewrite from scratch.)

--
Bartc

Javier Lopez

unread,
Mar 27, 2014, 3:07:28 PM3/27/14
to
El 27/03/2014 19:04, Keith Thompson escribió:
> Javier Lopez <j.lo...@aol.com> writes:
>> El 27/03/2014 8:53, luser- -droog escribió:
>>> compiles without warnings (if you don't ask for warnings) with gcc. currently 313 terse lines.
>>>
>>> https://github.com/luser-dr00g/inca
>>>
>>> Questions? Improvements? Style-bashing?
>> Good for IOCCC ;)
>> http://www.ioccc.org/
>
> Not really. IOCCC requires more creative obfuscation than hacks like
> "#define R return" that can be resolved just by running the code through
> the preprocessor (which the judges will do).
>
If this wasn't intented for a obfuscation contest, then it is
deliberately obfuscated and I don't understand the point.

James Kuyper

unread,
Mar 27, 2014, 3:10:19 PM3/27/14
to
On 03/27/2014 02:27 PM, luser- -droog wrote:
> On Thursday, March 27, 2014 10:28:04 AM UTC-5, Keith Thompson wrote:
...
>> typedef char C;
>> typedef intptr_t I;
>> typedef struct a{I t,r,d[3],p[2];} *A;
>> [...]
>>
>> #define P printf
>> #define R return
>>
>> And that's where I stopped reading.
>>
>> I'm curious, though. Why would you write code like that? Is it
>> deliberately obfuscated?
>>
>
> As you've commented elsewhere in this thread, it is
> /obscure/ but not very /obfuscated/, per se.
>
> The goal I think, is compactness.

That's a pretty nearly worthless goal to be pursuing, and you're
pursuing at great expense to readability, a far more important goal.

Keith Thompson

unread,
Mar 27, 2014, 4:00:51 PM3/27/14
to
luser- -droog <mij...@yahoo.com> writes:
> On Thursday, March 27, 2014 10:28:04 AM UTC-5, Keith Thompson wrote:
>> luser- -droog <mij...@yahoo.com> writes:
>>
>> > compiles without warnings (if you don't ask for warnings) with
>> > gcc. currently 313 terse lines.
>> >
>> > https://github.com/luser-dr00g/inca
>> >
>> > Questions? Improvements? Style-bashing?
>>
>> [...]
>>
>> typedef char C;
>> typedef intptr_t I;
>> typedef struct a{I t,r,d[3],p[2];} *A;
>> [...]
>>
>> #define P printf
>> #define R return
>>
>> And that's where I stopped reading.
>>
>> I'm curious, though. Why would you write code like that? Is it
>> deliberately obfuscated?
>
> As you've commented elsewhere in this thread, it is
> /obscure/ but not very /obfuscated/, per se.
>
> The goal I think, is compactness. I've lost some
> of that while adding extensions, but I'm still trying
> to keep it "tight", while removing limitations and
> errant behavior.

My comment was that its obfuscation would not be suitable for the IOCCC
(http://www.ioccc.org/).

That kind of compactness is not a virtue. Abbreviating "return" and
"printf" (which all C programmers understand) as "R" and "P" serves no
useful purpose that I can think of. I for one will not waste my time
trying to read code written in that horrid style.

(Apparently there are other problems as well, such as depending on
implicit int and assuming that int and pointers are the same size.)

If you find it fun to write such code for yourself, you are of course
free to do so. If you want anyone else to read it, as implied by
posting it here, going out of your way to make it more difficult
to read is counterproductive.

glen herrmannsfeldt

unread,
Mar 27, 2014, 4:10:41 PM3/27/14
to
James Kuyper <james...@verizon.net> wrote:

(snip, someone wrote)
>> The goal I think, is compactness.

> That's a pretty nearly worthless goal to be pursuing, and you're
> pursuing at great expense to readability, a far more important goal.

There are still a few cases left where compact is fast, and fast
is important. For real-time systems, it is either fast enough or
doesn't work at all.

The inner loop of an interpreter should also be fast, sometimes
at the expense of readability. (Though there is no excuse
for not having enough comments to explain the unreadable part.)

-- glen

James Kuyper

unread,
Mar 27, 2014, 4:21:43 PM3/27/14
to
On 03/27/2014 04:10 PM, glen herrmannsfeldt wrote:
> James Kuyper <james...@verizon.net> wrote:
>
> (snip, someone wrote)
>>> The goal I think, is compactness.
>
>> That's a pretty nearly worthless goal to be pursuing, and you're
>> pursuing at great expense to readability, a far more important goal.
>
> There are still a few cases left where compact is fast, and fast
> is important. For real-time systems, it is either fast enough or
> doesn't work at all.

Compact source code? The speed with which source code is processed
seldom is an important factor. In any event, this style of code should,
if anything, slow down the compiler, because of the additional work that
needs to be done during translation phase 4 (preprocessing). The only
thing that this speeds up is the typing of the code - and even that only
applies if the unreadability of the code doesn't slow down the code
development process enough to make up for the smaller source code files.

glen herrmannsfeldt

unread,
Mar 27, 2014, 4:38:26 PM3/27/14
to
James Kuyper <james...@verizon.net> wrote:

(snip, I wrote)
>> There are still a few cases left where compact is fast, and fast
>> is important. For real-time systems, it is either fast enough or
>> doesn't work at all.

> Compact source code? The speed with which source code is processed
> seldom is an important factor.

Sometimes more compact code is faster, but not always.

Personally, I like table-driven code, which tends to be compact,
some may find it more readable, some less.

I prefer a loop with a single IF statement in it to tens or
hundreds of consecutive IF statements testing different values
for a single, or small number, of variables. (Yes, I have seen
that latter in actual production code.)

Other than intentional obfuscation, exactly what someone
finds more readable can be different for different people.

-- glen




glen herrmannsfeldt

unread,
Mar 27, 2014, 4:47:01 PM3/27/14
to
Keith Thompson <ks...@mib.org> wrote:

(snip)

> My comment was that its obfuscation would not be suitable for the IOCCC
> (http://www.ioccc.org/).

> That kind of compactness is not a virtue. Abbreviating "return" and
> "printf" (which all C programmers understand) as "R" and "P" serves no
> useful purpose that I can think of. I for one will not waste my time
> trying to read code written in that horrid style.

There was once a question asked to one of the original creators of
unix, if they could go back and change one thing, what would they
have done differently.

As I remember it, it was spelling creat() with an extra e.

Many unix commands are shorter than similar commands on other
systems, and if not short enough, shell aliases will make them shorter.

It is very common in PostScript to define shorter versions of
common commands (I forget what PS calls them). (Though often that
is for program generated, not meant to be read by humans, code.)

> (Apparently there are other problems as well, such as depending on
> implicit int and assuming that int and pointers are the same size.)

> If you find it fun to write such code for yourself, you are of course
> free to do so. If you want anyone else to read it, as implied by
> posting it here, going out of your way to make it more difficult
> to read is counterproductive.

-- glen

BartC

unread,
Mar 27, 2014, 5:06:39 PM3/27/14
to


"glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
news:lh20k0$4pt$1...@speranza.aioe.org...
> James Kuyper <james...@verizon.net> wrote:
>
> (snip, someone wrote)
>>> The goal I think, is compactness.
>
>> That's a pretty nearly worthless goal to be pursuing, and you're
>> pursuing at great expense to readability, a far more important goal.
>
> There are still a few cases left where compact is fast, and fast
> is important. For real-time systems, it is either fast enough or
> doesn't work at all.

That doesn't follow, unless you're dealing with actual source code at run
time.

And even if significant, we don't know in this example how compact or
otherwise the expanded code might be.

> The inner loop of an interpreter should also be fast, sometimes
> at the expense of readability. (Though there is no excuse
> for not having enough comments to explain the unreadable part.)

This is one dispatch loop for a bytecode interpreter:

typedef void (*(*fnptr))(void);

do {
(**(fnptr)(pcptr))();
} while (!stopped);

It's reasonably fast (over 100M bytecodes per second), and is still pretty
clear, which is not unexpected for three lines of code! (BTW removing the
stop condition, just while(1), makes it slower for some reason.)

Faster (approaching 200M) is this, showing just one of nearly 300 similar
cases, each of which is handled in the same way:

while (1) {
switch (*pcptr) {
case knop: do_nop(); break;
....
}
}

That's about as far as I could go while using standard C, and still having
an actual inner loop. I've gone a couple of further steps, and managed
200-400M bytecodes per second, but the basic C bytecode handler functions
/are the same/ in all cases.

That is, for every bytecode instruction, there is a discrete, dedicated
function to handle it. You can't get more straightforward than that. And
compiler inlining will also collapse a lot of these, there is no need for
the code to be physically compact and unreadable.

--
Bartc

glen herrmannsfeldt

unread,
Mar 27, 2014, 6:10:57 PM3/27/14
to
BartC <b...@freeuk.com> wrote:

(big snip)

> Faster (approaching 200M) is this, showing just one of nearly 300 similar
> cases, each of which is handled in the same way:

> while (1) {
> switch (*pcptr) {
> case knop: do_nop(); break;
> ....
> }
> }

> That's about as far as I could go while using standard C, and still having
> an actual inner loop. I've gone a couple of further steps, and managed
> 200-400M bytecodes per second, but the basic C bytecode handler functions
> /are the same/ in all cases.

> That is, for every bytecode instruction, there is a discrete, dedicated
> function to handle it. You can't get more straightforward than that. And
> compiler inlining will also collapse a lot of these, there is no need for
> the code to be physically compact and unreadable.

I was recently looking at the flow charts of the microcode for the
IBM 360/40 CPU. (The smallest of the 360s that could run OS/360.)
Seems that they do a 16 way branch on the high half of the opcode,
followed by 16 way branches on the low half. I presume that it was
too much to supply a 256 way branch in microcode.

I wonder how the speed of nested 16 way switch/case would compare
to a 256 way switch/case?

-- glen

BartC

unread,
Mar 27, 2014, 7:07:50 PM3/27/14
to
"glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
news:lh27lh$muc$1...@speranza.aioe.org...
> BartC <b...@freeuk.com> wrote:

>> Faster (approaching 200M) is this, showing just one of nearly 300 similar
>> cases, each of which is handled in the same way:
>
>> while (1) {
>> switch (*pcptr) {
>> case knop: do_nop(); break;
>> ....
>> }
>> }

> I was recently looking at the flow charts of the microcode for the
> IBM 360/40 CPU. (The smallest of the 360s that could run OS/360.)
> Seems that they do a 16 way branch on the high half of the opcode,
> followed by 16 way branches on the low half. I presume that it was
> too much to supply a 256 way branch in microcode.
>
> I wonder how the speed of nested 16 way switch/case would compare
> to a 256 way switch/case?

There must have had their reasons for using a two-level switch. It's also
possible the flowchart didn't fully represent what was going on in the
microcode.

Although that would be a little different from a C switch which has to deal
with a default case, which is extra overhead for each level.

(Maybe there is a way of telling C not to use a default case, or it might be
able to infer it if, say, the switch expression was 8-bits, and 256
different case labels were provided.)

--
Bartc

Kaz Kylheku

unread,
Mar 27, 2014, 7:46:39 PM3/27/14
to
On 2014-03-27, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> James Kuyper <james...@verizon.net> wrote:
>
> (snip, I wrote)
>>> There are still a few cases left where compact is fast, and fast
>>> is important. For real-time systems, it is either fast enough or
>>> doesn't work at all.
>
>> Compact source code? The speed with which source code is processed
>> seldom is an important factor.
>
> Sometimes more compact code is faster, but not always.

Compactness obtained from transformations like:

#define l long_variable_name

has no bearing on executable speed.

James Kuyper

unread,
Mar 27, 2014, 8:25:43 PM3/27/14
to
On 03/27/2014 04:38 PM, glen herrmannsfeldt wrote:
> James Kuyper <james...@verizon.net> wrote:
>
> (snip, I wrote)
>>> There are still a few cases left where compact is fast, and fast
>>> is important. For real-time systems, it is either fast enough or
>>> doesn't work at all.
>
>> Compact source code? The speed with which source code is processed
>> seldom is an important factor.
>
> Sometimes more compact code is faster, but not always.

Are you talking about the code compiling faster, or executing faster?
Use of these macros might have a small amount of influence on the
compilation speed, but they shouldn't have any effect on the execution
speed. Are you really suggesting that use of these particular macros
might speed up (rather than slow down, as I expect) compilation of the
code sufficiently to justify using them?

...
> Other than intentional obfuscation, exactly what someone
> finds more readable can be different for different people.

In some cases, yes, readability can be a highly subjective issue, but
I'm not willing to concede that these particular macros could ever be
anything but an obfuscation, and a fairly substantial one at that. That
might not have been the author's intent, but it is in fact what he has
achieved.
--
James Kuyper

Javier Lopez

unread,
Mar 27, 2014, 8:53:20 PM3/27/14
to
El 27/03/2014 21:38, glen herrmannsfeldt escribió:
> James Kuyper <james...@verizon.net> wrote:
>
> (snip, I wrote)
>>> There are still a few cases left where compact is fast, and fast
>>> is important. For real-time systems, it is either fast enough or
>>> doesn't work at all.
>
>> Compact source code? The speed with which source code is processed
>> seldom is an important factor.
>
> Sometimes more compact code is faster, but not always.
I guess you are referring to generated machine code and then, yes, in
modern architectures more compact code == faster because of cache
locality. Likewise, larger code == slower because cache trashing.

But compact object code doesn't have /anything/ to do with compact
sources anyway.

Javier Lopez

unread,
Mar 27, 2014, 9:01:43 PM3/27/14
to
El 27/03/2014 22:06, BartC escribió:
> This is one dispatch loop for a bytecode interpreter:
>
> typedef void (*(*fnptr))(void);
>
> do {
> (**(fnptr)(pcptr))();
> } while (!stopped);
>
> It's reasonably fast (over 100M bytecodes per second), and is still pretty
> clear, which is not unexpected for three lines of code! (BTW removing
> the stop condition, just while(1), makes it slower for some reason.)
This depends on how smart the compiler is and the target architecture.
Because of indirect SIB (Scale-Index-Base) call on x86, I guess it
should be faster to use a jump table than to use switch.

If I'm not wrong, it should be faster to use switch if there's little
cases because of iCache.

James Kuyper

unread,
Mar 27, 2014, 9:18:34 PM3/27/14
to
Code using such macros has frequently been posted to this newsgroup by
people using a variety of different names, such as io_x <a...@b.c.invalid>,
Rosario1903 <Ros...@invalid.invalid>, "Citizen C" <alex5...@aol.com>,
"¬a\\/b" <al@f.g>, av <av@ala.a>, RoSsIaCrIiLoIA <n...@esiste.ee>, Giuseppe
<gius...@giuseppe.wwwew>. I found several references to an older
obfuscator named "Jens", though I didn't find any of his actual
messages. The reason why they chose to do so has been frequently asked,
but never (to my knowledge) satisfactorily answered. Hanlon's Razor
suggests that it might have been intended merely to reduce typing, but
I'm not willing to rule out a deliberate attempt to obfuscate.

It's hard to believe that so many people could separately invent a
concept so stupid; possibly they borrowed from each other. Since very
few, if any, of them seem to have valid e-mail addresses, they could
easily be multiple aliases for a much smaller cadre of idiots.

One message I found traced the usage back to "Arthur Whitney's J
Interpreter", which seems pretty suspicious in the context of this thread.
--
James Kuyper

glen herrmannsfeldt

unread,
Mar 27, 2014, 10:00:55 PM3/27/14
to
James Kuyper <james...@verizon.net> wrote:

(snip, I wrote)
>>>> There are still a few cases left where compact is fast, and fast
>>>> is important. For real-time systems, it is either fast enough or
>>>> doesn't work at all.

>>> Compact source code? The speed with which source code is processed
>>> seldom is an important factor.

>> Sometimes more compact code is faster, but not always.

> Are you talking about the code compiling faster, or executing faster?

Sorry, I meant more generally on writing compact code, and not
specifically on using macros to make it look smaller.

> Use of these macros might have a small amount of influence on the
> compilation speed, but they shouldn't have any effect on the execution
> speed. Are you really suggesting that use of these particular macros
> might speed up (rather than slow down, as I expect) compilation of the
> code sufficiently to justify using them?

For non-english speakers, I have no idea what macros might make
it easier to read C code. I might believe that for some people
single letters would be better.

Reminds me of a comment from IBM about the Fortran H compiler.
Seems that they use six (names are one to six characters long)
balanced trees, one for each length. They suggest that for maximum
compilation speed you should distribute your names evenly between
one and six characters long. No suggestion of readability.


>> Other than intentional obfuscation, exactly what someone
>> finds more readable can be different for different people.

> In some cases, yes, readability can be a highly subjective issue, but
> I'm not willing to concede that these particular macros could ever be
> anything but an obfuscation, and a fairly substantial one at that. That
> might not have been the author's intent, but it is in fact what he has
> achieved.

I might believe that on a 32 character wide screen that shorter names
make for more readable C. I did at one time use a computer running C
with a 32 character screen. Though I could print them out on wider
paper. (I had a 132 character wide printer at the time.)

-- glen

Message has been deleted

luser- -droog

unread,
Mar 28, 2014, 2:22:23 AM3/28/14
to
On Thursday, March 27, 2014 8:18:34 PM UTC-5, James Kuyper wrote:
> On 03/27/2014 03:07 PM, Javier Lopez wrote:
> > El 27/03/2014 19:04, Keith Thompson escribió:
> >> Javier Lopez <j.lo...@aol.com> writes:
> >>> El 27/03/2014 8:53, luser- -droog escribió:
> >>>> compiles without warnings (if you don't ask for >
> >>>>
What, I wonder, is "suspicious" about this?

My source says the same thing.
http://www.jsoftware.com/jwiki/Essays/Incunabulum

FWIW, I have removed the P and R macros and added
many comments to inca.c and examples to the README,
so you don't actually need to try to compile it to
get a feel for what the heck I'm talking about.

--
Michael Joshua Ryan (aka. luser-droog)
human individual.

luser- -droog

unread,
Mar 28, 2014, 2:33:37 AM3/28/14
to
On Thursday, March 27, 2014 4:06:43 AM UTC-5, luser- -droog wrote:
> On Thursday, March 27, 2014 3:51:04 AM UTC-5, jacob navia wrote:
>
> >
> > So, you publish code that only you can read. GREAT!
>
> Perhaps a select few others across this wide globe.
>
> It's definitely a hornet's nest of a pile of code droppings.
> But it kinda all works, if you type the syntax right.
>
> In your attempt, the spacing was off.
>
> 1+1
> should work. A space following a number must be
> followed by another number, and it concatenates
> the two into a list terminated by the first
> operator/function.
>
> 1 1 1+3 => 4 4 4
>
> It took me weeks poring over that original J
> incunabulum. Then learning more apl for context,
> then going back to the incunabulum.
>

Oops. No. Rosy memory. I've been scrutinizing the
original code for over a year, as the dates on my
comments to the SO question linked in the README show.

> The "byte"-code (actually, integer-code) format
> distinguishes between types by ranges.
> x < 16ish : it's a function or operator
> x >= '_' && x <= 'z' : it's a variable
> x > 'z' : it's a pointer
>
> This makes the assumption that pointer values
> in the ascii range are never returned by malloc.

luser- -droog

unread,
Mar 28, 2014, 3:15:10 AM3/28/14
to
On Thursday, March 27, 2014 3:47:01 PM UTC-5, glen herrmannsfeldt wrote:
> Keith Thompson <ks...@mib.org> wrote:
>
> (snip)
>
> > My comment was that its obfuscation would not be suitable for the IOCCC
>
> > (http://www.ioccc.org/).
>
> > That kind of compactness is not a virtue. Abbreviating "return" and
> > "printf" (which all C programmers understand) as "R" and "P" serves no
> > useful purpose that I can think of. I for one will not waste my time
> > trying to read code written in that horrid style.
>
> There was once a question asked to one of the original creators of
> unix, if they could go back and change one thing, what would they
> have done differently.
>
> As I remember it, it was spelling creat() with an extra e.
>
> Many unix commands are shorter than similar commands on other
> systems, and if not short enough, shell aliases will make them shorter.
>
> It is very common in PostScript to define shorter versions of
> common commands (I forget what PS calls them). (Though often that
> is for program generated, not meant to be read by humans, code.)
>
> > (Apparently there are other problems as well, such as depending on
> > implicit int and assuming that int and pointers are the same size.)
>

I'll look again. But I think I've added "I"s for all the
returns actually used. Then remaining implicit ints
should all be void-functions.

> > If you find it fun to write such code for yourself, you are of course
> > free to do so. If you want anyone else to read it, as implied by
> > posting it here, going out of your way to make it more difficult
> > to read is counterproductive.
>

I do understand that it appears that way. But that's
not how it happened. Take a peek at the the J incunabulum
that I started with. I merely tried to maintain a consistent
style while adding extensions.

BartC

unread,
Mar 28, 2014, 5:33:10 AM3/28/14
to


"Javier Lopez" <j.lo...@aol.com> wrote in message
news:lh2hn7$c87$1...@speranza.aioe.org...
Yes, that switch-based code I showed was faster than the simple
function-call loop. Almost certainly because the former can make excellent
use of inlining.

What is faster still than the switch, is to use a jump-table containing
label pointers. But this is not satisfactory because it uses both a
non-standard gcc extension, and lots of gotos:

loop:
goto **pcptr;

jnop:
do_nop();
goto loop;

.... // 280 more similar groups

(The table of pointers exists, but the contents are used to fix-up the
byte-code so it contains the label pointers directly.)

Strangely, eliminating the second goto to achieve 'threaded' code (and have
no 'inner loop') was slower:

loop:
goto **pcptr; // only executed once

jnop:
do_nop();
goto **pcptr; // After each bytecode, jump direct to the next
....

(Fastest is probably a threaded code 'inner loop' written in ASM and using
dedicated registers. Initially however it is slower than even the
function-call loop, because there is no inlining, and there are extra
overheads in saving registers to call the C bytecode handlers. The speed
comes from dealing with selected bytecodes in ASM and avoiding calling C as
much as possible.

This is all for a pure bytecode interpreter dealing with dynamic, tagged
data. There are more sophisticated techniques but then it will no longer be
a simple interpreter.)


--
Bartc

BartC

unread,
Mar 28, 2014, 6:47:09 AM3/28/14
to


"BartC" <b...@freeuk.com> wrote in message
news:fq_Yu.38364$9F.2...@fx27.am4...
I've done some work with the source. The results are here:

http://pastebin.com/7J0tfbJU

Mainly, replacing I by INT, A by ABC (to make things simpler for my editor),
and giving more vertical space to the functions. Ideally everything there
would be one statement per line, and the code would be consistently
indented, but I guess tools exist to do all that.

The overall structure is now a bit clearer (especially after I figured out
that V1 and V2 define functions), but it still looks quite complex to fully
understand. (Not knowing APL doesn't help.)

The code is also still very fragile: most things I type in will crash it.

--
Bartc

luser- -droog

unread,
Mar 28, 2014, 7:26:05 AM3/28/14
to
On Thursday, March 27, 2014 3:47:01 PM UTC-5, glen herrmannsfeldt wrote:
> Keith Thompson <ks...@mib.org> wrote:
>
> (snip)
>
> > My comment was that its obfuscation would not be suitable for the IOCCC
> > (http://www.ioccc.org/).
> > That kind of compactness is not a virtue. Abbreviating "return" and
> > "printf" (which all C programmers understand) as "R" and "P" serves no
> > useful purpose that I can think of. I for one will not waste my time
> > trying to read code written in that horrid style.
>
> There was once a question asked to one of the original creators of
> unix, if they could go back and change one thing, what would they
> have done differently.
>
> As I remember it, it was spelling creat() with an extra e.
>
> Many unix commands are shorter than similar commands on other
> systems, and if not short enough, shell aliases will make them shorter.
>
> It is very common in PostScript to define shorter versions of
> common commands (I forget what PS calls them). (Though often that
> is for program generated, not meant to be read by humans, code.)
>

They're usually called "mnemonics", assuming you do it right.
In postscript this can have benefits in storage space,
transmission time, and execution speed. Handwritten code will
often use loops and procedures, thus paying for decoding the
names just once, but generated code is usually unrolled,
so reducing a name by 1 char reduces the file by 1 char
for each usage, which can be significant.


Keith Thompson

unread,
Mar 28, 2014, 11:42:00 AM3/28/14
to
luser- -droog <mij...@yahoo.com> writes:
[...]
> I'll look again. But I think I've added "I"s for all the
> returns actually used. Then remaining implicit ints
> should all be void-functions.

If you're trying to write conforming modern C, you need to remove *all*
occurrences of implicit int. A void function needs to be declared with
an explicit return type of "void".

The "implicit int" feature was removed from the language by the C99
standard.

[...]

> I do understand that it appears that way. But that's
> not how it happened. Take a peek at the the J incunabulum
> that I started with. I merely tried to maintain a consistent
> style while adding extensions.

I found this:

https://github.com/tangentstorm/j-incunabulum

and in particular this:

https://github.com/tangentstorm/j-incunabulum/blob/master/ji.c

which I see is where the horrid macro definitions:

#define P printf
#define R return

came from. It's based on some code written in 1989, which probably
explains the use of implicit int. Quoting the README.md:

Although the code is terse and may seem unreadable at first,
it can be understood with a little effort. It may help to
understand that the code was written for and by people who
were very familiar with array-centric languages (APL) and who
came from a strong mathematical background. Indeed, one of the
main reasons for adopting a style like this is that it meakes
it easier to reason about and manipulate the code algebraically.

I'm not convinced about the claimed advantages of the style,
though I suppose it's possible I'm missing something.

Kenny McCormack

unread,
Mar 28, 2014, 12:49:35 PM3/28/14
to
In article <lntxaij...@nuthaus.mib.org>,
Keith Thompson <ks...@mib.org> wrote:
...
>If you're trying to write conforming modern C,

I think it is pretty clear that that's the last thing on "luser"'s mind or
list of goals and intentions.

>you need to remove *all* occurrences of implicit int.

He "needs" to do no such thing. Besides, I thought that C89 was still the
only "real" standard endoresed by the regs here.

>A void function needs to be declared with
>an explicit return type of "void".

There you go again. Telling people what they need.
How paternalistic of you!

>The "implicit int" feature was removed from the language by the C99
>standard.

Which means it is perfectly legal and OK by all standards bodies (including
you, Mr. Kiki!) in C89 code (which is what most people still write).
...
>which I see is where the horrid macro definitions:

Keep your editorial comments to yourself, please.

> Although the code is terse and may seem unreadable at first,
> it can be understood with a little effort. It may help to
> understand that the code was written for and by people who
> were very familiar with array-centric languages (APL) and who
> came from a strong mathematical background. Indeed, one of the
> main reasons for adopting a style like this is that it meakes
> it easier to reason about and manipulate the code algebraically.

Indeed. So get off their backs, OK!

>I'm not convinced about the claimed advantages of the style,
>though I suppose it's possible I'm missing something.

We're not here to convince you - or to gain your approval.

Go away!

--
"Although written many years ago, Lady Chatterley's Lover has just
been reissued by the Grove Press, and this fictional account of the
day-to-day life of an English gamekeeper is still of considerable
interest to outdoor minded readers, as it contains many passages on
pheasant raising, the apprehending of poachers, ways to control vermin,
and other chores and duties of the professional gamekeeper.

"Unfortunately, one is obliged to wade through many pages of extraneous
material in order to discover and savor these sidelights on the
management of a Midlands shooting estate, and in this reviewer's opinion
this book cannot take the place of J.R. Miller's Practical Gamekeeping"
(Ed Zern, Field and Stream, November 1959, p. 142).

James Kuyper

unread,
Mar 28, 2014, 9:36:58 PM3/28/14
to
On 03/28/2014 11:42 AM, Keith Thompson wrote:
...
> I found this:
>
> https://github.com/tangentstorm/j-incunabulum
>
> and in particular this:
>
> https://github.com/tangentstorm/j-incunabulum/blob/master/ji.c
>
> which I see is where the horrid macro definitions:
>
> #define P printf
> #define R return
>
> came from. It's based on some code written in 1989, which probably
> explains the use of implicit int. Quoting the README.md:
>
> Although the code is terse and may seem unreadable at first,
> it can be understood with a little effort. It may help to
> understand that the code was written for and by people who
> were very familiar with array-centric languages (APL) and who
> came from a strong mathematical background. Indeed, one of the
> main reasons for adopting a style like this is that it meakes
> it easier to reason about and manipulate the code algebraically.
>
> I'm not convinced about the claimed advantages of the style,
> though I suppose it's possible I'm missing something.

APL's syntax does indeed make it easier to "reason about an manipulate
the [APL] code algebraically". However, that C coding style provides no
such benefit.
--
James Kuyper

Öö Tiib

unread,
Mar 29, 2014, 6:16:26 AM3/29/14
to
On Thursday, 27 March 2014 11:06:43 UTC+2, luser- -droog wrote:
> In your attempt, the spacing was off.

Programs that crash or hang on any input (regardless
if "spacing was off" in input or other such silly
reason) are dangerous trash.

Crash means it is often possible to overtake system with
malicious input, hang means that it is vulnerable to DOS
attack.

So ... learn to program, pal.

glen herrmannsfeldt

unread,
Mar 29, 2014, 1:57:49 PM3/29/14
to
luser- -droog <mij...@yahoo.com> wrote:

(snip)

Talking about APL, I just found out that the Computer History Museum
(computerhistory.org) has the source from IBM for APL\360.

As usual, for non-commercial use and no redistribution.
(You have to agree to the license terms before downloading.)

I am not sure what the rights would be if you rewrote it in C.

-- glen

Kaz Kylheku

unread,
Mar 29, 2014, 3:01:06 PM3/29/14
to
On 2014-03-29, glen herrmannsfeldt <g...@ugcs.caltech.edu> wrote:
> Talking about APL, I just found out that the Computer History Museum
> (computerhistory.org) has the source from IBM for APL\360.
>
> As usual, for non-commercial use and no redistribution.
> (You have to agree to the license terms before downloading.)

`Cause if you violate this, some little old man will show up at your door and
beat you with his cane.

(Actually he will beat you with a toothpick which denotes the
semantics of being whipped in parallel with 1000 canes.)

BartC

unread,
Mar 29, 2014, 4:29:58 PM3/29/14
to


"glen herrmannsfeldt" <g...@ugcs.caltech.edu> wrote in message
news:lh71it$tgp$2...@speranza.aioe.org...
It seems to be written in assembly code (360 I guess, judging from the "L"
opcode I recognised).

You will have your work cut out in rewriting it in anything, as it is likely
closely tied to that platform. Suddenly luser- -droog's version doesn't
seem so bad after all!

--
Bartc

Dr Nick

unread,
Mar 29, 2014, 4:40:03 PM3/29/14
to
And this is, of course, the classic answer to the "no function should be
more than ... lines long" argument.

glen herrmannsfeldt

unread,
Mar 29, 2014, 5:12:20 PM3/29/14
to
BartC <b...@freeuk.com> wrote:

(snip, I wrote)

>> Talking about APL, I just found out that the Computer History Museum
>> (computerhistory.org) has the source from IBM for APL\360.

(snip)
>> I am not sure what the rights would be if you rewrote it in C.

> It seems to be written in assembly code (360 I guess, judging
> from the "L" opcode I recognised).

From that time frame, most was written directly in assembler,
but later in an internal PL/I-like language, compiled to assembly
code, and only the generated assembly code was released outside IBM.

> You will have your work cut out in rewriting it in anything,
> as it is likely closely tied to that platform. Suddenly
> luser- -droog's version doesn't seem so bad after all!

-- glen

luser- -droog

unread,
Apr 7, 2014, 3:44:22 AM4/7/14
to
I've adopted some of your substitutions,
but I've run into trouble get it to do
general matrix multiplications. I suppose it's
a harder task than I forsaw. It did take them
a long time the first time.

luser- -droog

unread,
Apr 12, 2014, 9:59:15 PM4/12/14
to
For anyone attempting to write an APL from scratch, one of
the best design documents I've found is this one from 1972
which describes an APL Machine as a microcode emulator
for the IBM 5100 to work with the system 360 emulator.
http://bitsavers.informatik.uni-stuttgart.de/pdf/ibm/apl/An_APL_Emulator_Jun72.pdf

While there are many similar documents available describing
everything from IVSYS on the 7090 through the SV and later
versions, but this 1972 document gives many more memory
map examples showing the organization of the low-level
data structures in much more detail than most other write-ups.

Incidentally, inca has acquired some new bizarre features,
such as template code generation. It's now pushing 1000 lines.

$ ./inca
i<:0!1+~y
7
0!1+~y
o<:0=1+~y
7
0=1+~y
u<:('ox),'iy
10
('ox),'iy
2"u3
5
0 0 1 1 1
!5"u9
14
1 1 1 1 1 0 0 0 0 0 0 0 0 0
r<:(40.'iy);(1+~<y);((0{:").'iy);((0{:u).'iy);(@~<y);(41.'iy);((0{:;).'iy-1),0
76
(40.'iy);(1+~<y);((0{:").'iy);((0{:u).'iy);(@~<y);(41.'iy);((0{:;).'iy-1),0
'r3
7 3
40 40 40
-2147117200 -2147117104 -2147117008
20 20 20
117 117 117
-2147115616 -2147115648 -2147115680
41 41 41
23 23 0
$,\@`
21
(1"u2);(2"u1);(3"u0)
;`
3 3
0 1 1
0 0 1
0 0 0

0 new messages