www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Recursive delegate type?

reply WB <witold.baryluk gmail.com> writes:
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.
Apr 22
next sibling parent WB <witold.baryluk gmail.com> writes:
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
Apr 22
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
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.
Apr 22
parent WB <witold.baryluk gmail.com> writes:
On Tuesday, 22 April 2025 at 20:04:52 UTC, Timon Gehr wrote:
 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.
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.
Apr 22