Jump to page: 1 2 3
Thread overview
Am I getting this all right?
Dec 13, 2006
Jason House
Dec 14, 2006
Sean Kelly
Dec 14, 2006
Ary Manzana
Dec 14, 2006
Jason House
Dec 14, 2006
Sean Kelly
Dec 14, 2006
Jason House
Dec 14, 2006
Sean Kelly
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Sean Kelly
Iterators recap
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Sean Kelly
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Sean Kelly
Dec 15, 2006
Bill Baxter
Dec 15, 2006
Oskar Linde
Dec 28, 2006
Sean Kelly
Dec 14, 2006
Sean Kelly
Dec 14, 2006
Bill Baxter
December 13, 2006
I'm kind of doing a trial by fire method to learn D and how it works... I'm taking an existing open source project and converting it over.  Here's the stuff that I've found / questions that I have.

Thanks in advance for all the thoughtful responses.  I know this is a long post!  I've worked through the issues to get working code, but I think my issues will be hit by others.

It seems that DTL and minTL are the two candidates for an STL equivalent in D.
 Both seem to be out of date.  Since minTL is documented, I chose to use that.
 I found that the latest dmd (0.176) doesn't compile the latest minTL.  It
complains that va_arg isn't defined even though it imports std.stdarg.  Adding
a fully qualified name fixed my usage problem.  Is this really the best option
that I have for STL equivalent?  Anyone else compiling this stuff and hitting
problems?

I know of no way in d to provide a const qualifier.  It seems like the concept purely doesn't exist.  minTL appears to have a workaround where it templates itself on a boolean value, and simply doesn't publish certain functions.  When will a real const qualifier get added to the language?  It seems really strange that a language that adds all kinds of contract programming wouldn't use const qualifiers / const types.

After banging my head on printing stuff for a long time, I've come to a few
conclusions:
* The C++ equivalent to std::ostream& operator << (std::ostream &out, const
type &x) does not exist
* Custom types use the toString property
* Enums do not (and can not) have a toString property
* I have found no way to determine (in a templated class) if a type is
printable or not.  static if(is(typeof(T))) comes close, but my very first
test using ints failed.

The special unittest member function doesn't get built in with -unittest
unless the actual class is used in some way (and then one copy of the unittest
funciton gets run for each type).  I'd really like to see some way for this to
work.  for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does
not run unless other code instantiates foo!(U)

In my early efforts at doing operator overloading, I wrote opCmp and then was shocked when my unit test showed that == didn't even call opCmp.  It silently did something wrong.  This seems like a gotcha built into the language that should probably get remedied.

I couldn't find a way to reinitialize a variable back to a default value...
For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
compile.  I'm not too sure why this is the case.
December 14, 2006
Jason House wrote:
> I'm kind of doing a trial by fire method to learn D and how it works... I'm
> taking an existing open source project and converting it over.  Here's the
> stuff that I've found / questions that I have.
> 
> Thanks in advance for all the thoughtful responses.  I know this is a long
> post!  I've worked through the issues to get working code, but I think my
> issues will be hit by others.
> 
> It seems that DTL and minTL are the two candidates for an STL equivalent in D.
>  Both seem to be out of date.  Since minTL is documented, I chose to use that.
>  I found that the latest dmd (0.176) doesn't compile the latest minTL.  It
> complains that va_arg isn't defined even though it imports std.stdarg.  Adding
> a fully qualified name fixed my usage problem.  Is this really the best option
> that I have for STL equivalent?  Anyone else compiling this stuff and hitting
> problems?

Check DSource (www.dsource.org).  IIRC there is at least one STL replacement project there.  Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year.  MinTL was created by Ben Hinkle, and has been dormant for almost as long.  MinTL is more mature however, and should be easier to update.

> I know of no way in d to provide a const qualifier.  It seems like the concept
> purely doesn't exist.  minTL appears to have a workaround where it templates
> itself on a boolean value, and simply doesn't publish certain functions.  When
> will a real const qualifier get added to the language?  It seems really
> strange that a language that adds all kinds of contract programming wouldn't
> use const qualifiers / const types.

This is correct.  In D, 'const' is a storage class, and can not be applied to values at runtime (essentially).  D has no run-time const behavior largely because the implementations in expisting popular languages are undesirable (C++ const, for example) for various reasons, and some of the more radical solutions such as const-by-default came up too late in the language's development cycle (as I understand it).

> After banging my head on printing stuff for a long time, I've come to a few
> conclusions:
> * The C++ equivalent to std::ostream& operator << (std::ostream &out, const
> type &x) does not exist

It could.  Mango (available on DSource) overloaded these operators for a while, but no one used them and I think they may have been removed. Mango's "whisper syntax" seems preferable in most cases, though it doesn't work for an IOStream concept, while the shift operators do.

> * Custom types use the toString property

Yes, though some of us wish this function were called "toUtf8" to improve clarity.  This is an idealistic point however, and not pertinent to the discussion.

> * Enums do not (and can not) have a toString property

They don't at the moment.  One could be added, I imagine, but it would have to be done in the compiler.

> * I have found no way to determine (in a templated class) if a type is
> printable or not.  static if(is(typeof(T))) comes close, but my very first
> test using ints failed.

"static if(is(typeof(T.toString)))" should tell you whether the function is defined, if T is a struct or class, but it sounds like you want to test concrete types as well?

> The special unittest member function doesn't get built in with -unittest
> unless the actual class is used in some way (and then one copy of the unittest
> funciton gets run for each type).  I'd really like to see some way for this to
> work.  for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does
> not run unless other code instantiates foo!(U)

Why not do:

    class C(T) {}
    unittest { /* test C here */ }

Since private data is actually visible at module scope, the above approach loses nothing over having unittest within the class definition itself.

> In my early efforts at doing operator overloading, I wrote opCmp and then was
> shocked when my unit test showed that == didn't even call opCmp.  It silently
> did something wrong.  This seems like a gotcha built into the language that
> should probably get remedied.

It calls opEquals.  Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.

> I couldn't find a way to reinitialize a variable back to a default value...
> For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
> compile.  I'm not too sure why this is the case.

Try:

    T[] bar = new T[size];
    T[0 .. $] = new T();

You still have to resize and assign in separate operations, but the above should work.


Sean
December 14, 2006
Sean Kelly escribió:
> Jason House wrote:
>> I couldn't find a way to reinitialize a variable back to a default value...
>> For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
>> compile.  I'm not too sure why this is the case.
> 
> Try:
> 
>     T[] bar = new T[size];
>     T[0 .. $] = new T();

It worked for me, if T is a class. If it's a primitive type, you should do "T.init" instead of "new T()". So heres the code:

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
class foo(T) {
	
	T[] bar;
	
	void func(){
		static if (is(T == class)) {
			bar[3] = new T();
		// TODO: what if it's a struct, typedef, etc.?
		} else {
			bar[3] = T.init;
		}
	}
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

BTW, I could compile this:

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
class foo(T) {
	
}

void main() {
	mixin foo!(int) a;
}
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

but this gives me an error

vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
1. class foo(T) {
2. 	
3. }
4.
5. void main() {
6.	mixin foo!(int) a;
7.	mixin foo!(real) b;
8. }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> main.d(7): mixin foo!(real) foo is not a template

Why?
December 14, 2006
Jason House wrote:
> I'm kind of doing a trial by fire method to learn D and how it works... I'm
> taking an existing open source project and converting it over.  Here's the
> stuff that I've found / questions that I have.

Great.  Welcome.

> Thanks in advance for all the thoughtful responses.  I know this is a long
> post!  I've worked through the issues to get working code, but I think my
> issues will be hit by others.
> 
> It seems that DTL and minTL [...]

Never tried either one, so can't help you there.

> I know of no way in d to provide a const qualifier.  It seems like the concept
> purely doesn't exist.  minTL appears to have a workaround where it templates
> itself on a boolean value, and simply doesn't publish certain functions.  When
> will a real const qualifier get added to the language?  It seems really
> strange that a language that adds all kinds of contract programming wouldn't
> use const qualifiers / const types.

That's right.  D's const is limited to things whose value can be determined at compile time.  So no const function parameters, for instance.  I agree it is a bit odd.  In particular I'd really like to have 'const inout' parameters for functions (though that actual nomenclature is nonsense).  Right now declaring a parameter to be 'inout T' is the only way to make sure a huge value type T doesn't get copied on the stack.  'inout' is basically a T& in C++ terms.  'const T&' is probably more common in C++ than plain 'T&'.  Sadly, D has no equivalent for it.

My vote would be for an 'refin' or 'inref' parameter type in addition to the existing 'in', 'out', and 'inout' flavors.

I think the reason D doesn't have it is just because C++ code gets pretty ugly with all those consts everywhere.  Then there's const-correctness hell, when you decide to change one method to const and suddenly there's a ripple effect across your whole application. Until you get to the point where you discover that some 3rd party code out of your control is not const-correct and you ultimately resort to const_cast<>s.

I guess I'm used to it, though.  :-) That doesn't seem such a bad thing to me if it results in a program that more clearly documents which things can be modified.  I'm certainly glad that D is not Fortran where every parameter is basically inout, and you have to read the documentation to see if what you pass in is going to be clobbered or not.

> After banging my head on printing stuff for a long time, I've come to a few
> conclusions:
> * The C++ equivalent to std::ostream& operator << (std::ostream &out, const
> type &x) does not exist

I think std.stream.OutputStream.write is the closest there is.  But mainly you can't overload operators outside of classes in D.  And also I think template lookup across modules doesn't work.  What I recall being the killer the last time I brought up something like this was that Walter says it's too tricky to get Koenig lookup working.  I'm not really sure what the deal is, but I think D is going to need it eventually.  Correct me if I'm wrong, folks, but right now the only way to do things like C++'s operator<< (the compile-time polymorphism functionality, not the syntax) is to have an exhaustive list of static if, else static if, ... cases inside a template.  Thus users can't add their own overrides in a different module.

> * Custom types use the toString property

Yes.

> * Enums do not (and can not) have a toString property

I guess not.  But of course you can make a toString non-property for your enum.  writefln(toString(myEnum)) instead of writefln(myEnum).

> * I have found no way to determine (in a templated class) if a type is
> printable or not.  static if(is(typeof(T))) comes close, but my very first
> test using ints failed.

You mean printable as in writefln(x) will work on it?  Hmm.  That is kinda tricky.  I think there's a way to do it, but it will likely involve lots of static if's checking one-by-one for types that are printable.  Ultimately, though, what's "printable" boils down to what things std.format.doFormat supports, and that's ultimately only determinable at runtime.

> The special unittest member function doesn't get built in with -unittest
> unless the actual class is used in some way (and then one copy of the unittest
> funciton gets run for each type).  I'd really like to see some way for this to
> work.  for example, class foo(T){ ... unittest{ foo!(int) sample; ...} } does
> not run unless other code instantiates foo!(U)

That sounds like a bug.  I didn't even realize you could put unittests inside of classes.  All the code I've seen has the unittests outside of the class.

> In my early efforts at doing operator overloading, I wrote opCmp and then was
> shocked when my unit test showed that == didn't even call opCmp.  It silently
> did something wrong.  This seems like a gotcha built into the language that
> should probably get remedied.

Like what?  I'm not really to up on opEquals/opCmp.  Should you get a warning if you only override opCmp?  Or an error?

> I couldn't find a way to reinitialize a variable back to a default value...
> For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
> compile.  I'm not too sure why this is the case.

bar[3] = T.init is what you need for a value type.

--bb
December 14, 2006
Sean Kelly wrote:
> Check DSource (www.dsource.org).  IIRC there is at least one STL replacement project there.  Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year.  MinTL was created by Ben Hinkle, and has been dormant for almost as long.  MinTL is more mature however, and should be easier to update.


When poking around that site, I didn't see anything obviously STL related.  I've been known to be bline in the past.


>> * Custom types use the toString property
> 
> Yes, though some of us wish this function were called "toUtf8" to improve clarity.  This is an idealistic point however, and not pertinent to the discussion.
> 
>> * Enums do not (and can not) have a toString property
> 
> They don't at the moment.  One could be added, I imagine, but it would have to be done in the compiler.

That's exactly correct... Or at the very least the compiler must allow such properties to be added to them.  I did try adding my own toString property (just in case there was neat hidden feature like that)


>> * I have found no way to determine (in a templated class) if a type is
>> printable or not.  static if(is(typeof(T))) comes close, but my very first
>> test using ints failed.
> 
> "static if(is(typeof(T.toString)))" should tell you whether the function is defined, if T is a struct or class, but it sounds like you want to test concrete types as well?

Sorry, typo in my original post.  What you propose is what I put in the code.  Yes, I want to handle concrete types as well.


> Why not do:
> 
>     class C(T) {}
>     unittest { /* test C here */ }
> 
> Since private data is actually visible at module scope, the above approach loses nothing over having unittest within the class definition itself.

That's what I have to do, but it seems to be against "the D way" of embedding contracts and unit tests as closely as possible to the true code.  I haven't used ddoc, but I bet the alternate method may yield misleading documentation.


> 
>> In my early efforts at doing operator overloading, I wrote opCmp and then was
>> shocked when my unit test showed that == didn't even call opCmp.  It silently
>> did something wrong.  This seems like a gotcha built into the language that
>> should probably get remedied.
> 
> It calls opEquals.  Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.

I can totally see that.  But what happens when only opCmp is defined? Should the default opEquals use opCmp or do something else?  I was assuming it'd use opCmp.  Again, in what I perceive to be the style of D, such oops type things should possibly cause a warning.


> 
>> I couldn't find a way to reinitialize a variable back to a default value...
>> For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
>> compile.  I'm not too sure why this is the case.
> 
> Try:
> 
>     T[] bar = new T[size];
>     T[0 .. $] = new T();
> 
> You still have to resize and assign in separate operations, but the above should work.


I'll try that.
My actual code was essentially
T[] bar = new T[size];
for (int i=0; i<size; i++)
  T[i] = new T();

... which I totally expect to work.  (sorry for leaving out the array sizing in my original example)
December 14, 2006
Jason House wrote:
> Sean Kelly wrote:
>> Check DSource (www.dsource.org).  IIRC there is at least one STL replacement project there.  Of the above, DTL was created by Matthew Wilson, and hasn't been updated in at least a year.  MinTL was created by Ben Hinkle, and has been dormant for almost as long.  MinTL is more mature however, and should be easier to update.
> 
> 
> When poking around that site, I didn't see anything obviously STL related.  I've been known to be bline in the past.

There is a branch of the Mango tree for containers.
http://dsource.org/projects/mango

That said, I find that I rarely miss container classes/structs in D.  The most common cases are handled by variable-length arrays.  (Although I do have pseudo-member functions in Cashew for simulating a stack using an array.)
http://dsource.org/projects/cashew

# import cashew .utils .array ;
# import std           .stdio ;
#
# void main (char[][] args) {
#   char[][] stack ;
#
#   foreach (x; args)
#     stack.push(x);
#
#   while (stack.length)
#     writefln("%s", stack.pop);
# }

Trees are also very easily achieved in D.  If all you need is the basic concept of a tree structure, with breadth-first and depth-first iteration, its a snap.  Something like this, for example:

# struct Tree(int B = 2, T) {
#   version (Tree_NoWarnings) {} else
#     static if (B == 0)
#       static assert(false, "A tree with zero branches is just useless.");
#     else static if (B == 1)
#       static assert(false, "A tree with only one branch may as well be an array.");
#
#   alias Tree!(B, T) Node ;
#
#   Node*[B] children ;
#   T        value    ;
#
#   int walkDepth (int delegate(inout Node) dlg) {
#     int result ;
#
#     foreach (x; children)
#       if (x && (result = x.walkDepth(dlg)))
#         goto L_end;
#     result = dlg(this);
#
#   L_end:
#     return result;
#   }
#
#   int walkBreadth (int delegate(inout Node) dlg) {
#     int     result          ;
#     Node*[] gen    = [this] ,
#             next            ;
#
#     while (gen.length) {
#       foreach (x; gen) {
#         if (result = dlg(x.value))
#           goto end;
#         foreach (y; x.children)
#           if (y)
#             next ~= y;
#       }
#       gen = next.dup;
#       next.length = 0;
#     }
#
#     end:
#       return result;
#   }
# }

(Of course there are some things that just seem to work better with elaborate container libraries.  Its all according to the needs, as with anything.)

>>> * Enums do not (and can not) have a toString property
>>
>> They don't at the moment.  One could be added, I imagine, but it would have to be done in the compiler.
> 
> That's exactly correct... Or at the very least the compiler must allow such properties to be added to them.  I did try adding my own toString property (just in case there was neat hidden feature like that)

No... but you can have a constant associative array, with the enum as the key and a string as the value.  This is what I usually do when I want string representations of enum values.  For a cheap example:

# enum Qubit {
#   T, F, TT, TF, FT, FF
# }
#
# const char[][Qubit] QubitNames ;
#
# static this () {
#   QubitNames[Qubit.T ] = "T"  ;
#   QubitNames[Qubit.F ] = "F"  ;
#   QubitNames[Qubit.TT] = "TT" ;
#     // ... etc
# }

> That's what I have to do, but it seems to be against "the D way" of embedding contracts and unit tests as closely as possible to the true code.  I haven't used ddoc, but I bet the alternate method may yield misleading documentation.

So far as I have personally experienced, DDoc doesn't emit any content for unittests anyhow.  So there should be no impact as far as that goes.  And since you can have as many unittests in a module as you like, its still pretty "D like" to have a unittest block after each class definition.

>>> In my early efforts at doing operator overloading, I wrote opCmp and then was
>>> shocked when my unit test showed that == didn't even call opCmp.  It silently
>>> did something wrong.  This seems like a gotcha built into the language that
>>> should probably get remedied.
>>
>> It calls opEquals.  Personally, I prefer this approach as it's not uncommon for me to define an ordering scheme that is less strict than I want for equality comparisons.
> 
> I can totally see that.  But what happens when only opCmp is defined? Should the default opEquals use opCmp or do something else?  I was assuming it'd use opCmp.  Again, in what I perceive to be the style of D, such oops type things should possibly cause a warning.

I for one think the default opEquals probably /should/ use opCmp... but alas.

>>> I couldn't find a way to reinitialize a variable back to a default value...
>>> For example class foo(T){ T[] bar; void func(){bar[3] = new T();} } won't
>>> compile.  I'm not too sure why this is the case.
>>
>> Try:
>>
>>     T[] bar = new T[size];
>>     T[0 .. $] = new T();
>>
>> You still have to resize and assign in separate operations, but the above should work.
> 
> 
> I'll try that.
> My actual code was essentially
> T[] bar = new T[size];
> for (int i=0; i<size; i++)
>   T[i] = new T();
> 
> ... which I totally expect to work.  (sorry for leaving out the array sizing in my original example)

You can also use...
 bar[] = new T;

...to emulate the above.  If I recall right, array[] as an LValue is the same as array[0..$] as one.  However, chances are what you meant to do was to set each element to a /seperate/ object, rather than setting them all to the same one...  If so, the following is what you would probably rather do.

# bar.length = size; // won't reallocate unless size is bigger than before
# foreach (inout x; bar)
#   x = new T;


Above all, have fun with your new D experience.  :)

-- Chris Nicholson-Sauls
December 14, 2006
Jason House wrote:
> Sean Kelly wrote:
>>
>>> * Enums do not (and can not) have a toString property
>>
>> They don't at the moment.  One could be added, I imagine, but it would have to be done in the compiler.
> 
> That's exactly correct... Or at the very least the compiler must allow such properties to be added to them.  I did try adding my own toString property (just in case there was neat hidden feature like that)

This actually works for arrays, but only arrays.  People have asked in the past that it be extended to work for arbitrary types, but no luck so far.  ie.

    void doSomething( char[] buf );

    doSomething( "abc" );
    "abc".doSomething();

Both of the above calls should work, since char[] is an array type.


Sean
December 14, 2006
Chris Nicholson-Sauls wrote:
> 
> That said, I find that I rarely miss container classes/structs in D.  The most common cases are handled by variable-length arrays.  (Although I do have pseudo-member functions in Cashew for simulating a stack using an array.)

I've got a module of array ops that offers heap and set operations, as well as sort, binary search, etc.  And I feel quite the same.


Sean
December 14, 2006
An earlier post showed stack with push and pop for an array.  How does one do a queue? a set?

Also, I haven't found a way to check if something is in an associative array or not.

This may all boil down to me not being able to find a comprehensive list of array properties and/or quality documentation on the D language.
December 14, 2006
Jason House wrote:
> An earlier post showed stack with push and pop for an array.  How does one do a
> queue? a set?
> 
> Also, I haven't found a way to check if something is in an associative array or not.
> 
> This may all boil down to me not being able to find a comprehensive list of array
> properties and/or quality documentation on the D language.

Well... I don't know that I've ever done Queue/Set, but it wouldn't be hard.  Quick cheap version of a Queue off the top of my head:

# // really only neccessary for completeness
# void qpush (T) (inout T[] haystack, T needle) {
#   haystack ~= needle;
# }
#
# T qpop (T) (inout T[] haystack) {
#   T result = haystack[0];
#
#   haystack = haystack[1 .. $];
#   return result;
# }
#
# // and now in use
# char[][] queue;
#
# queue.qpush("alpha");
# queue.qpush("beta");
# queue.qpush("gamma");
#
# auto item = queue.qpop(); // item == "alpha"

Or if one is using Cashew, you could really just do:

# import cashew .utils .array ;
#
# alias push  qpush ;
# alias shift qpop  ;


As for a Set... well, that might take a class/struct wrapper to do succinctly.  Or, again using cashew, you could just make a point of calling .unique() after each insert/concat.

# int[] set = ... ;
#
# set ~= 42, set.unique();

Not very pretty though.

-- Chris Nicholson-Sauls
« First   ‹ Prev
1 2 3