www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - playing around with D

reply Carsten Scharfenberg <cathune_public web.de> writes:
Hello,

I just downloaded D and now I'm playing around a bit. My oppinion about D is
more or the same as every body else's: D is great - but why does this or that
feature not work that am I used to from C++... I think that this is just normal
for a new langue :-).
Anyway I have a couple of questions that arose when I had a look into std.bind.
I'm using  dmd v1.007 and gdc v0.22 on Linux.


1.

the following behaviour I do not understand:


struct TupleContainer( T... )
{
    alias T tuple;

    template append( X )
    {
        alias TupleContainer!( T, X )   append;
    }
}

template UseAppend( /* alias */ TC )
{
    alias TC.append!( int )   UseAppend;
}


void main()
{
    writefln( typeid( TupleContainer!().append!( int ) ) ); // Ok
    writefln( typeid( UseAppend!( TupleContainer!() ) ) );  // Error
}



Error Message:
test.d(xxx): Error: template identifier append is not a member of TC
test.d(xxx): template instance test.UseAppend!(TupleContainer!() ) error
instantiating

If I uncomment the alias befor TC everything works fine - why?
As TC is of type TupleContainer!() which has the member "append" (more
precisely: the named template "append" - I'm not sure if this acounts as a
member) I would presume this should work without the alias.



2.

The second point seems to be a compiler bug - but correct me if I'm wrong:



template isTupleContainer( T )
{
    static if( is( typeof( T.tuple ) ) )
    {
        static if( is( T == TupleContainer!( T.tuple ) ) )
            static const bool isTupleContainer = true;
        else
            static const bool isTupleContainer = false;
    }
    else
        static const bool isTupleContainer = false;
}

template DoSomething( T )
{
    alias T.tuple  OrigTuple;
    
    alias int Result;
}

template AssertTest( T )
{
    static assert( isTupleContainer!( T ) );
    
    alias DoSomething!( T ).Result    AssertTest;
/*      alias int AssertTest;*/
}

void main()
{
    /*
     * this is perfectly fine and prints false
     */
    writefln( typeid( isTupleContainer!( int ) ) );
    
    /*
     * this should trigger the assert in AssertTest - but it doesn't,
     * a compiler error is emitted instead.
     */
    writefln( typeid( AssertTest!( int ) ) );
}


Error Message:
test.d(xxx): Error: no property 'tuple' for type 'int'
test.d(xxx): Error: T.tuple is used as a type
test.d(xxx): template instance test.DoSomething!(int) error instantiating


isTupleContainer checks, of course, if T is a TupleContainer. This works fine in
the main function - but in AssertTest its result seems always to be true
so that the assert is never triggered.
The assert is triggered in the correct way, if I (1) swap comments for both
assert lines in AssertTest, or (2) outcomment the first alias line in
DoSomething! This is very strange...



3.

Regarding the prevois isTupleContainer template it would be nice to have
a more general possiblity to check if a type is an arbitary instantiation of a
given template. It's easy to check for a special instantiation:



struct Type( T )
{
    ...
}

template CheckType( T )
{
    static if( is( T == Type( int ) ) )
        static const int CheckType = true;
    else
        static const int CheckType = false;
}


it is also possible to do the following:


template isInstantiation( T1, alias T2 )
{
    static if( is( T1 t == T2( t ) ) )
        static const int isInstantiation = true;
    else
        static const int isInstantiation = false;
}


this checks for an arbitary instantiation of an arbitary template - but only if
T2 has exactly one template parameter. I'm looking for a possiblity to do this
check for an arbitary number of template parameters.



4.

By the way: what is the difference between
static const int        and         const int ?
Both variants work in the examples above.

Regards,
Carsten Scharfenberg
Mar 05 2007
parent reply Walter Bright <newshound digitalmars.com> writes:
Carsten Scharfenberg wrote:
 I just downloaded D and now I'm playing around a bit. My oppinion about D is
more or the same as every body else's: D is great - but why does this or that
feature not work that am I used to from C++... I think that this is just normal
for a new langue :-).
 Anyway I have a couple of questions that arose when I had a look into
std.bind. I'm using  dmd v1.007 and gdc v0.22 on Linux.
 1.

This is a compiler bug, I'll fix it.
 2.
 
 The second point seems to be a compiler bug - but correct me if I'm wrong:
 
 template isTupleContainer( T )
 {
     static if( is( typeof( T.tuple ) ) )
     {
         static if( is( T == TupleContainer!( T.tuple ) ) )
             static const bool isTupleContainer = true;
         else
             static const bool isTupleContainer = false;
     }
     else
         static const bool isTupleContainer = false;
 }
 
 template DoSomething( T )
 {
     alias T.tuple  OrigTuple;
     
     alias int Result;
 }
 
 template AssertTest( T )
 {
     static assert( isTupleContainer!( T ) );
     
     alias DoSomething!( T ).Result    AssertTest;
 /*      alias int AssertTest;*/
 }
 
 void main()
 {
     /*
      * this is perfectly fine and prints false
      */
     writefln( typeid( isTupleContainer!( int ) ) );

Should be: writefln( isTupleContainer!(int) );
     
     /*
      * this should trigger the assert in AssertTest - but it doesn't,
      * a compiler error is emitted instead.
      */
     writefln( typeid( AssertTest!( int ) ) );
 }
 
 
 Error Message:
 test.d(xxx): Error: no property 'tuple' for type 'int'
 test.d(xxx): Error: T.tuple is used as a type
 test.d(xxx): template instance test.DoSomething!(int) error instantiating
 
 
 isTupleContainer checks, of course, if T is a TupleContainer. This works fine
in
 the main function - but in AssertTest its result seems always to be true
 so that the assert is never triggered.

The problem is you are expecting that the static assert is checked before the alias in AssertTest. Multiple semantic passes are done over the declarations, and static assert's aren't checked until later. To ensure an order, use static if, such as: template AssertTest( T ) { static if( isTupleContainer!( T ) ) alias DoSomething!( T ).Result AssertTest; else static assert(0); }
Mar 05 2007
next sibling parent Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 Carsten Scharfenberg wrote:

 isTupleContainer checks, of course, if T is a TupleContainer. This 
 works fine in
 the main function - but in AssertTest its result seems always to be true
 so that the assert is never triggered.

The problem is you are expecting that the static assert is checked before the alias in AssertTest. Multiple semantic passes are done over the declarations, and static assert's aren't checked until later. To ensure an order, use static if, such as: template AssertTest( T ) { static if( isTupleContainer!( T ) ) alias DoSomething!( T ).Result AssertTest; else static assert(0); }

This is becoming a genuine Frequently Asked Question (I think it's been asked twice in the past week). Probably the spec should include some explanation in the 'static assert' section -- eg Note that multiple semantic passes are done over the declarations, and static assert's are not checked until the template has already been partially evaluated. To ensure an order, use static if. --> plus an example.
Mar 05 2007
prev sibling parent reply BCS <ao pathlink.com> writes:
Reply to Walter,

 The problem is you are expecting that the static assert is checked
 before the alias in AssertTest. Multiple semantic passes are done over
 the declarations, and static assert's aren't checked until later. To
 ensure an order, use static if, such as:
 
 template AssertTest( T )
 {
 static if( isTupleContainer!( T ) )
 alias DoSomething!( T ).Result    AssertTest;
 else
 static assert(0);
 }

Why do the static asserts get processed later? I'd expect that having them get processed sooner would make things work nicer.
Mar 06 2007
parent reply Walter Bright <newshound digitalmars.com> writes:
BCS wrote:
 Why do the static asserts get processed later?
 
 I'd expect that having them get processed sooner would make things work 
 nicer.

There's always that chicken-and-egg problem of forward references.
Mar 06 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to Walter,

 BCS wrote:
 
 Why do the static asserts get processed later?
 
 I'd expect that having them get processed sooner would make things
 work nicer.
 


Ah!! Wild thought: I know it's to late to do this for for DMD but, what would the problems be of doing a lazy evaluation of the AST? I'm thinking something like; process the declarations and statements in order (starting at the module level) and when you find a symbol you don't know about go looking for it.
Mar 06 2007
parent reply Pragma <ericanderton yahoo.removeme.com> writes:
BCS wrote:
 Reply to Walter,
 
 BCS wrote:

 Why do the static asserts get processed later?

 I'd expect that having them get processed sooner would make things
 work nicer.


Ah!! Wild thought: I know it's to late to do this for for DMD but, what would the problems be of doing a lazy evaluation of the AST? I'm thinking something like; process the declarations and statements in order (starting at the module level) and when you find a symbol you don't know about go looking for it.

Interesting idea. Maybe I'm just naive, but how would this be any different than just adding an additional semantic pass, while relaxing DMD's tendency to barf on unresolved symbols - or is that what you're proposing? -- - EricAnderton at yahoo
Mar 07 2007
parent BCS <BCS pathlink.com> writes:
Pragma wrote:
 BCS wrote:
 
 Reply to Walter,

 BCS wrote:

 Why do the static asserts get processed later?

 I'd expect that having them get processed sooner would make things
 work nicer.


Ah!! Wild thought: I know it's to late to do this for for DMD but, what would the problems be of doing a lazy evaluation of the AST? I'm thinking something like; process the declarations and statements in order (starting at the module level) and when you find a symbol you don't know about go looking for it.

Interesting idea. Maybe I'm just naive, but how would this be any different than just adding an additional semantic pass, while relaxing DMD's tendency to barf on unresolved symbols - or is that what you're proposing?

You can't do it in a constant number of passes because asserts can depend on templates that depend on asserts that depend on templates ...
Mar 07 2007
prev sibling parent reply Don Clugston <dac nospam.com.au> writes:
Walter Bright wrote:
 BCS wrote:
 Why do the static asserts get processed later?

 I'd expect that having them get processed sooner would make things 
 work nicer.

There's always that chicken-and-egg problem of forward references.

Given how common static assert(0) is, I wonder if something could be done to improve the error message quality in the "static assert(0, "xxx")" case? file.d(58): static assert (0) is false, "xxx" Maybe drop out the "(0) is false" bit, since it doesn't seem to add much value, changing it to something like: file.d(58): static assert, "xxx" Or even drop the 'static assert' bit entirely, and just display "xxx".
Mar 07 2007
next sibling parent Walter Bright <newshound digitalmars.com> writes:
Don Clugston wrote:
 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?
 
 file.d(58): static assert  (0) is false, "xxx"
 
 Maybe drop out the "(0) is false" bit, since it doesn't seem to add much 
 value, changing it to something like:
 
 file.d(58): static assert, "xxx"
 
 Or even drop the 'static assert' bit entirely, and just display "xxx".

good ideas
Mar 07 2007
prev sibling parent reply Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Don Clugston wrote:
 
 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?
 
 file.d(58): static assert  (0) is false, "xxx"
 
 Maybe drop out the "(0) is false" bit, since it doesn't seem to add much 
 value, changing it to something like:
 
 file.d(58): static assert, "xxx"
 
 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).
Mar 07 2007
parent reply Don Clugston <dac nospam.com.au> writes:
Frits van Bommel wrote:
 Don Clugston wrote:
 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?

 file.d(58): static assert  (0) is false, "xxx"

 Maybe drop out the "(0) is false" bit, since it doesn't seem to add 
 much value, changing it to something like:

 file.d(58): static assert, "xxx"

 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).

Why is it important to distinguish between an error that's detected in a library, compared to one that is detected by the compiler? I would think that a library writer would have the decency to explain in the text of the error, that the error occurred in the library. somefile.d(25): "SnazzySQL: Syntax error in SQL statement 'SELET * FROM CUSTOMERS'" (You could be correct, it's just not obvious to me).
Mar 07 2007
next sibling parent reply Bill Baxter <dnewsgroup billbaxter.com> writes:
Don Clugston wrote:
 Frits van Bommel wrote:
 Don Clugston wrote:
 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?

 file.d(58): static assert  (0) is false, "xxx"

 Maybe drop out the "(0) is false" bit, since it doesn't seem to add 
 much value, changing it to something like:

 file.d(58): static assert, "xxx"

 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).

Why is it important to distinguish between an error that's detected in a library, compared to one that is detected by the compiler? I would think that a library writer would have the decency to explain in the text of the error, that the error occurred in the library. somefile.d(25): "SnazzySQL: Syntax error in SQL statement 'SELET * FROM CUSTOMERS'" (You could be correct, it's just not obvious to me).

There may be other reasons, but often IDEs will take you to lines where errors were generated, sorting those that are errors ahead of lines that were warnings or informational or what have you. For that to work though, prefixes need to be consistent. An IDE won't know if "SnazzySQL" is an error a warning or what. So from my POV at least static asserts should be prefixed with *something* fixed, but I don't care so much if it's just "somefile.d(25): Error" or "somefile.d(25): static assert. If the latter then an IDE could have a rule that prioritizes static asserts over other errors. Don't know how useful that would be though. Seems common to only distinguish 3 categories -- Error (this won't compile), Warning (this might cause trouble at runtime), Information ("hey I'm going to link with phobos.lib, ok?") --bb
Mar 07 2007
parent Don Clugston <dac nospam.com.au> writes:
Bill Baxter wrote:
 Don Clugston wrote:
 Frits van Bommel wrote:
 Don Clugston wrote:
 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?

 file.d(58): static assert  (0) is false, "xxx"

 Maybe drop out the "(0) is false" bit, since it doesn't seem to add 
 much value, changing it to something like:

 file.d(58): static assert, "xxx"

 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).

Why is it important to distinguish between an error that's detected in a library, compared to one that is detected by the compiler? I would think that a library writer would have the decency to explain in the text of the error, that the error occurred in the library. somefile.d(25): "SnazzySQL: Syntax error in SQL statement 'SELET * FROM CUSTOMERS'" (You could be correct, it's just not obvious to me).

There may be other reasons, but often IDEs will take you to lines where errors were generated, sorting those that are errors ahead of lines that were warnings or informational or what have you. For that to work though, prefixes need to be consistent. An IDE won't know if "SnazzySQL" is an error a warning or what. So from my POV at least static asserts should be prefixed with *something* fixed, but I don't care so much if it's just "somefile.d(25): Error" or "somefile.d(25): static assert. If the latter then an IDE could have a rule that prioritizes static asserts over other errors. Don't know how useful that would be though. Seems common to only distinguish 3 categories -- Error (this won't compile), Warning (this might cause trouble at runtime), Information ("hey I'm going to link with phobos.lib, ok?")

Fair enough, but existing DMD error messages don't do that. file.d(729): found 'auto' when expecting ';' following 'statement' so it's a general issue. But since Walter doesn't like warnings, they're all errors anyway.
Mar 07 2007
prev sibling parent reply BCS <BCS pathlink.com> writes:
Don Clugston wrote:
 Frits van Bommel wrote:
 
 Don Clugston wrote:

 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?

 file.d(58): static assert  (0) is false, "xxx"

 Maybe drop out the "(0) is false" bit, since it doesn't seem to add 
 much value, changing it to something like:

 file.d(58): static assert, "xxx"

 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).

Why is it important to distinguish between an error that's detected in a library, compared to one that is detected by the compiler? I would think that a library writer would have the decency to explain in the text of the error, that the error occurred in the library. somefile.d(25): "SnazzySQL: Syntax error in SQL statement 'SELET * FROM CUSTOMERS'" (You could be correct, it's just not obvious to me).

1) Never trust convention or decency to make people do something that is *needed* 2) compile errors are usually the fault of the lib, asserts are the fault of the user. Also the asserts will probably be more useful when trying to fix things.
Mar 07 2007
parent Don Clugston <dac nospam.com.au> writes:
BCS wrote:
 Don Clugston wrote:
 Frits van Bommel wrote:

 Don Clugston wrote:

 Given how common static assert(0) is, I wonder if something could be 
 done to improve the error message quality in the
 "static assert(0, "xxx")" case?

 file.d(58): static assert  (0) is false, "xxx"

 Maybe drop out the "(0) is false" bit, since it doesn't seem to add 
 much value, changing it to something like:

 file.d(58): static assert, "xxx"

 Or even drop the 'static assert' bit entirely, and just display "xxx".

I don't think dropping the 'static assert' bit is a good idea (at least, without replacing it with something of similar meaning). I think it's a good thing that static asserts are clearly distinct from compiler-generated errors. The exact wording could be different but it should be clear that this is an error because the author of the code explicitly _made_ it one, not because of any inherent language rule (other than the one on static assert, obviously).

Why is it important to distinguish between an error that's detected in a library, compared to one that is detected by the compiler? I would think that a library writer would have the decency to explain in the text of the error, that the error occurred in the library. somefile.d(25): "SnazzySQL: Syntax error in SQL statement 'SELET * FROM CUSTOMERS'" (You could be correct, it's just not obvious to me).

1) Never trust convention or decency to make people do something that is *needed*

IMHO, it's not *needed*, just nice.
 2) compile errors are usually the fault of the lib, asserts are the 
 fault of the user. Also the asserts will probably be more useful when 
 trying to fix things.

I'm only talking about the specific case of static assert(0, "xxx"); -- giving the library writer an option to suppress the "static assert" message.
Mar 07 2007