New set class

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Mon Feb 26 02:45:53 PST 2007


Michiel wrote:
> Bill Baxter wrote:
> 
[snip suggestion about counters in set-foreach]
> I feel that if I added that syntax, it would imply that the counter has
> some sort of relevance to the set, which it really doesn't.
> 
> A counter that increments by one each iteration has real meaning for an
> array. So does a key-type for an associative array. But for a set...
> sorry, I'd just feel dirty adding it.

I agree with you here, sets don't have indexes for their elements, they 
are unordered.

>> But if you really want to do put such things in your code you could try
>> this:
>> struct Set(T) {
>>     ...
>>     void opApplyReverse()() {static assert(0,"don't be silly");}
>> }
>>
>> Since foo is a template member, no attempt is made to compile it unless
>> it's actually called from somewhere.  If you do try to call it then you
>> trip the static assert at compile-time.
> 
> No, if you use a static assert, the compilation will fail as soon as you
> instantiate the class somewhere. Not if you try to use foreach_reverse.
> If it weren't a template class, the compiler would throw the error in
> any case.

The _member_ is _also_ a template here (with 0 parameters, but a 
template nonetheless). So compilation will only fail if that template is 
instantiated, which will happen only if foreach_reverse is used (or it's 
explicitly called, of course).

Here, let me show you (some modifications made to above code)
---
urxae at urxae:~/tmp$ cat test.d
import std.stdio;

struct Set(T) {
     void opApplyReverse()(int delegate(inout T)) { static 
assert(0,"don't be silly");}
}

void main()
{
     Set!(int) x;
     version(ForeachReverse)
         foreach_reverse(int e; x) {}
}
urxae at urxae:~/tmp$ dmd test.d && ./test
gcc test.o -o test -m32 -lphobos -lpthread -lm -Xlinker 
-L/home/urxae/opt/dmd/lib
urxae at urxae:~/tmp$ # Note: no error above
urxae at urxae:~/tmp$ dmd -version=ForeachReverse test.d
test.d(4): static assert  (0) is false, "don't be silly"
---

The static assert is only triggered with -version=ForeachReverse.

> You're right that a compiler error would be preferable to a runtime
> error, but simply leaving the function out doesn't give as clear an
> error message ("Error: cannot infer type for e"). It would be ideal if I
> could have both.

No, "cannot infer type for e" is indeed a bit unclear, it doesn't 
explain *why* it happened.

> But well, I don't understand why unittests are done at runtime either.

Yeah, there's been some discussion about that. A lot of people would 
like them to be ran after compiling & linking, but so far no change has 
been made to allow this to be done.

>>>> Finally
>>>>    Set!(T[0]) set(T...)(T elements)
>>>> why not just
>>>>    Set!(T) set(T)(T elements...) ??
>>> You only use that syntax if T is an aggregate type. So the resulting set
>>> would actually be Set!(T[0]) anyway. I think I tried this before and had
>>> some problems, but I'm not certain now.
>> I don't follow what you mean about "aggregate type".  The unittest uses
>> int as the type.  I don't think 'int' is considered an aggregate.
> 
> Well, That's what the 'void func(T name...)' syntax is for. If T is an
> aggregate type (array, class, struct, etc.) you can either supply that
> type to the func, or all of its members separated by comma's.
> 
> I suspect that you meant this one: 'void func(T name, ...)', which is
> something different. I haven't tried it, and I will.

I suspect he may have meant the "void func(T)(T[] name...)" syntax (or 
in this case, "Set!(T) set(T)(T[] elements...)"). That would let the 
user pass as many arguments as he wants, while presenting them as a nice 
typesafe array to the library.
By the way, "void func(int name...)" is also perfectly valid syntax but 
only allows one argument to be specified.
This is all explained in the section "Typesafe Variadic Functions" of 
http://www.digitalmars.com/d/function.html.



More information about the Digitalmars-d mailing list