CTFE thoughts & functional approach

Robert M. Münch via Digitalmars-d digitalmars-d at puremagic.com
Tue Feb 2 00:27:18 PST 2016


On 2016-01-31 14:35:13 +0000, cym13 said:

> I see things differently. First of all I don't see everyone trying
> to do meta-programming with the same language. C++ for example has
> a quite specific syntax between its arcane templates and the
> preprocessor.

Well, ok, maybe a "using the same concepts as the underlaying language" 
might hit it better.

> I see having the same language as a *huge* advantage. If a function
> doesn't have side effects then it can be used at runtime or at
> compile-time and integrated with your logic easily.

The thing I mean is not that you shouldn't be able to reference or use 
things from the "target language" but how to write down what you want 
to do. 

Code generation by building strings using the D operators for example 
is something I think is not very elegant. If I could use a list and 
build it up without having to care about the code / data difference, 
that would simplify things a lot.

Imagine we could use Lua during compile time and have access to the AST etc.


> D's metaprogramming success is IMHO directly linked to it not having
> a separate language for it, because it lowers the cost of learning
> and using metaprogramming.

But limits you to a subset that doesn't feel very natural for doing a 
lot of common things in code-generation.

> It's saying "metaprogramming isn't different from any other kind of 
> programming, you can use the same tools".

Yes, and I don't think this statement holds. It's very different 
because the goal is totally different. I need a tool that allows me to 
manipulate my underlying code during compilation. The main aspect is: 
Manipulate D code.

>> Why not have a CTL (compile-time-language) that has access to some 
>> compiler internals, that follows a more functional concept? We are 
>> evaluating sequences of things to generate code, include / exclude code 
>> etc.
> 
> Having access to some compiler internals is already what is done, or I 
> don't understand exactly what you mean by that.

Sure, but the question is how do to deal with it. IMO it's not very 
straight forward at the moment.

> I think you should put some sort of example of how you'd want it,
> because right now I don't understand. D has some nice functional
> tools and they already show their strength at compile-time.

Ok, here is a simple example: I want to ensure that specific switch 
statements handle all cases for a given enum, list, etc. This is a 
common pattern and often a source of problems because you change a 
collection but miss to update all side-effecting places.

This is an example how I have done it (maybe there is a much better way 
to do it, but I didn't come up with one):

==> BEGIN

import std.conv;
import std.stdio;
import std.string;
import std.traits;

// @@example code should work with classes as well
enum A {afoo, bfoo, cfoo};

enum members1 = __traits(allMembers, A); // returns TypeTuple
auto members2 = __traits(allMembers, A);

pragma(msg, typeof(members1));
// pragma(msg, typeid(members1)); // run-time only
// static assert(is(members1 : enum)); // Error: basic type expected, not enu

pragma(msg, typeof(members2));
// pragma(msg, typeid(members2)); // run-time only


// function that generates a string which is used as a mixin at compile time
// result string must conform to syntax as it was hand-written code
string generateEnums(T...)(string type){
    string code = "enum " ~ type ~ " {";

    // this is a static foreach (compile time)
    foreach(m; T){
      debug pragma(msg, m ~ ","); // check what code we get at compile time
      code ~= m ~ ",";
    }

    return(code ~ "}");
}

int main(){
    A switch_var_a;
    final switch(switch_var_a){
      case A.afoo:
      case A.bfoo:
      case A.cfoo:
    }

    string user_input = readln();

    mixin(generateEnums!members1("B"));
    B switch_var_b = chomp(user_input).to!B; // get rid of terminating chars

    final switch (switch_var_b) {
      case B.afoo:
      {
        writeln("a");
        break;
      }
      case B.bfoo: // if commeted will cause a compiler error
      {
        writeln("b");
        break;
      }
      case B.cfoo: {writeln("c");}
    }

    return(0);
}

<== END

How about being able to write something like "ensure_final_switch B;" 
and have this call a CTF that generates the necessary code and has 
access to tool for building D structured code, AST etc.? And has a 
compile-time state I can later access in a upcoming CTF.


-- 
Robert M. Münch
http://www.saphirion.com
smarter | better | faster
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20160202/f39cac4d/attachment.html>


More information about the Digitalmars-d mailing list