Thread overview
Recursive delegate type?
Apr 22
WB
Apr 22
WB
Apr 23
WB
April 22

Most typed programming languages, other than maybe Haskell or Ocaml can do it, but throwing it here, as a puzzle:


alias OpCodeHandler = void function(OpCode *ops, Reg *regs, void*);


private string next(string offset = "1", string dispatch_table = "d", string ops = "ops", string pc = "pc", string args = ", regs") {
  return `return (cast(OpCodeHandler*)(` ~ dispatch_table ~ `))[*((` ~ ops ~ `) + (` ~ offset ~ `))]((` ~ ops ~ `) + (` ~ offset ~ `)` ~ args ~ `, (` ~ dispatch_table ~ `));`;
}


void add_int(OpCode *ops, Reg *regs, void* d) {
  regs[0].Int += 1;
  mixin(next(/*offset=*/"2"));
}
...

static __gshared OpCodeHandler[256] dispatch = [
  &add_int,
  ...
];

So the 3rd argument to the function (d), is actually of type OpCodeHandler*, but obviously that is not an option:

alias OpCodeHandler = void function(OpCode *ops, Reg *regs, OpCodeHandler*);

Any ideas, how to make it prettier, and avoid casts? I doubt it is possible.

April 22

On Tuesday, 22 April 2025 at 19:53:10 UTC, WB wrote:

>

Most typed programming languages, other than maybe Haskell or Ocaml can do it, but throwing it here, as a puzzle:

...
Any ideas, how to make it prettier, and avoid casts? I doubt it is possible.

Some random idea to myself. Y-combinator but on types. Maybe

April 22
On 4/22/25 21:53, WB wrote:
> Most typed programming languages, other than maybe Haskell or Ocaml can do it, but throwing it here, as a puzzle:
> 
> 
> ```d
> 
> alias OpCodeHandler = void function(OpCode *ops, Reg *regs, void*);
> 
> 
> private string next(string offset = "1", string dispatch_table = "d", string ops = "ops", string pc = "pc", string args = ", regs") {
>    return `return (cast(OpCodeHandler*)(` ~ dispatch_table ~ `))[*((` ~ ops ~ `) + (` ~ offset ~ `))]((` ~ ops ~ `) + (` ~ offset ~ `)` ~ args ~ `, (` ~ dispatch_table ~ `));`;
> }
> 
> 
> void add_int(OpCode *ops, Reg *regs, void* d) {
>    regs[0].Int += 1;
>    mixin(next(/*offset=*/"2"));
> }
> ...
> 
> static __gshared OpCodeHandler[256] dispatch = [
>    &add_int,
>    ...
> ];
> 
> ```
> 
> So the 3rd argument to the function (`d`), is actually of type `OpCodeHandler*`, but obviously that is not an option:
> 
> 
> ```d
> alias OpCodeHandler = void function(OpCode *ops, Reg *regs, OpCodeHandler*);
> ```
> 
> Any ideas, how to make it prettier, and avoid casts? I doubt it is possible.
> 
> 

D does not support equirecursion, but there is isorecursion:

```d
struct OpCodeHandler{
    void function(OpCode *ops, Reg *regs, OpCodeHandler*) payload;
    alias this=payload;
}
```

You can also unwrap it once:

```d
alias OpCodeHandler=void function(OpCode *ops, Reg *regs, OpCodeHandlerWrapper*);
struct OpCodeHandlerWrapper{
	OpCodeHandler payload;
	alias this=payload;
}
```

You may have to wrap and even unwrap manually sometimes, but there are no _unsafe_ casts required, at least.
April 23

On Tuesday, 22 April 2025 at 20:04:52 UTC, Timon Gehr wrote:

>

D does not support equirecursion, but there is isorecursion:

struct OpCodeHandler{
    void function(OpCode *ops, Reg *regs, OpCodeHandler*) payload;
    alias this=payload;
}

You can also unwrap it once:

alias OpCodeHandler=void function(OpCode *ops, Reg *regs, OpCodeHandlerWrapper*);
struct OpCodeHandlerWrapper{
	OpCodeHandler payload;
	alias this=payload;
}

You may have to wrap and even unwrap manually sometimes, but there are no unsafe casts required, at least.

That is pretty smart. Recursion works in structs in D, and with alias it is almost transparent. I will try that. Code gene should be the same too.

Also, I never heard of the term equirecursion and isorecursion, but nice to know the term, so the problem is easier to google.