GithubHelp home page GithubHelp logo

d-templates-tutorial's Introduction

D Template Tutorial

What's it's about

This project is about a wonderful part of the D programming language: templates. It contains a markdown document on templates aiming to be a kind of tutorial.

It's divided in 6 chapters:

  • Introduction is just, well, the introduction text, explaining the goal of this document and the formatting conventions used.
  • Basics is about templates syntax, basic building blocks (static if, eponymous trick) and function, struct and class templates.
  • Some More Advanced Considerations is about more advanced ideas, like constraints, tuples or operator overloading.
  • Around Templates deals with other metaprogramming constructs interacting with templates: traits, compile-time function evaluation (CTFE) and string mixins.
  • Examples presents some more detailed examples of what can be done with D templates.
  • The Appendix gives some explanation on the is expression and links on other templates resources.

If you find any inexactitude, plain error or missing subject, don't hesitate to open an issue on github!

Other formats

The markdown syntax used for the doc is the extended version used by Pandoc (mainly for tables or code sections). Using markdown files and Pandoc, I generate the HTML, pdf and epub versions. Feel free to comment on them also.

Utils

The utils folder contains a small D script to extract the hundreds of modules present in the text and test their compilation. You can also find there the extracted and tested modules.

d-templates-tutorial's People

Contributors

andrejmitrovic avatar geneticgrabbag avatar insideoutclub avatar ntrel avatar philippesigaud avatar sigod avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

d-templates-tutorial's Issues

Example on page 13 not working

The second example on page 13 doesn't work.

template NameOf (alias name)
{
    enum string NameOf = name.stringof;
}

int foo (int i) { return i + 1; }

auto s1 = NameOf!(foo); // this will fail
auto s2 = NameOf!(NameOf);

Compiling the code will result in an error similar to this:

test.d(8): Error: function test.foo (int i) is not callable using argument types ()
test.d(8): Error: expected 1 function arguments, not 0
test.d(15): Error: template instance test.NameOf!(foo) error instantiating

The reason is because the compiler thinks you're trying to call "foo". D allows to call a function taking no arguments without parentheses, that's how properties are implemented.

is() now works for tuples

You might want to update Page 177 where you define the isTuple template.

import std.typecons;

template isTuple(T)
{
    static if (is(T tup == Tuple!(InnerTypes), InnerTypes...))  // now works (2.060+ methinks)
        enum isTuple = true;
    else
        enum isTuple = false;
}

void test(T)(T t)
    if (isTuple!T)
{
}

void main()
{
    auto tup = tuple(1, 2);
    test(tup);
}

Typo for auto ref

Somewhere around line 679-681 in templates_basics.tex (my editor and git show different lines), is this line:

\aparte{\D{auto ref}}{ A function template can have an \D{auto ref} return type. That means that for templates where the returned values are rvalues, the template will get the \D{ref}ed version. And the non-\D{ref} version if not.}

I think this line should be: "That means that for templates where the returned values are lvalues"

Mapping variadic template arguments in D

Based on this SO question: http://stackoverflow.com/questions/12888263/mapping-variadic-template-arguments-in-d

import std.stdio;
import std.string;
import std.traits;
import std.typetuple;

mixin template Delay(alias Call, alias Arg)
{
    ReturnType!Call Delay() { return Call(Arg); };
}

@property string getMapperMixin(size_t count)()
{
    string result;
    string[] mixinDecls;
    string[] tupleList;

    foreach (idx; 0 .. count)
    {
        mixinDecls ~= xformat("mixin .Delay!(Call, Args[%s]) Del%s;", idx, idx);
        tupleList ~= xformat("Del%s.Delay", idx);
    }

    string tupleStr = "alias TypeTuple!(";
    tupleStr ~= tupleList.join(",");
    tupleStr ~= ") Map;";

    string mixinStr = mixinDecls.join("\n");
    result = mixinStr ~ "\n" ~ tupleStr;

    return result;
}

template Map(alias Call, Args...) 
{
    /** 
        Expands to (when length is 2):

        mixin .Delay!(Call, Args[0]) Del1;
        mixin .Delay!(Call, Args[1]) Del2;

        alias TypeTuple!(
            Del1.Delay,
            Del2.Delay
        ) Map;
    */
    mixin(getMapperMixin!(Args.length));
}

int functor(int arg)
{
    return arg * 10;
}

void initCall(Args...)(Args args)
{
    writeln( Map!(functor, args) );
}

void main()
{
    int x = 1;
    int y = 2;
    initCall(x, y);
}

I would ordinarly just use a recursive template instead of combining a string mixin with mixin templates, but this bug stopped me: http://d.puremagic.com/issues/show_bug.cgi?id=8833

Anyway I think it's interesting enough to consider including it in the book. (or maybe not, but maybe it's interesting to you?).

Another template example

Here's another template sample if you'd like to include it, it's similar to that Recorder example but this one fires a delegate when a change happens to a field:

/*
 *           Copyright Andrej Mitrovic 2011.
 *  Distributed under the Boost Software License, Version 1.0.
 * 
 * Info: Invokes a custom delegate when a Notify!Type field has changed.
 */
module test;
import std.stdio;

template Fields(T, string field1, string field2)
{
    alias typeof(this) This;

    mixin("T " ~ field1 ~ ";");
    mixin("T " ~ field2 ~ ";");

    This opBinary(string op)(This rhs)
    {
        This res;
        mixin("res." ~ field1 ~ " = this." ~ field1 ~ op ~ " rhs." ~ field1 ~ ";");
        mixin("res." ~ field2 ~ " = this." ~ field2 ~ op ~ " rhs." ~ field2 ~ ";");
        return res;
    }

    void opOpAssign(string op)(This rhs)
    {
        mixin("this = this " ~ op ~ " rhs;");
    }                
}

struct Point {
    mixin Fields!(int, "x", "y");
}

struct Size {
    mixin Fields!(int, "width", "height");
}

class Widget 
{
    this()
    {
        point.init((Point pt) { writefln("changed point to %s", pt); });
        size.init((Size sz)   { writefln("changed size to %s", sz); });
    }

    Notify!Point point;
    Notify!Size size;
}

struct Notify(T)
{
    T payload;
    alias void delegate(T) OnEventFunc;
    OnEventFunc onEvent;

    void init(OnEventFunc func) {
        onEvent = func;
    }

    static if (is(T.toString)) {
        alias T.toString toString;
    }

    auto opEquals(T)(T rhs)
    {
        return rhs == rhs;
    }

    auto opBinaryRight(string op, T)(T rhs)
    {
        mixin("return rhs " ~ op ~ " payload;");
    }

    auto opBinary(string op, T)(T rhs)
    {
        mixin("return payload " ~ op ~ " rhs;");
    }

    void opAssign(T)(T rhs)
    {
        auto temp = payload;
        payload = rhs;

        if (temp != payload)
            onEvent(payload);
    }

    void opOpAssign(string op, T)(T rhs)
    {
        auto temp = payload;
        mixin("payload " ~ op ~ "= rhs;");

        if (temp != payload)
            onEvent(payload);
    }
}

void main()
{
    auto widget = new Widget;
    widget.point = Point(1, 10);  // changed point, delegate invoked
    assert(widget.point == Point(1, 10));

    widget.size += Size(1, 10);   // changed size, delegate invoked
    assert(widget.size == Size(1, 10));

    widget.point += Point(0, 0);  // no change, delegate not invoked
    widget.size  += Size(0, 0);   // no change, delegate not invoked
    assert(widget.point == Point(1, 10));
    assert(widget.size  == Size(1, 10));
}

If there was a way to use static foreach then Fields could be improved to take any number of arguments. Another trick might be to use __traits(allMembers, Type); to extract fields and assign each field of a type this way.

Confusing names with template mixins

Zachary Lund:

On page 78 where template mixins are discussed, some of the variable names feel rather confusing. I would suggest changing them to be more distinct.

Update the alias syntax

The text should be updated to use the new alias New = Old; syntax, instead of alias Old New;.

Update the text

This tutorial was written in 2011 & 2012. It's now 2014, many things happened in D meanwhile, that affected templates:

  • eponymous templates can have private members
  • the new () => value syntax for anonymous template functions.
  • templates have automatic attribute deduction
  • some things that were not possible 2 years ago are now OK.

Andrei's comments

"They are used everywhere in Phobos, D standard library and any D user should know about them." -> "They are used everywhere in Phobos---D's standard library---and therefore any D user should know about them."

"But, based on C++’s templates as they are, they can be a bit daunting at first." -> "But, based on C++’s templates as they are, D templates can be a bit daunting at first."

"Well, D’s sane syntax for templates, nifty things like static if, alias or tuples cured me of that impression." -> "Well, D’s sane syntax for templates and nifty features such as static if, alias, or tuples, cured me of that impression." (Generally prefer "such as" to "like".)

"I hope this docu- ment will help you also." -> "I hope this docu- ment will help you, too."

"Part III presents other metaprogramming tools: string mixins (18), compile- time function evaluation (19) and __traits (20)." -> "Part III presents other metaprogramming tools: string mixins (18), compile- time function evaluation (19), and __traits (20)." (Use the "Oxford comma" throughout.)

"template-y" -> "\mbox{template-y}"

"...in the next sections (You’ll see for example..." -> "...in the next sections (you’ll see for example..."

"... except inside a (standard) function." -> "except inside a (regular) function."

"Up to now, templates must seem not that interesting to you..." -> "Up to now, templates may not seem all that interesting..."

"It’s both an expression and a declaration, so I’ll call it a construct." -> "It’s both a statement and a declaration, so I’ll call it a construct." In fact you can call it a declaration because some declarations may occur wherever a statement is allowed.

static if ... static assert pattern

I noticed that the following pattern appears regularly (example 22.1.4):

static if (someCondition)
    static assert(0, "message");

When the code could be written simply as

static assert(someCondition, "message");

If this is a deliberate style decision, you might consider making a note of it somewhere and informing the reader that static assert takes an expression just like its runtime cousin.

Static If allows to choose between *many* different code paths.

( this was totally here the entire time. )

static if(one) blah; 
else static if(two) blah2; 
else static if(three) blah3; 

Page 20, line under 2.3.3 and Syntax (In the PDF version.)
Line 351, in the tex.

It's a little bit pedantic, but this is a tutorial.

I'd say simply changing that the word 'two' to 'different'.

I'll create a pull request if someone'll give me the go ahead.

Publish a website

Salut Philippe,

I don't know if you know about GitHub's gh-pages branch. You just push a static website there and it will be browsable at ‹user›.github.io/‹repo›.

Since your tutorial is generated using pandoc, I think you should consider pushing to a branch called gh-pages!

Add another example

Just posted this to the newsgroups and thought it would be worth including in the book as an example:

import std.algorithm;
import std.conv;
import std.string;
import std.stdio;
import std.range;

struct Foo
{
    int one = 1;
    @property int test() { return 1; }
    int three = 3;
    string[string] aa;
    string toString() { return prettyFieldsString(this); }
}

string prettyFieldsString(T)(T t)
    if (is(T == struct) || is(T == class))
{
    Appender!string result;
    Appender!(string[]) fields;
    Appender!(string[]) values;

    foreach (member; __traits(allMembers, T))
    {
        mixin("
        static if (!is( FunctionTypeOf!(t." ~ member ~ ") ))
        {        
            static if (member != " ~ `"toString"` ~ ")
            {
                fields.put(member);
                values.put(to!string(__traits(getMember, t, " ~ `"` ~ member ~ `"` ~ ")));
            }
        }
        ");
    }

    size_t spaceLen = 1;
    foreach (field; fields.data)
        spaceLen = max(spaceLen, field.length);

    alias std.array.replicate replicate;
    string spaceString = replicate(" ", spaceLen);

    foreach (field, value; lockstep(fields.data, values.data))
        result.put(format("%s: %s%s\n", field, replicate(" ", spaceLen - field.length), value));

    return result.data;
}

void main()
{
    Foo foo;
    foo.aa["foo"] = "bar";
    writeln(foo);
}

Sample output: http://paste.pocoo.org/show/558492/

Maybe this has more to do with static introspection than templates, but I thought I'd be nice for the book.

Explanatory boxes should be floats, sidebars or mboxes{}

From Andrei:

It would be great to make the explanatory boxes either floats, sidebars, or \mbox{}es so they don't span more than one page. Look
what happened with "Specializations or static if or Templates Constraints?" on page 21.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.