digitalmars.D.learn - Trying to understand map being a template
- =?UTF-8?B?Tm/DqQ==?= Falzon (44/44) Jan 05 On the subject of `map` taking the function as template
- H. S. Teoh (11/25) Jan 05 That's simple, if the argument is a runtime function, it is treated as a
- Paul Backus (18/29) Jan 06 It works for the same reason this example works:
- FeepingCreature (52/83) Jan 06 To clarify, what this actually compiles to is:
- =?UTF-8?B?Tm/DqQ==?= Falzon (3/3) Jan 09 Thank you very much for your answers. The point I had mostly
On the subject of `map` taking the function as template parameter, I was surprised to see it could still be used with functions determined at runtime, even closures, etc. I am trying to understand the mechanism behind it. The commented out line causes the error that `choice(funcs)` cannot be determined at compile time, which is fair, but how is it not the same case for `func` two lines above? I thought it might be because the functions are literals visible at compile time, but the closure makes that dubious. ``` import std.stdio; import std.algorithm; import std.random; void main() { int r = uniform(0,100); int delegate(int)[] funcs = [ x => x * 2, x => x * x, x => 3, x => x * r // Closure ]; auto foo = [1,2,3,4,5]; foreach(i; 0..10) { // This is fine: auto func = funcs.choice; writeln(foo.map!func); // This is not? // writeln(foo.map!(funcs.choice)); } } ``` In fact, how can the template be instantiated at all in the following example, where no functions can possibly be known at compile time: ``` auto do_random_map(int delegate(int)[] funcs, int[] values) { auto func = funcs.choice; return values.map!func; } ``` Thank you for the insights!
Jan 05
On Fri, Jan 05, 2024 at 08:41:53PM +0000, Noé Falzon via Digitalmars-d-learn wrote:On the subject of `map` taking the function as template parameter, I was surprised to see it could still be used with functions determined at runtime, even closures, etc. I am trying to understand the mechanism behind it.That's simple, if the argument is a runtime function, it is treated as a function pointer (or delegate). [...]In fact, how can the template be instantiated at all in the following example, where no functions can possibly be known at compile time: ``` auto do_random_map(int delegate(int)[] funcs, int[] values) { auto func = funcs.choice; return values.map!func; } ```[...] The argument is taken to be a delegate to be bound at runtime. In the instantiation a shim is inserted to pass along the delegate from the caller's context. T -- Creativity is not an excuse for sloppiness.
Jan 05
On Friday, 5 January 2024 at 20:41:53 UTC, Noé Falzon wrote:In fact, how can the template be instantiated at all in the following example, where no functions can possibly be known at compile time: ``` auto do_random_map(int delegate(int)[] funcs, int[] values) { auto func = funcs.choice; return values.map!func; } ``` Thank you for the insights!It works for the same reason this example works: ```d void printVar(alias var)() { import std.stdio; writeln(__traits(identifier, var), " = ", var); } void main() { int x = 123; int y = 456; printVar!x; // x = 123 printVar!y; // y = 456 x = 789; printVar!x; // x = 789 } ```
Jan 06
On Saturday, 6 January 2024 at 17:57:06 UTC, Paul Backus wrote:On Friday, 5 January 2024 at 20:41:53 UTC, Noé Falzon wrote:To clarify, what this actually compiles to is: ```d void main() { int x = 123; int y = 456; void printVar_x() { import std.stdio; writeln(__traits(identifier, x), " = ", x); } void printVar_y() { import std.stdio; writeln(__traits(identifier, y), " = ", y); } printVar_x; printVar_y; x = 789; printVar_x; } ``` Which lowers to: ```d struct mainStackframe { int x; int y; } void printVar_main_x(mainStackframe* context) { import std.stdio; writeln(__traits(identifier, context.x), " = ", context.x); } void printVar_main_y(mainStackframe* context) { import std.stdio; writeln(__traits(identifier, context.y), " = ", context.y); } void main() { // this is the only "actual" variable in main() mainStackframe frame; frame.x = 123; frame.y = 456; printVar_main_x(&frame); printVar_main_y(&frame); frame.x = 789; printVar_main_x(&frame); } Same with `map`.In fact, how can the template be instantiated at all in the following example, where no functions can possibly be known at compile time: ``` auto do_random_map(int delegate(int)[] funcs, int[] values) { auto func = funcs.choice; return values.map!func; } ``` Thank you for the insights!It works for the same reason this example works: ```d void printVar(alias var)() { import std.stdio; writeln(__traits(identifier, var), " = ", var); } void main() { int x = 123; int y = 456; printVar!x; // x = 123 printVar!y; // y = 456 x = 789; printVar!x; // x = 789 } ```
Jan 06
Thank you very much for your answers. The point I had mostly misunderstood was alias template parameters, which make this possible.
Jan 09