Skip to content

Conversation

timotheecour
Copy link
Contributor

defines new std.traits templates:

  • isSame
  • isSameTypleTuple
  • GetTemplateParent
  • GetTemplateArguments
  • isTemplateInstantiation

These are useful generic traits that can be used

related discussions:

http://forum.dlang.org/post/mailman.1382.1371938670.13711.digitalmars-d@puremagic.com
http://d.puremagic.com/issues/show_bug.cgi?id=4265
In particular, GetTemplateParent, GetTemplateArguments avoid requiring templates to define internal aliases for type parameters, as is currently done in d modules (and always done in C++ templates). GetTemplateParent/GetTemplateArguments removes the need to introduce new compiler __traits.

These traits are also essential in a subsequent pull request I will make to fix std.traits.fullyQualifiedName + friends to work on templated types (currently fullyQualifiedName + friends fail on those)

'isSame' works with pretty much everything I've tried. It wraps around __traits(isSame, a==b) , is(a==b), a==b as required.

Caveats:

  • currently I have no way to get this to work with function templates (only struct/class templates). Help welcome.
  • isSameTypleTuple may be better placed in std.typetuple.
  • Is there a way to avoid requiring the 1st size_t N argument while giving the same functionality?

struct A{}
}
struct A4(alias fun,T...){}
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is a good moment to gather all dummy types used by std.traits unit tests in one block and use unified naming for them, for maintenance reasons.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will fix

@mihails-strasuns
Copy link

It is welcome addition (have totally forgot about templates when writing fullyQualifiedName for types >_<), but utility templates need to be much better defined and have strict constraints. By the way, while you are still on this, do you have any ideas about http://d.puremagic.com/issues/show_bug.cgi?id=10190 ? I still can't think any good workaround that does not involve patching DMD.

Regarding functions, it is complicated because for aggregates symbol is also the type at the same time. Amd for functions plain symbol is not a type but parens-less call. I have no idea how to get function type without loosing function symbol (FunctionTypeOf will return type with all "T"'s instantiated).

@timotheecour
Copy link
Contributor Author

utility templates need to be much better defined and have strict constraints.

I'm arguing there's a good use case for isSame / isSameTypeTuple to work on 'everything', as i did. For restricted cases, ppl can use __traits(isSame), is(a==b), a==b depending on conditions.

can you think of a way to get rid of the "N" parameters in isSameTypeTuple ? If so i can even fold isSameTypeTuple into isSame.

do you have any ideas about http://d.puremagic.com/issues/show_bug.cgi?id=10190

Yes, i have a fix for 10190 (i had submitted that bug actually:) ). Will make pull request after this is accepted. It depends on functionality in this pull.

Regarding functions, it is complicated because for aggregates symbol is also the type at the same time

also have a fix for functions. But not templated functions yet !
my 2nd pull will fix fullyqualifiedname for both functions and non-function templates

@mihails-strasuns
Copy link

By the way, you commits don't seem to have a commit message. Will return to this later in the evening.

@timotheecour
Copy link
Contributor Author

can i amend commit messages from github?

also, just found out that there exists a private template std.typetuple.isSame that seems to be equivalent to my proposed std.traits.isSame. So that proves that it was useful indeed!
but I guess it belongs more here than in std.typetuple, whereas my isSameTypleTuple would probably be best in std.typetuple than std.traits. In any case, it should'nt be private. I'll have to double check functionality is the same indeed.

EDIT: added AliasTuple and removed isSameTypleTuple, which isn't necessary anymore.

@Dav1dde
Copy link
Contributor

Dav1dde commented Jun 24, 2013

git rebase -i HEAD~5

Change the pick in the beginning of a line to "r", then you can edit the commit messages and also squash them together into one big commit.

~5 Tells git to go 5 commits back in History and list only these 5, you can increase/decrease the number accordingly.

…TypeTuple since tuples can now be compared after wrapping through AliasTuple
@timotheecour
Copy link
Contributor Author

made some improvements:
grouped version(unittest) dummy structs
added AliasTuple (more general than TypeTuple)
removed isSameTypeTuple since TypeTuples can now be compared after wrapping into AliasTuple

@ghost
Copy link

ghost commented Jun 25, 2013

There's a lot that needs fixing here, I'll review shortly.

---
+/
template AliasTuple(T...){
alias AliasTuple=AliasTupleImpl!T;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AliasTuple looks a limited version of std.typetuple.Pack.

@ghost
Copy link

ghost commented Jun 25, 2013

  • Please follow the D style guide. Among other things this means braces on their own line, expressions separated by spaces, parameters separated by spaces, and consistent 4-space indentation (no tabs, and no mixing of tabs and spaces).
  • Using a single private block for structs like A1, A2, will make code examples confusing to users
    because they will have no idea what these symbols are when they look at the example code. Code examples should also be copy-pastable and compilable, so they need to be part of documented unittests and the example structs should be put inside the unittest blocks.

The one exception is the test for GetTemplateSymbol, where S4 can't be put inline because this triggers a compiler bug (Error: template instance _S4!(__lambda14, int) cannot use local '__lambda14(__T13)(a)' as parameter to non-global template _S4(alias fun, T...)).

  • Use /// ditto to join multiple symbols under the same documentation section.
  • Use XREF to link to another symbol in another module, and use $(D ParamName) to syntax-highlight the parameters in the documentation.
  • Use /// to enable documented unittests which will inject example code to the documentation of the previous declaration.
  • isTemplateInstance is shorter than isTemplateInstantiation, and it also avoids the problematic "instantiation <> instanciation" spelling for non-English users. I've seen plenty of people use both forms, so it's better to use something that's easier to type.
  • I think GetTemplateSymbol is a better name than GetTemplateParent, because Parent is usually a term that's related with scoping. For example a nested declaration has a parent, the symbol it's nested in.

Here's what the updated pull looks like with these changes:

struct AliasTupleTuple(U...) { }

/**
 * AliasTuple is a more general version of $(XREF typetuple, TypeTuple).
 * AliasTuple instances can be compared against one another in $(D is) expressions.
 */
template AliasTuple(T...)
{
    alias AliasTuple = AliasTupleTuple!T;
}

///
unittest
{
    import std.typetuple : Alias;
    alias fun = Alias!(a => a);
    alias fun2 = fun;
    int b;
    alias b1 = b;
    auto b2 = b;

    static assert(is(AliasTuple!(double, "a", b, fun) == AliasTuple!(double, "a", b1, fun2)));
    static assert(!is(AliasTuple!(double, "a", b, fun) == AliasTuple!(double, "a", b2, fun2)));
}

/**
 * Tests whether $(D S) is an aliasable symbol.
 */
template isAliasable(alias S)
{
    enum isAliasable = true;
}

/// ditto
template isAliasable(T)
{
    enum isAliasable = false;
}

///
unittest
{
    struct A1(T) { }
    struct A2 { }
    template A3(T)
    {
        struct A { }
    }
    struct A4(alias fun, T...) { }

    static assert(!isAliasable!(double));
    static assert(isAliasable!("foo"));
    static assert(isAliasable!(A1));
    static assert(isAliasable!(A1!double));
    static assert(isAliasable!(A2));
    static assert(isAliasable!(a=>a));
    enum b = 1;
    static assert(isAliasable!b);
}

private template isComparableAtCompileTime(alias T1, alias T2)
{
    static assert(T1 == T2);
}

/**
 * Tests for equality between 2 symbols (types/templates/values etc).
 */
template isSame(S...) if (S.length == 2)
{
    static if (__traits(compiles, isComparableAtCompileTime!(S[0], S[1])))
    {
        enum isSame = S[0] == S[1];
    }
    else static if (isAliasable!(S[0]) && isAliasable!(S[1]))
    {
        enum isSame = __traits(isSame, S[0], S[1]);
    }
    else static if (__traits(compiles, is(S[0] == S[1])))
    {
        enum isSame = is(S[0] == S[1]);
    }
    else
    enum isSame = false; // eg: "foo" , int
}

///
unittest
{
    struct A1(T) { }
    struct A2 { }
    template A3(T)
    {
        struct A { }
    }
    struct A4(alias fun, T...) { }

    static assert(isSame!(double, double));
    static assert(isSame!(A1, A1));
    static assert(isSame!(A1!int, A1!int));
    static assert(!isSame!(A1!int, A1!float));
    static assert(isSame!("foo", "foo"));
    static assert(!isSame!("foo", "bar"));
    static assert(!isSame!(a => a, a => a));
    auto fun = (int a) => a;
    static assert(isSame!(fun, fun));
    static assert(!isSame!("foo", int));
}

/**
 * Retrieves template symbol from a template instance.
 * $(RED Note:) Does not yet work with template function instances.
 */
template GetTemplateSymbol(T : TI!TP, alias TI, TP...)
{
    alias GetTemplateSymbol = TI;
}

/// ditto
template GetTemplateSymbol(alias T : TI!TP, alias TI, TP...)
{
    // TODO: how come this doesn't work with functions?
    alias GetTemplateSymbol = TI;
}

///
unittest
{
    struct A1(T) { }
    template A3(T)
    {
        struct A { }
    }
    // struct _S4(alias fun, T...) { }  // note: compiler bug with local instances

    static assert(isSame!(GetTemplateSymbol!(A1!double), A1));
    static assert(isSame!(GetTemplateSymbol!(_S4!(a => a, int)), _S4));
    static assert(isSame!(GetTemplateSymbol!(A3!(int)), A3));
}

///
version(unittest)
{
    struct _S4(alias fun, T...) { }
}

/**
 * Retrieves template arguments from a template instantiation.
 * $(RED Note:) Does not yet work with template function instances.
 */
template GetTemplateArguments(T : TI!TP, alias TI, TP...)
{
    alias GetTemplateArguments = TP;
}

/// ditto
template GetTemplateArguments(alias T : TI!TP, alias TI, TP...)
{
    // TODO: how come this doesn't work with functions?
    alias GetTemplateArguments = TP;
}

///
unittest
{
    struct A1(T) { }
    struct A4(alias fun, T...) { }

    import std.typetuple;
    static assert(is(AliasTuple!double == AliasTuple!(GetTemplateArguments!(A1!double))));
    static assert(is(AliasTuple!("foo", int) == AliasTuple!(GetTemplateArguments!(A4!("foo", int)))));
}

/**
 * Checks whether $(D S) is a template instance.
 */
template isTemplateInstance(S...) if (S.length == 1)
{
    enum isTemplateInstance = is(typeof(GetTemplateSymbol!S));
}

///
unittest
{
    struct A1(T) { }
    struct A2 { }
    template A3(T)
    {
        struct A { }
    }

    static assert(isTemplateInstance!(A1!double));
    static assert(!isTemplateInstance!(A1));
    static assert(!isTemplateInstance!(A2));
    static assert(!isTemplateInstance!(A3));
    static assert(isTemplateInstance!(A3!double));
    static assert(!isTemplateInstance!(A3!double.A));
    static assert(!isTemplateInstance!(int));
}

@mihails-strasuns
Copy link

I'm arguing there's a good use case for isSame / isSameTypeTuple to work on 'everything', as i did. For restricted > cases, ppl can use __traits(isSame), is(a==b), a==b depending on conditions.

I am speaking about documentation mostly here. If some generic utility gets into standard library, it needs to be perfectly clear what it should be used for and what not, in other words, it shouldn't rely on implementation-defined semantics. Especially when behaviour is as vague as here.

@ghost
Copy link

ghost commented Feb 14, 2014

There's now TemplateOf, TemplateArgsOf in git-head. If you plan on working on the other stuff it's probably best to open a new pull. The last review wasn't responded to.

@ghost ghost closed this Feb 14, 2014
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants