Re: My thoughts experiences with D so far, as a novice D coder

2013-10-08 Thread Denis Shelomovskij

28.03.2013 0:28, Andrei Alexandrescu пишет:

On 3/27/13 3:18 PM, H. S. Teoh wrote:

Which is what Denis' multidimensional array implementation does. As does
my implementation as well.

This seems to be quite a common use-case; we should put this into Phobos
IMO.


Agree. Do you (or Denis) have something in reviewable form?

Andrei


No. The module is 2 years old and I only made changes on dmd requests. 
But if such functionality is really needed I will be happy to revise API 
and prepare my implementation for review.


P.S.
It's an accident I have seen this post. I think in the case of such 
questions it is obligatory to e-mail the author or there is a big risk 
the question will bot be delivered.


--
Денис В. Шеломовский
Denis V. Shelomovskij


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-29 Thread Jesse Phillips

On Friday, 29 March 2013 at 02:39:59 UTC, Jonathan M Davis wrote:


Only having append would actually be problematic, as there
are cases where you really do need write and not append. And 
neither of them
have been in Phobos for all that long (peek, read, write, and 
append were

added in 2.060).

- Jonathan M Davis


Ah, I was just going by the docs when I wrote this. I apparently 
got it wrong. write doesn't using indexing it uses opSliceAssign 
(which isn't in its constraints). I'm also not familiar with the 
use cases and there are definitely reasons to stray from 
idiomatic D.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-29 Thread Jonathan M Davis
On Friday, March 29, 2013 16:33:33 Jesse Phillips wrote:
 Ah, I was just going by the docs when I wrote this. I apparently
 got it wrong. write doesn't using indexing it uses opSliceAssign
 (which isn't in its constraints).

I'll have to take a look at that. I think that it was pretty much assuming 
that all of the slicing stuff would work with hasSlicing, but that stuff 
doesn't 
check for opSliceAssign, so clearly the template constraints need some work. 
Thanks for pointing that out.

- Jonathan M Davis


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Jacob Carlborg

On 2013-03-27 16:34, Vidar Wahlberg wrote:


- I find myself in a world of pain when I want to share data more
complex than the basic data types (int, char, byte, etc) across threads.
Seemingly the magic trick is to cast(shared) foo (or
cast(immutable)) when passing objects/references to another thread,
then cast(Foo) back on the receiving end (as most classes/structs in
the standard library refuse to let you call any methods when the object
is shared). The examples in the source and TDPL are fairly limited on
the issue, it mostly covers only those basic data types.


Try message passing and serialize the data you want to send.

Message passing: http://dlang.org/phobos/std_concurrency.html
Serialization: https://github.com/jacob-carlborg/orange

--
/Jacob Carlborg


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread 1100110

On 03/27/2013 12:08 PM, Steven Schveighoffer wrote:

On Wed, 27 Mar 2013 11:34:19 -0400, Vidar Wahlberg
vidar.wahlb...@gmail.com wrote:


- When casting a value to an enum, there's no checking that the value
actually is a valid enum value. Don't think I ever found a solution on
how to check whether the value after casting is a valid enum value, it
hasn't been a pressing issue.


Typically, one uses std.conv.to to safely convert one value into
another. Cast should be avoided unless absolutely necessary.

I just tested it, it works on enum *strings*, but not enum *values*

For example:

import std.conv;

enum X {
i, j, k
}

void main()
{
X x = to!X(i); // works!
x = to!X(1); // fails!
}




I think to should be able to do this, but I'm not a good enough guru
with templates and compile-time type info to know if it's possible.
Anyone know if this is possible? If so, I think it should be added.

-Steve


It also works on values


enum A
{
B,
C,
D,
}
int w;

import std.conv;
import std.stdio;

void main()
{
   auto t = w.to!A.B;

   writeln(t);
}


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread 1100110

On 03/27/2013 03:47 PM, Steven Schveighoffer wrote:

On Wed, 27 Mar 2013 14:09:07 -0400, Nick Sabalausky
seewebsitetocontac...@semitwist.com wrote:


On Wed, 27 Mar 2013 14:07:27 -0400
Nick Sabalausky seewebsitetocontac...@semitwist.com wrote:


On Wed, 27 Mar 2013 13:08:19 -0400

 I just tested it, it works on enum *strings*, but not enum *values*

 For example:

 import std.conv;

 enum X {
 i, j, k
 }

 void main()
 {
 X x = to!X(i); // works!
 x = to!X(1); // fails!
 }


Works for me on 2.063 Win. Keep in mind:

assert(cast(int)X.i == 0);
assert(cast(int)X.j == 1);



I meant of course 2.062



Hah, I have not yet downloaded 2.062. It did not work in 2.061, not sure
if that was a bug or it's a new feature.

anyway, that is good to know!

-Steve


It worked for me in 2.061, as that's what I'm currently on.


Waiting to build the release that I hear might have shared objects!


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Timon Gehr

On 03/28/2013 04:18 AM, deadalnix wrote:

On Wednesday, 27 March 2013 at 18:20:49 UTC, Andrei Alexandrescu wrote:

On 3/27/13 1:23 PM, Timon Gehr wrote:

- Function that never return are inferred void. I would have preferred
typeof(null) as void lead to many static and repetitive code for
nothing
when doing metaprograming.


I strongly disagree.


Ideally such function should return a none type, the bottom of the
hierarchy lattice. We don't have such, so returning typeof(null)
(which we do have) is the next best choice as it's just above bottom.



I thought that typeof(null) was that bottom type. What is the difference ?



There is a huge difference.

 - typeof(null) is a subtype of all _class, interface and pointer_
   types because they all _include_ its value, null.

 - bottom is a subtype of _all_ types, because there is _no_ value of
   type bottom.


Anyway, void isn't the right choice here and is a pain to work with.


typeof(null) would be worse.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread deadalnix

On Thursday, 28 March 2013 at 10:34:35 UTC, Timon Gehr wrote:

On 03/28/2013 04:18 AM, deadalnix wrote:
On Wednesday, 27 March 2013 at 18:20:49 UTC, Andrei 
Alexandrescu wrote:

On 3/27/13 1:23 PM, Timon Gehr wrote:
- Function that never return are inferred void. I would 
have preferred
typeof(null) as void lead to many static and repetitive 
code for

nothing
when doing metaprograming.


I strongly disagree.


Ideally such function should return a none type, the bottom 
of the
hierarchy lattice. We don't have such, so returning 
typeof(null)
(which we do have) is the next best choice as it's just above 
bottom.




I thought that typeof(null) was that bottom type. What is the 
difference ?




There is a huge difference.

 - typeof(null) is a subtype of all _class, interface and 
pointer_

   types because they all _include_ its value, null.

 - bottom is a subtype of _all_ types, because there is _no_ 
value of

   type bottom.



OK I see the difference.

Anyway, void isn't the right choice here and is a pain to work 
with.


typeof(null) would be worse.


I don't see how it is worse.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread renoX

On Wednesday, 27 March 2013 at 16:04:49 UTC, bearophile wrote:

Vidar Wahlberg:

[cut]
That static arrays are value types while dynamic arrays are 
reference types may not be obvious for those with primarily 
Java background.


Java has a semantics more limited compared to a system language 
as D/Rust. This is not easy to avoid.


Especially when keeping the poor C/C++ syntax for declaration 
instead of Pascal-style declaration syntax where you *name* the 
kind of array you're using!


*Sigh* and some still think that syntax doesn't matter..

renoX


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Vidar Wahlberg

To follow up with some new woes I'm currently struggling with:
I'm storing some various values in an ubyte array. I discovered 
that it's probably std.bitmanip I wish to use in order to 
convert i.e. an int to 4 bytes (although I went first to 
std.conv looking for this feature).
So I have ubyte[] buffer;, and my second thought is that the 
append method 
(http://dlang.org/phobos/std_bitmanip.html#.append) is what I 
want to append values to my ubyte-array (my first thought was 
something like buffer ~= to!ubyte[](42);, although then I 
forgot about endianness). In the example in the documentation it 
does say auto buffer = appender!(const ubyte[])();, with no 
explanation as of what appender is (I later learned that this 
is from std.array), but just looking a bit up I see that the 
write method explained just above use ubyte[] buffer; 
buffer.write!ubyte(42);, so I assumed that I could use ubyte[] 
myself instead of this appender which I thought was some legacy 
code.

So I write some simple test code:
 import std.bitmanip, std.stdio;
 void main() {
  ubyte[] buffer;
  buffer.append!ubyte(42);
 }
Run it through rdmd, and get: 
core.exception.AssertError@/usr/include/d/std/array.d(591): 
Attempting to fetch the front of an empty array of ubyte.
Just to see what happens I set the size of the buffer 
(buffer.length = 1;) before appending and run it again. Now it 
runs, but instead of appending it behaves like write(), which was 
not exactly what I wanted.


At this time I google for this appender used in the example and 
learn that it comes from std.array, so I import std.array and try 
again using auto buffer = appender!(ubyte[])();, and surely 
enough, now it does append correctly to the buffer. Great, I have 
a solution, so I go back to my project and implement it like I 
implemented it in my test code, but when I compile my project 
after this addition I get a new cryptic error message: Error: 
__overloadset isn't a template.
After digging a bit I realized that it's because in my project I 
also import std.file, apparently there are some collisions 
between std.bitmanip and std.file. Again it's solvable, but it's 
yet another fight with the language/standard library. I would 
also assume that it's not that uncommon for a module that use 
std.bitmanip to also use std.file, meaning that this error 
potentially may occur often.


A bit on the side: It seems to me as importing std.bitmanip 
somehow adds new properties to my array (.read() and 
.write(), for example). Not necessarily a bad thing, more of 
I've not seen this before, I was expecting that I were to 
concatenate the bytes from the conversion to my buffer using ~.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread H. S. Teoh
On Thu, Mar 28, 2013 at 09:24:49PM +0100, Vidar Wahlberg wrote:
 To follow up with some new woes I'm currently struggling with: I'm
 storing some various values in an ubyte array. I discovered that it's
 probably std.bitmanip I wish to use in order to convert i.e.  an int
 to 4 bytes (although I went first to std.conv looking for this
 feature).
[...]

There are several ways to convert an int into 4 bytes:

1) Use a union:

static assert(int.sizeof==4);
ubyte[4] intToUbytes(int x) {
union U {
int i;
ubyte[4] b;
}
U u;
u.i = x;
return u.b;
}

2) Use bit operators:

ubyte[4] intToUbytes(int x) {
ubyte[4] bytes;

// Note: this assumes little-endian. For big-endian,
// reverse the order below.
bytes[0] = x  0xFF;
bytes[1] = (x  8)  0xFF;
bytes[2] = (x  16)  0xFF;
bytes[3] = (x  24)  0xFF;

return bytes;
}

3) Use a pointer cast (warning: un-@safe):

ubyte[4] intToUbytes(int x) @system {
ubyte[4] b;
ubyte* ptr = cast(ubyte*)x;
b[0] = *ptr++;
b[1] = *ptr++;
b[2] = *ptr++;
b[3] = *ptr;

return b;
}

4) Reinterpret a pointer (warning: un-@safe):

ubyte[4] intToUbytes(int x) @system {
return *cast(ubyte[4]*)x;
}

I'm sure there are several other ways to do it.

You don't need to use appender unless you're doing a lot of conversions
in one go.


--T


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread 1100110

On 03/28/2013 03:24 PM, Vidar Wahlberg wrote:

To follow up with some new woes I'm currently struggling with:
I'm storing some various values in an ubyte array. I discovered that
it's probably std.bitmanip I wish to use in order to convert i.e. an
int to 4 bytes (although I went first to std.conv looking for this
feature).
So I have ubyte[] buffer;, and my second thought is that the append
method (http://dlang.org/phobos/std_bitmanip.html#.append) is what I
want to append values to my ubyte-array (my first thought was something
like buffer ~= to!ubyte[](42);, although then I forgot about
endianness). In the example in the documentation it does say auto
buffer = appender!(const ubyte[])();, with no explanation as of what
appender is (I later learned that this is from std.array), but just
looking a bit up I see that the write method explained just above use
ubyte[] buffer; buffer.write!ubyte(42);, so I assumed that I could use
ubyte[] myself instead of this appender which I thought was some
legacy code.
So I write some simple test code:
import std.bitmanip, std.stdio;
void main() {
ubyte[] buffer;
buffer.append!ubyte(42);
}
Run it through rdmd, and get:
core.exception.AssertError@/usr/include/d/std/array.d(591): Attempting
to fetch the front of an empty array of ubyte.
Just to see what happens I set the size of the buffer (buffer.length =
1;) before appending and run it again. Now it runs, but instead of
appending it behaves like write(), which was not exactly what I wanted.

At this time I google for this appender used in the example and learn
that it comes from std.array, so I import std.array and try again using
auto buffer = appender!(ubyte[])();, and surely enough, now it does
append correctly to the buffer. Great, I have a solution, so I go back
to my project and implement it like I implemented it in my test code,
but when I compile my project after this addition I get a new cryptic
error message: Error: __overloadset isn't a template.
After digging a bit I realized that it's because in my project I also
import std.file, apparently there are some collisions between
std.bitmanip and std.file. Again it's solvable, but it's yet another
fight with the language/standard library. I would also assume that it's
not that uncommon for a module that use std.bitmanip to also use
std.file, meaning that this error potentially may occur often.

A bit on the side: It seems to me as importing std.bitmanip somehow adds
new properties to my array (.read() and .write(), for example). Not
necessarily a bad thing, more of I've not seen this before, I was
expecting that I were to concatenate the bytes from the conversion to my
buffer using ~.



Yes, some functions do overload one another's functions...
Usually it's because they are templated, and can accept the same arguments.

using std.file.read will work, or import stdfile = std.file;
stdfile.read;

Just makin sure ya knew how to fix that.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Chris Cain

On Thursday, 28 March 2013 at 20:24:50 UTC, Vidar Wahlberg wrote:

To follow up with some new woes I'm currently struggling with:
I'm storing some various values in an ubyte array. I discovered 
that it's probably std.bitmanip I wish to use in order to 
convert i.e. an int to 4 bytes (although I went first to 
std.conv looking for this feature).

--snip--


I am completely confused as to why you're doing what you are 
doing ... std.conv does work (and in the case you've listed, is 
unnecessary anyway). Try this:


import std.stdio, std.conv;

void main() {
ubyte[] buffer;
buffer ~= 5; // Simple solution
buffer ~= to!ubyte(6); // Proper usage of to
writeln(buffer);
}

---

Now, for performance reasons you might want to use appender (or 
buffer.reserve(n), if you happen to know how many items you'll be 
storing), but the simplest thing works.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Chris Cain

On Thursday, 28 March 2013 at 20:24:50 UTC, Vidar Wahlberg wrote:
that it's probably std.bitmanip I wish to use in order to 
convert i.e. an int to 4 bytes (although I went first to 
std.conv looking for this feature).


Ah, I reread it a couple of times and realized what you mean now.

You want to turn an int like 5 into an array of ubytes like 
[0,0,0,5].


So, you were on the right track, here's one way on how it's done:

---

import std.stdio, std.bitmanip, std.array;
void main() {
auto app = appender!(ubyte[])(); // Create an appender of 
type ubyte[]

app.append!int(5);
writeln(app.data());
}

---

Without using appender, it's a bit more complicated:

---
import std.stdio, std.bitmanip;
void main() {
auto buf = new ubyte[](4);
buf.append!int(5);
writeln(buf);
}
---

So, what append is doing is writing into the buffer, which must 
have enough space to put the int. So, thus, it must have 4 bytes. 
Guess what happens if we try to store a long in it? Yeah, it'll 
break on that as well. You'll also notice that subsequent calls 
to append on that buf will overwrite what's already in there.



It's not obvious, but append needs either an array with enough 
space to store the element or an output range, like appender. 
Maybe the documentation could use a little work in this regard.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Vidar Wahlberg

On Thursday, 28 March 2013 at 21:16:32 UTC, Chris Cain wrote:
I am completely confused as to why you're doing what you are 
doing ... std.conv does work (and in the case you've listed, is 
unnecessary anyway). Try this:


import std.stdio, std.conv;

void main() {
ubyte[] buffer;
buffer ~= 5; // Simple solution
buffer ~= to!ubyte(6); // Proper usage of to
writeln(buffer);
}


This is not what I'm trying to achieve.
This gives me an array with two elements, [5, 6]. What I want is 
to append the 4 bytes that make up one integer value, which using 
your values means buffer should hold a total of 8 bytes (two 
integers).


H. S. Teoh answered well on how this can be achieved, although my 
feedback was not really meant as a question of how is this 
done?, more of why is this done like this, couldn't it be done 
much easier?.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Chris Cain

On Thursday, 28 March 2013 at 22:22:49 UTC, Chris Cain wrote:

---
ubyte[T.sizeof] toUbytes(T)(T val) @safe {
ubyte[T.sizeof] buf;
std.bitmanip.append!T(buf[], val);
return buf;
}
---


This should be:

ubyte[T.sizeof] toUbytes(T)(T val) @safe {
ubyte[T.sizeof] buf;
import std.bitmanip : append;
append!T(buf[], val);
return buf;
}


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Chris Cain

On Thursday, 28 March 2013 at 20:24:50 UTC, Vidar Wahlberg wrote:
A bit on the side: It seems to me as importing std.bitmanip 
somehow adds new properties to my array (.read() and 
.write(), for example). Not necessarily a bad thing, more of 
I've not seen this before, I was expecting that I were to 
concatenate the bytes from the conversion to my buffer using ~.


Sorry about the repeated postings ... I'm trying to read  answer 
it while also dealing with the norovirus :x


---

import std.stdio : writeln;
void main() {
ubyte[] array;
array ~= 5.toUbytes();
array ~= 6.toUbytes();
writeln(array);
}

ubyte[T.sizeof] toUbytes(T)(T val) @safe {
ubyte[T.sizeof] buf;
std.bitmanip.append!T(buf[], val);
return buf;
}

---

I see your latest post and see that you don't necessary care how 
to do it, but, I figured I might as well provide yet another way 
that's @safe and simple.


On Thursday, 28 March 2013 at 20:24:50 UTC, Vidar Wahlberg wrote:
Great, I have a solution, so I go back to my project and 
implement it like I implemented it in my test code, but when I 
compile my project after this addition I get a new cryptic 
error message: Error: __overloadset isn't a template.
After digging a bit I realized that it's because in my project 
I also import std.file, apparently there are some collisions 
between std.bitmanip and std.file. Again it's solvable, but 
it's yet another fight with the language/standard library. I 
would also assume that it's not that uncommon for a module that 
use std.bitmanip to also use std.file, meaning that this error 
potentially may occur often.


Yeah, that's a bit of an issue. Weird cryptic error. Oh well, as 
a general rule, try to import only the parts of the module you're 
actually using. This does two great things: it prevents namespace 
pollution causing errors like you've seen, and it documents WHERE 
someone has to look in order to find documentation on a function 
you're using in your module.


As 1100110 noted, using a fully qualified ID is also a potential 
solution, especially if you only intend on using it in one place 
and the line isn't very noisy to begin with (as I showed in my 
example above).



why is this done like this, couldn't it be done much easier?.


Maybe. What needs to be made easier and how would you suggest to 
fix it? The error message, certainly. Probably the documentation 
too. But the API itself seems sane to me in this instance, it 
just needs a better description.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Vidar Wahlberg

On Thursday, 28 March 2013 at 22:22:49 UTC, Chris Cain wrote:
Sorry about the repeated postings ... I'm trying to read  
answer it while also dealing with the norovirus :x


Been there. Not amusing, I wish you well.



why is this done like this, couldn't it be done much easier?.


Maybe. What needs to be made easier and how would you suggest 
to fix it? The error message, certainly. Probably the 
documentation too. But the API itself seems sane to me in this 
instance, it just needs a better description.


Well, I'm not so proficient in the language yet that I'm going to 
climb to the top of Mount Stupid and say how it should be, 
because for what I know this may be perfectly logical with just 
me being blind to it, but to try to explain how it would make 
more sense to me:
Since you got ubyte[] buffer = [0, 0, 0, 0]; 
buffer.write!int(42); buffer.read!int();, I think it would be 
logical that ubyte[] buffer; buffer.append!int(42); 
buffer.read!int() would do pretty much the same (except instead 
of writing 4 bytes at index 0, it appends 4 bytes to the end of 
the array, then reads back the value). The latter code does 
however give you Attempting to fetch the front of an empty array 
of ubyte.
I don't get why you need to drag in std.array.appender() for 
std.bitmanip.append(), when you don't need it for read() and 
write().


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Jonathan M Davis
On Friday, March 29, 2013 00:38:25 Vidar Wahlberg wrote:
 I don't get why you need to drag in std.array.appender() for
 std.bitmanip.append(), when you don't need it for read() and
 write().

Because read and write operate in place, and append doesn't. read and write 
operate on input ranges - read just reads the values from it as it iterates, 
and write overwrites what's there as it iterates. However, append uses an 
output range, because it's appending rather than overwriting, and for reasons 
that I don't understand, when treating an array as an output range, rather 
than appending (like an output range normally would), the put function (which 
is how stuff gets written to an output range) overwrites what's in the array 
rather than appending to it. So, using an empty array with any function 
operating on output ranges isn't going to work. Maybe there's a good reason 
for arrays working that way when they're treated as output ranges, but for me, 
it's a good reason to not use arrays when you need an output range.

In either case, I'd suggest reading this if you want to know more about 
ranges:

http://ddili.org/ders/d.en/ranges.html

And since D's standard library ranges quite heavily, you're going to need at 
least a basic understanding of them if you want to use much of it. We really 
need a good article on ranges on dlang.org, but until we do, that link is 
probably your best resource for learning about ranges.

- Jonathan M Davis


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Jesse Phillips

Definitely need to add some updates to the docs. Long story:

D provides an iterable interface called a Range. There are two 
base forms, inputRange and outputRange.


Dynamic Arrays have the privilege of being, a inputRange, 
outputRange, and a container.


An array however doesn't operate as you might expect, especially 
when using a function called append on it.


An output range consists of the ability call put for Range and 
Element (defined in std.range) for a dynamic array this means you 
can assign to front.


ubyte[] buffer;
buffer.append!ubyte(42);

The append function takes an outputRange, if we drill down the 
call that would be made (ignoring my value isn't correct)


buffer.front = 42;
buffer.popFront();

Thus when using an array as an outputRange it
1) Must have a size (hence the error: Attempting to fetch the 
front of an empty array of ubyte)
2) Starts at the beginning (hence the observation: instead of 
appending it behaves like write())

3) Is consumed (You didn't run into this)

That is why arrays are awkward and the example makes use of 
appender (a more traditional form of an outputRange)




The write function seems a little odd as it uses random access 
(indexing).


Instead of assigning to front like append does it assigns at 
index buffer[0]...




The implementation of append is what you will find more in 
idiomatic D. In fact if the module was written today write 
wouldn't exist and append would probably have been named write.


-
-

Error: __overloadset isn't a template

That needs fixed, it usually does a better job of specifying 
conflicting modules across modules.





It seems to me as importing std.bitmanip somehow adds new 
properties


D provides UFCS (Uniform Function Call Syntax). For a given type 
A, foo(A a) is callable in both foo(a) and a.foo().


(Historical note: UFCS is recent addition, a bug allowed it to 
work with dynamic arrays like you see in these docs)


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Jonathan M Davis
On Friday, March 29, 2013 03:11:08 Jesse Phillips wrote:
 The write function seems a little odd as it uses random access
 (indexing).
 
 Instead of assigning to front like append does it assigns at
 index buffer[0]...

That's because it's operating on multiple bytes at a time (e.g. writing the
4 bytes of an int at once). Really, it's  written for arrays and was
generalized because it could be rather than really having been written for
ranges.

 The implementation of append is what you will find more in
 idiomatic D. In fact if the module was written today write
 wouldn't exist and append would probably have been named write.

That could be argued for, but write and append do different things and both 
exist for a reason. Only having append would actually be problematic, as there 
are cases where you really do need write and not append. And neither of them 
have been in Phobos for all that long (peek, read, write, and append were 
added in 2.060).

- Jonathan M Davis


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Vidar Wahlberg

On Friday, 29 March 2013 at 01:13:36 UTC, Jonathan M Davis wrote:
In either case, I'd suggest reading this if you want to know 
more about

ranges:

http://ddili.org/ders/d.en/ranges.html


Thank you, I will read that (when the time is not 0400).
I feel I need to stress that this is something that quite 
possibly will scare away newcomers, that static arrays, dynamic 
arrays and ranges looks very similar to each other, but behaves 
differently. This is not the first time I fall in this pit, and I 
suspect it's not the last time either.
And well, sorry for continuing to nag about this, but take a look 
at the documentation for read(), write() and append() in 
std.bitmanip:
T read(T, En­dian en­di­an­ness = Endian.​bigEndian, R)(ref R 
range);
void write(T, En­dian en­di­an­ness = Endian.​bigEndian, R)(R 
range, T value, size_t index);
void ap­pend(T, En­dian en­di­an­ness = Endian.​bigEndian, R)(R 
range, T value);
append() and write() are practically identical, just with write() 
having an extra parameter. The documentation even comes with 
examples for write() that use ubyte[] buffer; 
buffer.write!ubyte(42, 0);, is it really odd that I assumed I 
could use append() in a similar matter when its parameters are 
exactly the same as for write() (minus the index)? Or is it 
unthinkable that I mistook arrays and Ranges for being 
interchangeable when the examples pass an array to a function 
that takes a Range?
Ranges is something that's going to be new for a lot of people 
entering this language. When you know how arrays and ranges works 
in D I'm sure this makes perfect sense, but until you learn that, 
this is something that likely will confuse many people.


Hopefully the article about ranges will clear things up for me.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-28 Thread Jonathan M Davis
On Friday, March 29, 2013 04:01:40 Vidar Wahlberg wrote:
 Or is it
 unthinkable that I mistook arrays and Ranges for being
 interchangeable when the examples pass an array to a function
 that takes a Range?

I don't think that it's unthinkable at all (and arrays _are_ ranges; it's just 
that in the case of output ranges, arrays act a bit oddly). The documentation 
should probably be improved to make such a mistake less likely.

 Ranges is something that's going to be new for a lot of people
 entering this language. When you know how arrays and ranges works
 in D I'm sure this makes perfect sense, but until you learn that,
 this is something that likely will confuse many people.
 
 Hopefully the article about ranges will clear things up for me.

Yes. Ranges are incredibly powerful, but while the concept doesn't originate 
with D, AFAIK, actually using them in a serious API (particularly in a 
standard library) is unique to D. And our lack of good tutorials on them is 
probably our biggest documentation problem. It definitely needs to be fixed.

- Jonathan M Davis


My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Vidar Wahlberg
I know I'm probably going to upset some people with this, bashing 
their favourite child and all, but I wanted to let you know the 
experience I've had with D so far, as a novice D coder with a 
heavy Java  light C++ background.
It's not that I dislike D, in fact there are tons of things I 
love about it, it's pretty much exactly what I'm looking for in a 
programming language at the moment. Yet, I encounter some 
frustrating issues when coding, often leaving me with the 
impression that I'm fighting the language more than the problem 
I'm trying to solve.
True, there are many things I don't know about D, compilers or 
the inner workings of a computer, and some of the fights I have 
with the language are likely started by myself because I'm 
dragging along my bias from other languages, drawing 
misconceptions on how the D language actually works.
My intentions are not to insult, but shed some light on some of 
the difficulties I've faced (and how I solved them), with the 
hope that it will help others from facing the same difficulties.



Woes:
-
- I find myself in a world of pain when I want to share data more 
complex than the basic data types (int, char, byte, etc) across 
threads. Seemingly the magic trick is to cast(shared) foo (or 
cast(immutable)) when passing objects/references to another 
thread, then cast(Foo) back on the receiving end (as most 
classes/structs in the standard library refuse to let you call 
any methods when the object is shared). The examples in the 
source and TDPL are fairly limited on the issue, it mostly covers 
only those basic data types.


- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you may 
wish to store the result of a function/method call as a global 
variable/class member, but when the function/method returns 
auto it's not apparent what the data type may be. While you may 
be able to find out what bar is by digging in the source code, 
it can still be difficult to find. One example is to save the 
result of std.regex.match() as a member in a class. For me the 
solution was to import std.traits, create a function auto 
matchText(string text) { return match(text, myRegex); } and 
define the class member as ReturnType!matchText matchResult; 
(do also note that function  member must come in the right order 
for this to compile). This was all but obvious to a novice D 
coder as myself, the solution was suggested to me in the IRC 
channel.



Gotchas:

- The lack of rectangular arrays created at runtime in D (int 
i = 5; int[i][i] foo;) can be quite confusing for programmers 
with Java or C++ background. Even though there exists 
alternatives 
(http://denis-sh.github.com/phobos-additions/unstd.multidimensionalarray.html), 
this design decision and how to get around it when you really 
desire a rectangular array could be explained in more detail at 
http://dlang.org/arrays.html.


- Static array versus dynamic array was one of the first traps I 
stepped on 
(http://forum.dlang.org/thread/jnu1an$rjr$1...@digitalmars.com). 
Until Jonathan M. Davis explained it in detail 
(http://d.puremagic.com/issues/show_bug.cgi?id=8026#c4), I pretty 
much considered it as magic that randomShuffle(staticArray); 
did not sort the array while randomShuffle(staticArray[]); did 
(the first call now gives you an compile error, though). That 
static arrays are value types while dynamic arrays are reference 
types may not be obvious for those with primarily Java background.


- When casting a value to an enum, there's no checking that the 
value actually is a valid enum value. Don't think I ever found a 
solution on how to check whether the value after casting is a 
valid enum value, it hasn't been a pressing issue.


- Compiling where DMD can't find all modules cause a rather 
cryptic error message. A solution is to make sure you specify all 
source files when compiling.



Wishlist:
-
- void[T] associative array (i.e. a set) would be nice, can 
be achieved with byte[0][T].


- Foo foo = new Foo(); for global variables/class members. Now 
you must Foo foo; static this() { foo = new Foo(); }.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread John Colvin

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg wrote:

- The lack of rectangular arrays created at runtime in D 
(int i = 5; int[i][i] foo;) can be quite confusing for 
programmers with Java or C++ background. Even though there 
exists alternatives 
(http://denis-sh.github.com/phobos-additions/unstd.multidimensionalarray.html), 
this design decision and how to get around it when you really 
desire a rectangular array could be explained in more detail 
at http://dlang.org/arrays.html.



int i = 5;

auto foo = new int[][](i,i);


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread bearophile

Vidar Wahlberg:

- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you 
may wish to store the result of a function/method call as a 
global variable/class member, but when the function/method 
returns auto it's not apparent what the data type may be. 
While you may be able to find out what bar is by digging in 
the source code, it can still be difficult to find.


Beside using returnType as suggested, another solution is to add 
in your code something like this:


pragma(msg, typeof(foo));

This tells you the type to use for your class member.

Haskell solves this in a better way, using Type holes:
http://www.haskell.org/haskellwiki/GHC/TypeHoles

The idea of those holes was developed in several complex ways, 
but at its smallest it is just a way offered by the compiler to 
the Haskell programmer to leave one thing explicitly not 
specified. The program will not compile, but the error message 
will tell you very well the type of what's missing. So you use 
this type information to put in the hole what the compiler wants.



That static arrays are value types while dynamic arrays are 
reference types may not be obvious for those with primarily 
Java background.


Java has a semantics more limited compared to a system language 
as D/Rust. This is not easy to avoid. On the other hand iterating 
on an array of structs/fixed size arrays has a trap that a D lint 
should warn against.



- When casting a value to an enum, there's no checking that the 
value actually is a valid enum value. Don't think I ever found 
a solution on how to check whether the value after casting is a 
valid enum value, it hasn't been a pressing issue.


cast() is a sharp unsafe tool. In Bugzilla I have a request to 
use to!() to perform that safely.



- Compiling where DMD can't find all modules cause a rather 
cryptic error message.


This was improved, and maybe there is further space for 
improvements. It's a fixable problem.




Wishlist:
-
- void[T] associative array (i.e. a set) would be nice, can 
be achieved with byte[0][T].


I think there's no need to add that as a built-in. There are 
things much more important to have as builtins (like tuples). For 
that a Phobos Set!T suffices.




- Foo foo = new Foo(); for global variables/class members.


Maybe in some time it will happen, thanks to Don too.

Bye,
bearophile


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread deadalnix

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg wrote:
I know I'm probably going to upset some people with this, 
bashing their favourite child and all, but I wanted to let you 
know the experience I've had with D so far, as a novice D coder 
with a heavy Java  light C++ background.
It's not that I dislike D, in fact there are tons of things I 
love about it, it's pretty much exactly what I'm looking for in 
a programming language at the moment. Yet, I encounter some 
frustrating issues when coding, often leaving me with the 
impression that I'm fighting the language more than the problem 
I'm trying to solve.
True, there are many things I don't know about D, compilers or 
the inner workings of a computer, and some of the fights I have 
with the language are likely started by myself because I'm 
dragging along my bias from other languages, drawing 
misconceptions on how the D language actually works.
My intentions are not to insult, but shed some light on some of 
the difficulties I've faced (and how I solved them), with the 
hope that it will help others from facing the same difficulties.




That is fine don't worry. Knowing what people have trouble with 
when starting with D is very valuable IMO.



Woes:
-
- I find myself in a world of pain when I want to share data 
more complex than the basic data types (int, char, byte, etc) 
across threads. Seemingly the magic trick is to cast(shared) 
foo (or cast(immutable)) when passing objects/references to 
another thread, then cast(Foo) back on the receiving end (as 
most classes/structs in the standard library refuse to let you 
call any methods when the object is shared). The examples in 
the source and TDPL are fairly limited on the issue, it mostly 
covers only those basic data types.




Well, that is a long standing issue. shared is poorly defined and 
inconsistently implemented. Sad, but true.


- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you 
may wish to store the result of a function/method call as a 
global variable/class member, but when the function/method 
returns auto it's not apparent what the data type may be. 
While you may be able to find out what bar is by digging in 
the source code, it can still be difficult to find. One example 
is to save the result of std.regex.match() as a member in a 
class. For me the solution was to import std.traits, create a 
function auto matchText(string text) { return match(text, 
myRegex); } and define the class member as 
ReturnType!matchText matchResult; (do also note that function 
 member must come in the right order for this to compile). 
This was all but obvious to a novice D coder as myself, the 
solution was suggested to me in the IRC channel.




Yes, I have to say that it is a pain sometime. Additionally, it 
have some rough edges you may want to know :
 - Function that never return are inferred void. I would have 
preferred typeof(null) as void lead to many static and repetitive 
code for nothing when doing metaprograming.
 - Type inference handle very poorly recursion. It should simply 
exclude the recursion when doing type inference as it won't 
change the return type. The error message can be very opaque.
 - In some cases, you have to add explicit casts when implicit 
would have been enough in theory (but the type inference 
mechanism is confused).


Back to your issue, you may want to use typeof . Sometime, it is 
plain better as type can become complex when doing 
metaprogramming (and phobos is full of this). You can also use an 
alias in order to make things look nice.


alias FooT = typeof(foo());
FooT bar;

bar = foo(); // Happy ?



Gotchas:

- The lack of rectangular arrays created at runtime in D 
(int i = 5; int[i][i] foo;) can be quite confusing for 
programmers with Java or C++ background. Even though there 
exists alternatives 
(http://denis-sh.github.com/phobos-additions/unstd.multidimensionalarray.html), 
this design decision and how to get around it when you really 
desire a rectangular array could be explained in more detail 
at http://dlang.org/arrays.html.


- Static array versus dynamic array was one of the first traps 
I stepped on 
(http://forum.dlang.org/thread/jnu1an$rjr$1...@digitalmars.com). 
Until Jonathan M. Davis explained it in detail 
(http://d.puremagic.com/issues/show_bug.cgi?id=8026#c4), I 
pretty much considered it as magic that 
randomShuffle(staticArray); did not sort the array while 
randomShuffle(staticArray[]); did (the first call now gives 
you an compile error, though). That static arrays are value 
types while dynamic arrays are reference types may not be 
obvious for those with primarily Java background.




Yes, Java have no value types, only reference types. This is 
actually a performance issue for 2 reasons :
 - You chase pointers, so you have cache miss and this is very 
costly on modern CPUs.

 

Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Dicebot
Welcome and thanks for sharing your experience! Few (hopefully) 
useful hints:



-
- I find myself in a world of pain when I want to share data 
more complex than the basic data types (int, char, byte, etc) 
across threads. Seemingly the magic trick is to cast(shared) 
foo (or cast(immutable)) when passing objects/references to 
another thread, then cast(Foo) back on the receiving end (as 
most classes/structs in the standard library refuse to let you 
call any methods when the object is shared). The examples in 
the source and TDPL are fairly limited on the issue, it mostly 
covers only those basic data types.


That is somewhat intended as D proposes message-passing a 
default multi-threading approach and makes sharing global data 
intentionally difficult. What lacks though, is some solid article 
series about how D way of doing things here, it is often quite 
not obvious. Definitely an area for improvement.




- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you 
may wish to store the result of a function/method call as a 
global variable/class member, but when the function/method 
returns auto it's not apparent what the data type may be. 
While you may be able to find out what bar is by digging in 
the source code, it can still be difficult to find. One example 
is to save the result of std.regex.match() as a member in a 
class. For me the solution was to import std.traits, create a 
function auto matchText(string text) { return match(text, 
myRegex); } and define the class member as 
ReturnType!matchText matchResult; (do also note that function 
 member must come in the right order for this to compile). 
This was all but obvious to a novice D coder as myself, the 
solution was suggested to me in the IRC channel.


It is much more simple actually, typeof(match(string.init, 
Regex.init)) variable; and no extra functions or source digging 
is needed. D static introspection is so much more powerful than 
in other languages that is often completely overlooked by 
newcomers.


- Static array versus dynamic array was one of the first traps 
I stepped on 
(http://forum.dlang.org/thread/jnu1an$rjr$1...@digitalmars.com). 
Until Jonathan M. Davis explained it in detail 
(http://d.puremagic.com/issues/show_bug.cgi?id=8026#c4), I 
pretty much considered it as magic that 
randomShuffle(staticArray); did not sort the array while 
randomShuffle(staticArray[]); did (the first call now gives 
you an compile error, though). That static arrays are value 
types while dynamic arrays are reference types may not be 
obvious for those with primarily Java background.


Unfortunately, there is a conflict of interest when targeting 
both programmers with Java and C background at the same time, 
what D tries to do. Sometimes it is very hard to resolve right.


- When casting a value to an enum, there's no checking that the 
value actually is a valid enum value. Don't think I ever found 
a solution on how to check whether the value after casting is a 
valid enum value, it hasn't been a pressing issue.


You most likely want std.conv.to - Phobos lexical cast. It does 
check enum valid values.


- Compiling where DMD can't find all modules cause a rather 
cryptic error message. A solution is to make sure you specify 
all source files when compiling.


Have you tried rdmd?


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread John Colvin

On Wednesday, 27 March 2013 at 16:15:45 UTC, John Colvin wrote:

This is actually nothing to do with auto. It's endemic to all 
templated returns from functions and the same is true in c++ (I 
don't know enough about java generics to comment).


Sorry, I'd want to correct this to This is only partly to do 
with auto.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread John Colvin

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg wrote:

- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you 
may wish to store the result of a function/method call as a 
global variable/class member, but when the function/method 
returns auto it's not apparent what the data type may be. 
While you may be able to find out what bar is by digging in 
the source code, it can still be difficult to find. One example 
is to save the result of std.regex.match() as a member in a 
class. For me the solution was to import std.traits, create a 
function auto matchText(string text) { return match(text, 
myRegex); } and define the class member as 
ReturnType!matchText matchResult; (do also note that function 
 member must come in the right order for this to compile). 
This was all but obvious to a novice D coder as myself, the 
solution was suggested to me in the IRC channel.


This is actually nothing to do with auto. It's endemic to all 
templated returns from functions and the same is true in c++ (I 
don't know enough about java generics to comment).


A solution to your particular problem

class A(type_of_myRegex) {
alias ReturnType!(match!(string, type_of_myRegex)) RegexR;
RegexR r;
void foo(string text, type_of_myRegex myRegex) {
r = match(text, myRegex);
}
}

of course, if you only ever use one Regex type then of course you 
could do without the templating in the class and hard-code it in.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 16:34:19 +0100
Vidar Wahlberg vidar.wahlb...@gmail.com wrote:
 
 Woes:
 -
 - I find myself in a world of pain when I want to share data more 
 complex than the basic data types (int, char, byte, etc) across 
 threads. Seemingly the magic trick is to cast(shared) foo (or 
 cast(immutable)) when passing objects/references to another 
 thread, then cast(Foo) back on the receiving end (as most 
 classes/structs in the standard library refuse to let you call 
 any methods when the object is shared). The examples in the 
 source and TDPL are fairly limited on the issue, it mostly covers 
 only those basic data types.
 

I haven't been dealing with threads or shared, but my
understanding is that casting to and from shared is not recommended as
it (deliberately) subverts the safety checks in the type system.
Although can't really say what the right way to handle it is since,
as I said, I've never dealt with that part of the language.


 - While the auto-keyword often is great, it can lead to 
 difficulties, especially when used as the return type of a 
 function, such as auto foo() { return bar; }. Sometimes you may 
 wish to store the result of a function/method call as a global 
 variable/class member, but when the function/method returns 
 auto it's not apparent what the data type may be. While you may 
 be able to find out what bar is by digging in the source code, 

Here's the trick I like to use:

// Some var with unknown type
auto var = ...;
pragma(msg, var:  ~ typeof(var).stringof);

That will print something like this at compile-time:

var: int

Unfortunately (or fortunately, depending on your point of view), it
ignores all convenience aliases and will always give you the *full*
original concrete static type, instead of any prettied-up aliases for
it, but it does work and gets the job done.


 
 - Static array versus dynamic array was one of the first traps I 
 stepped on 
 (http://forum.dlang.org/thread/jnu1an$rjr$1...@digitalmars.com). 
 Until Jonathan M. Davis explained it in detail 
 (http://d.puremagic.com/issues/show_bug.cgi?id=8026#c4), I pretty 
 much considered it as magic that randomShuffle(staticArray); 
 did not sort the array while randomShuffle(staticArray[]); did 
 (the first call now gives you an compile error, though). That 
 static arrays are value types while dynamic arrays are reference 
 types may not be obvious for those with primarily Java background.
 

Yea, I'd imagine there would be some value-type/reference-type
confusion from a lot of newcomers just because D *has* both value types
and reference types. As opposed to, say, Java where (almost?) everything
is a reference type, or C++ where everything is a value type, etc.

Personally, I find it very much worthwhile to have both value and
reference types. But you're right it is something many people will have
to learn to get used to, and particularly so with arrays.


 - When casting a value to an enum, there's no checking that the 
 value actually is a valid enum value. Don't think I ever found a 
 solution on how to check whether the value after casting is a 
 valid enum value, it hasn't been a pressing issue.
 

Honestly, I hate that, too. The problem is that enum is (unfortunately)
intended to do double-duty as a bitfield so you can do something like
this:

enum Options
{
FeatureA = 0b_0001;
FeatureB = 0b_0010;
FeatureC = 0b_0100;
FeatureD = 0b_1000;
// etc...
}

// Use features A and C
auto myOptions = Options.FeatureA | Options.FeatureC;

That possibility means that D *can't* check for validity as you suggest.

I'm convinced that scenario *should* be considered an entirely separate
thing because cramming it together with regular enumerations creates
conflicting goals with the two usages of enum, and forces unfortunate
design compromises with both.


 - Compiling where DMD can't find all modules cause a rather 
 cryptic error message. A solution is to make sure you specify all 
 source files when compiling.
 

D uses the C/C++ compilation model: It doesn't compile any files you
don't specifically tell it to compile. Remember, importing is not
the same as compiling: Merely importing a file only makes the
symbols visible, it doesn't automatically *compile* the imported file.
You have to tell it to do that.

Non-C/C++ developers often get tripped up on this, but it's normal and
expected for C/C++ toolchains or really anything that uses a separate
link step.

But D has an easy solution - just use RDMD instead:

rdmd --build-only -I{include paths as usual} {other flags} main.d

Just give it your *main* D file (*must* be the *last* argument), and
it'll automatically find all .d files needed and pass them all to DMD.


 
 Wishlist:
 -
 - void[T] associative array (i.e. a set) would be nice, can 
 be achieved with byte[0][T].
 

I agree. I've just been using bool[T], but byte[0][T] is a good
idea. Could probably do this, too, to help out:

template 

Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 04:34:19PM +0100, Vidar Wahlberg wrote:
[...]
 - While the auto-keyword often is great, it can lead to
 difficulties, especially when used as the return type of a function,
 such as auto foo() { return bar; }. Sometimes you may wish to store
 the result of a function/method call as a global variable/class
 member, but when the function/method returns auto it's not apparent
 what the data type may be.

This is true. Sometimes you really *do* want to know what the return
type of an auto function is. However, you can work around this by using
typeof:

auto func() {
return mysteriousType();
}

void main() {
alias RetType = typeof(func());

// Look, ma! I can use a type without knowing what it
// is!
RetType t = func();
...
}


 While you may be able to find out what bar is by digging in the
 source code, it can still be difficult to find.

I think this is a bad solution. A library user shouldn't need to look at
library source code to figure out what a return type is.


 One example is to save the result of std.regex.match() as a member
 in a class. For me the solution was to import std.traits, create a
 function auto matchText(string text) { return match(text, myRegex);
 } and define the class member as ReturnType!matchText matchResult;
 (do also note that function  member must come in the right order for
 this to compile). This was all but obvious to a novice D coder as
 myself, the solution was suggested to me in the IRC channel.

I find this solution a bit cumbersome. D already has a built-in typeof
operator, there's no need to write tons of wrappers everywhere just to
get a return type out. I would write it like this:

class C {
// Capture the return type of std.regex.match
alias MatchResult = typeof(std.regex.match(, ));

// Now you can store it
MatchResult result;

this(string target, string regex) {
result = std.regex.match(target, regex);
}
}


 Gotchas:
 
 - The lack of rectangular arrays created at runtime in D (int i =
 5; int[i][i] foo;) can be quite confusing for programmers with Java
 or C++ background. Even though there exists alternatives 
 (http://denis-sh.github.com/phobos-additions/unstd.multidimensionalarray.html),
 this design decision and how to get around it when you really desire
 a rectangular array could be explained in more detail at
 http://dlang.org/arrays.html.

We really need rectangular arrays in Phobos. Denis has written one, as
you linked above, and I've written one, too (which is similar to Denis'
version). But this is such a common usage that we really should have a
library module for it.

Note, however, that if all but 1 of the dimensions are known, then you
*can* have rectangular arrays:

// This is a rectangular array
int[3][4][5] rect;

See also: http://wiki.dlang.org/Dense_multidimensional_arrays


 - Static array versus dynamic array was one of the first traps I
 stepped on
 (http://forum.dlang.org/thread/jnu1an$rjr$1...@digitalmars.com). Until
 Jonathan M. Davis explained it in detail
 (http://d.puremagic.com/issues/show_bug.cgi?id=8026#c4), I pretty
 much considered it as magic that randomShuffle(staticArray); did
 not sort the array while randomShuffle(staticArray[]); did (the
 first call now gives you an compile error, though). That static
 arrays are value types while dynamic arrays are reference types may
 not be obvious for those with primarily Java background.

Well, the documentation needs to be improved in this regard, that's for
sure. But language-wise, there's really nothing wrong with it (it's not
a sin to be different from Java).


 - When casting a value to an enum, there's no checking that the value
 actually is a valid enum value. Don't think I ever found a solution on
 how to check whether the value after casting is a valid enum value, it
 hasn't been a pressing issue.

Yeah, I find this to be questionable behaviour too. But then again, in
D, one is expected to use std.conv for conversions (casting is generally
not recommended unless there's no other way to do it), and std.conv.conv
does check for valid enum values:

enum A { abc = 100, def = 200 }
A a;
writeln(a); // prints abc

a = to!A(150);  // this throws a runtime exception: 150 is not
// in the enum.


 - Compiling where DMD can't find all modules cause a rather cryptic
 error message. A solution is to make sure you specify all source
 files when compiling.

You could use rdmd, which I believe automatically scans for all source
files you depend on.


 Wishlist:
 -
 - void[T] associative array (i.e. a set) would be nice, can be
 achieved with byte[0][T].

I think we should make a Phobos module for this. I, for one, found

Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 05:04:48PM +0100, bearophile wrote:
[...]
 - When casting a value to an enum, there's no checking that the
 value actually is a valid enum value. Don't think I ever found a
 solution on how to check whether the value after casting is a
 valid enum value, it hasn't been a pressing issue.
 
 cast() is a sharp unsafe tool. In Bugzilla I have a request to use
 to!() to perform that safely.
[...]

It already does that on latest git phobos:

enum A { abc=100, def=200 }
A a;
a = to!A(150);  // throws runtime exception


T

-- 
All problems are easy in retrospect.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Steven Schveighoffer
On Wed, 27 Mar 2013 11:34:19 -0400, Vidar Wahlberg  
vidar.wahlb...@gmail.com wrote:


- When casting a value to an enum, there's no checking that the value  
actually is a valid enum value. Don't think I ever found a solution on  
how to check whether the value after casting is a valid enum value, it  
hasn't been a pressing issue.


Typically, one uses std.conv.to to safely convert one value into another.   
Cast should be avoided unless absolutely necessary.


I just tested it, it works on enum *strings*, but not enum *values*

For example:

import std.conv;

enum X {
 i, j, k
}

void main()
{
   X x = to!X(i); // works!
   x = to!X(1); // fails!
}

I think to should be able to do this, but I'm not a good enough guru with  
templates and compile-time type info to know if it's possible.  Anyone  
know if this is possible?  If so, I think it should be added.


-Steve


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 12:52:25PM -0400, Nick Sabalausky wrote:
 On Wed, 27 Mar 2013 16:34:19 +0100
 Vidar Wahlberg vidar.wahlb...@gmail.com wrote:
[...]
  - While the auto-keyword often is great, it can lead to 
  difficulties, especially when used as the return type of a 
  function, such as auto foo() { return bar; }. Sometimes you may 
  wish to store the result of a function/method call as a global 
  variable/class member, but when the function/method returns 
  auto it's not apparent what the data type may be. While you may 
  be able to find out what bar is by digging in the source code, 
 
 Here's the trick I like to use:
 
 // Some var with unknown type
 auto var = ...;
 pragma(msg, var:  ~ typeof(var).stringof);
 
 That will print something like this at compile-time:
 
 var: int
 
 Unfortunately (or fortunately, depending on your point of view), it
 ignores all convenience aliases and will always give you the *full*
 original concrete static type, instead of any prettied-up aliases for
 it, but it does work and gets the job done.

What's wrong with using typeof?

auto var = ...;
typeof(var) anotherVar;
...
anotherVar = var;


[...]
  - When casting a value to an enum, there's no checking that the 
  value actually is a valid enum value. Don't think I ever found a 
  solution on how to check whether the value after casting is a 
  valid enum value, it hasn't been a pressing issue.
  
 
 Honestly, I hate that, too. The problem is that enum is (unfortunately)
 intended to do double-duty as a bitfield so you can do something like
 this:
 
 enum Options
 {
 FeatureA = 0b_0001;
 FeatureB = 0b_0010;
 FeatureC = 0b_0100;
 FeatureD = 0b_1000;
 // etc...
 }
 
 // Use features A and C
 auto myOptions = Options.FeatureA | Options.FeatureC;
 
 That possibility means that D *can't* check for validity as you suggest.

As a compromise for now, I'd just use std.conv.to for when I want enum
values checked. In any case, using casts should be avoided in D unless
there's no other way around it. Casting is a @system-level operation,
and most application code shouldn't be using it.


 I'm convinced that scenario *should* be considered an entirely separate
 thing because cramming it together with regular enumerations creates
 conflicting goals with the two usages of enum, and forces unfortunate
 design compromises with both.
[...]

Yeah, I find using enums for bitfields a bit ugly. I mean, I love using
bitfields too (don't know if this is because of my C/C++ background
tending toward premature optimization) but conflating them with enums
that supposedly should have unique values is IMO a language smell. (And
don't get me started on enums being manifest constants instead of real
enums... I still find that jarring.)


T

-- 
Marketing: the art of convincing people to pay for what they didn't need
before which you can't deliver after.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Timon Gehr

On 03/27/2013 05:04 PM, deadalnix wrote:

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg wrote:

...



- While the auto-keyword often is great, it can lead to
difficulties, especially when used as the return type of a function,
such as auto foo() { return bar; }. Sometimes you may wish to store
the result of a function/method call as a global variable/class
member, but when the function/method returns auto it's not apparent
what the data type may be. While you may be able to find out what
bar is by digging in the source code, it can still be difficult to
find. One example is to save the result of std.regex.match() as a
member in a class. For me the solution was to import std.traits,
create a function auto matchText(string text) { return match(text,
myRegex); } and define the class member as ReturnType!matchText
matchResult; (do also note that function  member must come in the
right order for this to compile). This was all but obvious to a novice
D coder as myself, the solution was suggested to me in the IRC channel.



Yes, I have to say that it is a pain sometime. Additionally, it have
some rough edges you may want to know :
  - Function that never return are inferred void. I would have preferred
typeof(null) as void lead to many static and repetitive code for nothing
when doing metaprograming.


I strongly disagree. What would be an example of the problems you are 
apparently experiencing?



  - Type inference handle very poorly recursion. It should simply
exclude the recursion when doing type inference as it won't change the
return type. The error message can be very opaque.


The cases that are allowed would need to be specified more rigorously.


  - In some cases, you have to add explicit casts when implicit would
have been enough in theory (but the type inference mechanism is confused).

...


- Foo foo = new Foo(); for global variables/class members. Now you
must Foo foo; static this() { foo = new Foo(); }.


Yes, as it imply an heap allocation. It is an harder problem that it
seems as all thoses object could reference themselves.


Just serialize the CTFE object graph into the static data segment.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread deadalnix
On Wednesday, 27 March 2013 at 16:52:27 UTC, Nick Sabalausky 
wrote:
Honestly, I hate that, too. The problem is that enum is 
(unfortunately)
intended to do double-duty as a bitfield so you can do 
something like

this:

enum Options
{
FeatureA = 0b_0001;
FeatureB = 0b_0010;
FeatureC = 0b_0100;
FeatureD = 0b_1000;
// etc...
}

// Use features A and C
auto myOptions = Options.FeatureA | Options.FeatureC;

That possibility means that D *can't* check for validity as you 
suggest.




It can. myOptions is an int here, as Options would decay to its 
base type.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Brad Anderson

On Wednesday, 27 March 2013 at 17:23:01 UTC, Timon Gehr wrote:

On 03/27/2013 05:04 PM, deadalnix wrote:

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg

...
- Foo foo = new Foo(); for global variables/class members. 
Now you

must Foo foo; static this() { foo = new Foo(); }.


Yes, as it imply an heap allocation. It is an harder problem 
that it

seems as all thoses object could reference themselves.


Just serialize the CTFE object graph into the static data 
segment.


I believe that's what this pull aims to do:

https://github.com/D-Programming-Language/dmd/pull/1724


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Steven Schveighoffer

On Wed, 27 Mar 2013 13:32:06 -0400, deadalnix deadal...@gmail.com wrote:


On Wednesday, 27 March 2013 at 16:52:27 UTC, Nick Sabalausky wrote:

Honestly, I hate that, too. The problem is that enum is (unfortunately)
intended to do double-duty as a bitfield so you can do something like
this:

enum Options
{
FeatureA = 0b_0001;
FeatureB = 0b_0010;
FeatureC = 0b_0100;
FeatureD = 0b_1000;
// etc...
}

// Use features A and C
auto myOptions = Options.FeatureA | Options.FeatureC;

That possibility means that D *can't* check for validity as you suggest.



It can. myOptions is an int here, as Options would decay to its base  
type.


No, it's not.  try it.  I thought as you did too until recently.

And before you go checking, it's not a bug, it's functioning per the spec.

-Steve


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread deadalnix

On Wednesday, 27 March 2013 at 17:23:01 UTC, Timon Gehr wrote:
I strongly disagree. What would be an example of the problems 
you are apparently experiencing?




T foo(alias fallback)() {
// Do some processing return the result. If an error occurs 
use fallback mechanism.

}

Reasonable thing to do as fallback is to try another method 
workaround the error, throw, whatever.


The problem is that the fallback type inference makes it painful 
to work with, especially if fallback is a template itself.


For instance, in SDC, you can parse ambiguous things as follow :
parseTypeOrExpression!((parsed) {
static if(is(typeof(parsed) : Expression)) {
// Do something
} else {
throw SomeException();
}
})(tokenRange);

This is bound to fail. When a function never return, it make no 
sens to force a type on it and the magic subtype typeof(null) 
should be used (as typeof(null) can cast to anything, it is valid 
to call the function in any condition).


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread deadalnix
On Wednesday, 27 March 2013 at 17:36:46 UTC, Steven Schveighoffer 
wrote:
On Wed, 27 Mar 2013 13:32:06 -0400, deadalnix 
deadal...@gmail.com wrote:


On Wednesday, 27 March 2013 at 16:52:27 UTC, Nick Sabalausky 
wrote:
Honestly, I hate that, too. The problem is that enum is 
(unfortunately)
intended to do double-duty as a bitfield so you can do 
something like

this:

enum Options
{
   FeatureA = 0b_0001;
   FeatureB = 0b_0010;
   FeatureC = 0b_0100;
   FeatureD = 0b_1000;
   // etc...
}

// Use features A and C
auto myOptions = Options.FeatureA | Options.FeatureC;

That possibility means that D *can't* check for validity as 
you suggest.




It can. myOptions is an int here, as Options would decay to 
its base type.


No, it's not.  try it.  I thought as you did too until recently.



I knew the bug existed, but I thought it would be solved now. If 
it is how the spec specify it, then it is a spec bug and a 
compiler bug.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 18:32:06 +0100
deadalnix deadal...@gmail.com wrote:

 On Wednesday, 27 March 2013 at 16:52:27 UTC, Nick Sabalausky 
 wrote:
  Honestly, I hate that, too. The problem is that enum is 
  (unfortunately)
  intended to do double-duty as a bitfield so you can do 
  something like
  this:
 
  enum Options
  {
  FeatureA = 0b_0001;
  FeatureB = 0b_0010;
  FeatureC = 0b_0100;
  FeatureD = 0b_1000;
  // etc...
  }
 
  // Use features A and C
  auto myOptions = Options.FeatureA | Options.FeatureC;
 
  That possibility means that D *can't* check for validity as you 
  suggest.
 
 
 It can. myOptions is an int here, as Options would decay to its 
 base type.

Options myOptions = Options.FeatureA | Options.FeatureC;



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread bearophile

Nick Sabalausky:


enum Options
{
FeatureA = 0b_0001;
FeatureB = 0b_0010;
FeatureC = 0b_0100;
FeatureD = 0b_1000;
// etc...
}

// Use features A and C
auto myOptions = Options.FeatureA | Options.FeatureC;

That possibility means that D *can't* check for validity as you 
suggest.


I'm convinced that scenario *should* be considered an entirely 
separate
thing because cramming it together with regular enumerations 
creates
conflicting goals with the two usages of enum, and forces 
unfortunate

design compromises with both.


This was discussed in past. A library code BitFlags similar to 
struct bitfields is probably able to solve most of this problem 
in a mostly type safe way. If you want a built-in solution, with 
a @bitflags, you will have to wait longer.


Bye,
bearophile


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 10:05:08 -0700
H. S. Teoh hst...@quickfur.ath.cx wrote:

 On Wed, Mar 27, 2013 at 04:34:19PM +0100, Vidar Wahlberg wrote:
 [...]
 
  - Foo foo = new Foo(); for global variables/class members. Now you
  must Foo foo; static this() { foo = new Foo(); }.
 
 Yeah, this is an irksome limitation. Though, it does have the benefit
 of not letting you do something that incurs runtime-cost without being
 explicit about it. Still, it is cumbersome to have to use static
 this() all over the place. It would be nice for the compiler to
 automatically lower such things into implicit ctor calls.
 

I wouldn't want such things to be implicitly converted to static ctors
unless the cyclic dependency issue was somehow ironed out.

I don't mind initializers of mutable vars being implicitly run at
runtime (that convenience would certainly be nice), but I definitely
don't want cyclic dependency error being triggered by something so
innocent-looking.



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 01:59:13PM -0400, Nick Sabalausky wrote:
 On Wed, 27 Mar 2013 10:05:08 -0700
 H. S. Teoh hst...@quickfur.ath.cx wrote:
 
  On Wed, Mar 27, 2013 at 04:34:19PM +0100, Vidar Wahlberg wrote:
  [...]
  
   - Foo foo = new Foo(); for global variables/class members. Now you
   must Foo foo; static this() { foo = new Foo(); }.
  
  Yeah, this is an irksome limitation. Though, it does have the
  benefit of not letting you do something that incurs runtime-cost
  without being explicit about it. Still, it is cumbersome to have to
  use static this() all over the place. It would be nice for the
  compiler to automatically lower such things into implicit ctor
  calls.
  
 
 I wouldn't want such things to be implicitly converted to static ctors
 unless the cyclic dependency issue was somehow ironed out.

True.


 I don't mind initializers of mutable vars being implicitly run at
 runtime (that convenience would certainly be nice), but I definitely
 don't want cyclic dependency error being triggered by something so
 innocent-looking.

I wonder if it would solve the problem if different instances of static
ctors in the same module are regarded as separate entities with their
own dependencies, so that you won't get a cyclic dependency error unless
there's truly an irreducible cyclic dependency. That is, cyclic
dependency errors shouldn't happen just because *one* static ctor
depends on stuff that indirectly depends on one of the 20 other static
ctors.

Don't know if this will cause conflicts with the current way module
dependencies work, though.


T

-- 
Кто везде - тот нигде.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 13:08:19 -0400
 
 I just tested it, it works on enum *strings*, but not enum *values*
 
 For example:
 
 import std.conv;
 
 enum X {
   i, j, k
 }
 
 void main()
 {
 X x = to!X(i); // works!
 x = to!X(1); // fails!
 }
 

Works for me on 2.063 Win. Keep in mind:

assert(cast(int)X.i == 0);
assert(cast(int)X.j == 1);



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Vidar Wahlberg
I'm impressed and most grateful for the feedback, I've learned 
some new things today :)



int i = 5;
auto foo = new int[][](i,i);


Won't this create an array (with 5 elements) of arrays (with 5 
elements), also called a jagged array? Where memory is not 
necessarily continuously allocated and looking up values adds 
another layer of indirection?



It is much more simple actually, typeof(match(string.init, 
Regex.init)) variable; and no extra functions or source 
digging is needed.


Many of you pointed this out, thanks, this a better solution than 
what I had. I needed to write Regex!char.init and not just 
Regex.init, but that's just a minor detail.




Yea, I'd imagine there would be some value-type/reference-type
confusion from a lot of newcomers just because D *has* both 
value types
and reference types. As opposed to, say, Java where (almost?) 
everything
is a reference type, or C++ where everything is a value type, 
etc.


Personally, I find it very much worthwhile to have both value 
and
reference types. But you're right it is something many people 
will have

to learn to get used to, and particularly so with arrays.


I find it quite nice that you have both value and reference 
types, and for the most part it's rather clear in D when you're 
dealing with a reference and when you're dealing with a value. It 
was just arrays that caught me off guard, and I think others with 
a similar background may do the same mistake, so my comment about 
this really just is arrays may require more explanation aimed at 
Java developers :)




But D has an easy solution - just use RDMD instead:

rdmd --build-only -I{include paths as usual} {other flags} 
main.d


That's a good tip! Somehow I had the notion that rdmd was purely 
a tool for scripting, as in dynamically parsing code (like 
Python, Perl, etc), so I never looked much into it.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 14:07:27 -0400
Nick Sabalausky seewebsitetocontac...@semitwist.com wrote:

 On Wed, 27 Mar 2013 13:08:19 -0400
  
  I just tested it, it works on enum *strings*, but not enum *values*
  
  For example:
  
  import std.conv;
  
  enum X {
i, j, k
  }
  
  void main()
  {
  X x = to!X(i); // works!
  x = to!X(1); // fails!
  }
  
 
 Works for me on 2.063 Win. Keep in mind:
 
 assert(cast(int)X.i == 0);
 assert(cast(int)X.j == 1);
 

I meant of course 2.062



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 07:06:45PM +0100, Vidar Wahlberg wrote:
[...]
 Yea, I'd imagine there would be some value-type/reference-type
 confusion from a lot of newcomers just because D *has* both value
 types and reference types. As opposed to, say, Java where (almost?)
 everything is a reference type, or C++ where everything is a value
 type, etc.
 
 Personally, I find it very much worthwhile to have both value and
 reference types. But you're right it is something many people will
 have to learn to get used to, and particularly so with arrays.
 
 I find it quite nice that you have both value and reference types, and
 for the most part it's rather clear in D when you're dealing with a
 reference and when you're dealing with a value. It was just arrays
 that caught me off guard, and I think others with a similar background
 may do the same mistake, so my comment about this really just is
 arrays may require more explanation aimed at Java developers :)

Yeah, the documentation needs to be improved. Maybe file an enhancement
bug for this at d.puremagic.com/issues ?


 But D has an easy solution - just use RDMD instead:
 
 rdmd --build-only -I{include paths as usual} {other flags} main.d
 
 That's a good tip! Somehow I had the notion that rdmd was purely a
 tool for scripting, as in dynamically parsing code (like Python,
 Perl, etc), so I never looked much into it.

rdmd gives D a scripting-like interface, but D is inherently a compiled
language, so it isn't actually a D interpreter. :) It's just that D
compilation (esp. with DMD) is incredibly fast, given what it does, so
that calling rdmd is almost like interpreting D code on-the-fly.

What it actually does, of course, is to compile the code and cache the
compiled objects, so running it multiple times does not repeatedly incur
the compile-time overhead.


T

-- 
Caffeine underflow. Brain dumped.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Andrei Alexandrescu

On 3/27/13 1:23 PM, Timon Gehr wrote:

- Function that never return are inferred void. I would have preferred
typeof(null) as void lead to many static and repetitive code for nothing
when doing metaprograming.


I strongly disagree.


Ideally such function should return a none type, the bottom of the 
hierarchy lattice. We don't have such, so returning typeof(null) (which 
we do have) is the next best choice as it's just above bottom.


Andrei


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Jesse Phillips

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg wrote:
I know I'm probably going to upset some people with this, 
bashing their favourite child and all, but I wanted to let you 
know the experience I've had with D so far, as a novice D coder 
with a heavy Java  light C++ background.


I think D has quite a strong set of critic users, namely because 
the benefits are just too great.


Not to suggest less importance to these issues, but these are 
known issues. It is good to have them brought up from the new 
user perspective.



Woes:
-
- I find myself in a world of pain when I want to share data


I don't use this, but my understanding is that 'shared' is a low 
level feature. In general one doing threading should never touch 
it and instead a library is built from it.


The problem is we don't have a good threading library, we have 
parallelism and concurrency which may use threads but not always 
what one would expect when looking for threading.


I could be completely wrong here!

- While the auto-keyword often is great, it can lead to 
difficulties, especially when used as the return type of a 
function, such as auto foo() { return bar; }. Sometimes you 
may wish to store the result of a function/method call as a 
global variable/class member, but when the function/method 
returns auto it's not apparent what the data type may be.


My observation is that many times in D the type is something you 
probably don't want to write out even if you know it. Using 
typeof() tends to be a better choice even if it isn't straight 
forward.



Gotchas:

- The lack of rectangular arrays created at runtime in D 
(int i = 5; int[i][i] foo;) can be quite confusing for 
programmers with Java or C++ background.


Well in this case you are trying to create a static 2D array with 
a runtime value.


I haven't had issues with 2D arrays, but I'm not familiar with 
rectangular arrays.


- Static array versus dynamic array was one of the first traps 
I stepped on


Static arrays are very hidden. Much like arrays are hidden in C.

- When casting a value to an enum, there's no checking that the 
value actually is a valid enum value. Don't think I ever found 
a solution on how to check whether the value after casting is a 
valid enum value, it hasn't been a pressing issue.


This would be nice, but enum's are also nice for binary flags.

auto option = My.A | My.B | My.C;

option would be a valid My for how it is used, but it is not 
defined as valid. There has been discussions on alternatives to 
using an enum (but enum is convenient).


- Compiling where DMD can't find all modules cause a rather 
cryptic error message. A solution is to make sure you specify 
all source files when compiling.


The compile = link process is pretty well hidden in most 
languages these days (many don't have it).



Wishlist:
-
- void[T] associative array (i.e. a set) would be nice, can 
be achieved with byte[0][T].


I think a proper library container would be fine.

- Foo foo = new Foo(); for global variables/class members. 
Now you must Foo foo; static this() { foo = new Foo(); }.


This won't happen. It is kind of a feature. Otherwise you'd be 
confused with the static this dependency error because I'm not 
using static this.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread John Colvin

On Wednesday, 27 March 2013 at 18:06:46 UTC, Vidar Wahlberg wrote:
I'm impressed and most grateful for the feedback, I've learned 
some new things today :)



int i = 5;
auto foo = new int[][](i,i);


Won't this create an array (with 5 elements) of arrays (with 5 
elements), also called a jagged array? Where memory is not 
necessarily continuously allocated and looking up values adds 
another layer of indirection?




Unfortunately yes.

However, it's not a hard problem to overcome with a wrapper 
struct over a contiguous array.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 18:46:09 +0100
deadalnix deadal...@gmail.com wrote:

 On Wednesday, 27 March 2013 at 17:23:01 UTC, Timon Gehr wrote:
  I strongly disagree. What would be an example of the problems 
  you are apparently experiencing?
 
 
 T foo(alias fallback)() {
  // Do some processing return the result. If an error occurs 
 use fallback mechanism.
 }
 
 Reasonable thing to do as fallback is to try another method 
 workaround the error, throw, whatever.
 
 The problem is that the fallback type inference makes it painful 
 to work with, especially if fallback is a template itself.
 
 For instance, in SDC, you can parse ambiguous things as follow :
 parseTypeOrExpression!((parsed) {
  static if(is(typeof(parsed) : Expression)) {
  // Do something
  } else {
  throw SomeException();
  }
 })(tokenRange);
 
 This is bound to fail. When a function never return, it make no 
 sens to force a type on it and the magic subtype typeof(null) 
 should be used (as typeof(null) can cast to anything, it is valid 
 to call the function in any condition).

A does not return return type would be nice for other things anyway.
For example:

void error(string s) // Convenience helper
{
throw new MyException(blah blah blah: ~s);
}

void serveFilesForever()
{
while(true)
listenAndRespond();
}

int doStuff()
{
if(blah)
return 1;
else if(blah2)
{
// Bullshit compile error:
// Not all paths return a value
error(poop);

// Must add dead code, keep compiler happy:
//assert(0);
}
else
{
// Same bullshit
serveFilesForever();
//assert(0);
}
}

Compare to:

no_return error() // Convenience helper
{
//if(foo) return; // Oops! But compiler catches error.

throw new MyException(blah blah blah);
}

no_return serveFilesForever()
{
// This might be harder for the compiler to check :(
while(true)
listenAndRespond();
}

int doStuff()
{
if(blah)
return 1;
else if(blah2)
error(poop); // No bullshit, just works
else
serveFilesForever(); // Whee!
}



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 07:41:42PM +0100, John Colvin wrote:
 On Wednesday, 27 March 2013 at 18:06:46 UTC, Vidar Wahlberg wrote:
 I'm impressed and most grateful for the feedback, I've learned
 some new things today :)
 
 int i = 5;
 auto foo = new int[][](i,i);
 
 Won't this create an array (with 5 elements) of arrays (with 5
 elements), also called a jagged array? Where memory is not
 necessarily continuously allocated and looking up values adds
 another layer of indirection?
 
 
 Unfortunately yes.
 
 However, it's not a hard problem to overcome with a wrapper struct
 over a contiguous array.

Which is what Denis' multidimensional array implementation does. As does
my implementation as well.

This seems to be quite a common use-case; we should put this into Phobos
IMO.


T

-- 
People tell me that I'm skeptical, but I don't believe it.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Nick Sabalausky
On Wed, 27 Mar 2013 11:13:31 -0700
H. S. Teoh hst...@quickfur.ath.cx wrote:

 On Wed, Mar 27, 2013 at 07:06:45PM +0100, Vidar Wahlberg wrote:
 [...]
  
  I find it quite nice that you have both value and reference types,
  and for the most part it's rather clear in D when you're dealing
  with a reference and when you're dealing with a value. It was just
  arrays that caught me off guard, and I think others with a similar
  background may do the same mistake, so my comment about this really
  just is arrays may require more explanation aimed at Java
  developers :)

Yea, the arrays definitely do blur the value/reference lines. Aside
from static/dynamic, another example of this is how a dynamic array's
*values* are reference, but it's length is by-value. Of course, it's
very simple when you realize that a D dynamic array is more-or-less
like this:

struct Array(T)
{
size_t length;
T* ptr;
}

But still, it's definitely something to get used to.

  But D has an easy solution - just use RDMD instead:
  
  rdmd --build-only -I{include paths as usual} {other flags} main.d
  
  That's a good tip! Somehow I had the notion that rdmd was purely a
  tool for scripting, as in dynamically parsing code (like Python,
  Perl, etc), so I never looked much into it.

It was originally designed for scripting uses. But making that work
well required adding the feature of *automatically* detect and compile
all required sources. And that feature turned out to be very useful
just for its own sake, so RDMD grew into something that could nicely
handle both.

 
 rdmd gives D a scripting-like interface, but D is inherently a
 compiled language, so it isn't actually a D interpreter. :) 

Sure it is! It's an AOT interpreter!

(Which is ironically something very well-respected and sought-after in
interpreted-language circles. Go figure: they've reinvented native
compilation and simply gave it a new name.)



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Dmitry Olshansky

27-Mar-2013 19:34, Vidar Wahlberg пишет:

I know I'm probably going to upset some people with this, bashing their
favourite child and all, but I wanted to let you know the experience
I've had with D so far, as a novice D coder with a heavy Java  light
C++ background.
It's not that I dislike D, in fact there are tons of things I love about
it, it's pretty much exactly what I'm looking for in a programming
language at the moment. Yet, I encounter some frustrating issues when
coding, often leaving me with the impression that I'm fighting the
language more than the problem I'm trying to solve.
True, there are many things I don't know about D, compilers or the inner
workings of a computer, and some of the fights I have with the language
are likely started by myself because I'm dragging along my bias from
other languages, drawing misconceptions on how the D language actually
works.
My intentions are not to insult, but shed some light on some of the
difficulties I've faced (and how I solved them), with the hope that it
will help others from facing the same difficulties.


Woes:
-
- I find myself in a world of pain when I want to share data more
complex than the basic data types (int, char, byte, etc) across threads.
Seemingly the magic trick is to cast(shared) foo (or
cast(immutable)) when passing objects/references to another thread,
then cast(Foo) back on the receiving end (as most classes/structs in
the standard library refuse to let you call any methods when the object
is shared). The examples in the source and TDPL are fairly limited on
the issue, it mostly covers only those basic data types.

- While the auto-keyword often is great, it can lead to difficulties,
especially when used as the return type of a function, such as auto
foo() { return bar; }. Sometimes you may wish to store the result of a
function/method call as a global variable/class member, but when the
function/method returns auto it's not apparent what the data type may
be. While you may be able to find out what bar is by digging in the
source code, it can still be difficult to find. One example is to save
the result of std.regex.match() as a member in a class. For me the
solution was to import std.traits, create a function auto
matchText(string text) { return match(text, myRegex); } and define the
class member as ReturnType!matchText matchResult; (do also note that
function  member must come in the right order for this to compile).


Currently documentation for match states in plain text that:
 ...
Returns:
a RegexMatch object holding engine state after first match.

Where RegexMatch is a template to be found in the the same module. I can 
see that docs are nothing stellar but the key info is present.


That being said I see no problem with ReturnType!xyz, typeof(smth) or 
just typing auto.



This was all but obvious to a novice D coder as myself, the solution was
suggested to me in the IRC channel.


Gotchas:

- The lack of rectangular arrays created at runtime in D (int i = 5;
int[i][i] foo;) can be quite confusing for programmers with Java or C++
background.


The code you suggested doesn't work in both C and Java.


Even though there exists alternatives
(http://denis-sh.github.com/phobos-additions/unstd.multidimensionalarray.html),
this design decision and how to get around it when you really desire a
rectangular array could be explained in more detail at
http://dlang.org/arrays.html.



IRC you can get jagged arrays with the syntax:
int[][] arr = new int[][](x,y);




- Compiling where DMD can't find all modules cause a rather cryptic
error message. A solution is to make sure you specify all source files
when compiling.


Linker... there are many ways to improve on that old technology that but 
not much have been done. And the problem is not D specific.


There is a tool rdmd that tracks all dependencies:

rdmd main_module.d

That plus:
rdmd --build-only main_module.d

Is more then enough in 90% of cases for me.


Wishlist:
-
- void[T] associative array (i.e. a set) would be nice, can be
achieved with byte[0][T].


We need a better set anyway as hash-map is a good map but suboptimal as 
a set.



--
Dmitry Olshansky


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Andrei Alexandrescu

On 3/27/13 11:34 AM, Vidar Wahlberg wrote:

I know I'm probably going to upset some people with this, bashing their
favourite child and all, but I wanted to let you know the experience
I've had with D so far, as a novice D coder with a heavy Java  light
C++ background.

[snip]

We're very interested (and therefore grateful) in hearing experience 
reports.


There have been a number of responses already so I'll just insert a 
couple of brief points.


* The MSB I'm seeing for all of these grievances is that we must improve 
our documentation.


* We used to have reference semantics for static arrays, it was a nightmare.

* As mentioned, shared is a last-resort, intentionally limited of 
communicating between threads. We must improve our message passing 
infrastructure (including documentation and examples). Definitely we 
must finish all details of what shared means (and doesn't). This remains 
largely an educational issue because people coming from share-intensive 
language expect to use shared casually (much as seasoned C++ users 
expected to use const casually; this particular issue has been largely 
resolved).


* We need to have a battery of multidimensional array shapes along with 
simple iteration and access primitives, at least for interfacing with 
scientific libraries that define and expect such formats. I'm thinking 
rectangular (generally hyperrectangular) matrices, triangular matrices, 
sparse matrices, and band matrices.


Thanks again for sharing your thoughts.


Andrei


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Andrei Alexandrescu

On 3/27/13 3:18 PM, H. S. Teoh wrote:

Which is what Denis' multidimensional array implementation does. As does
my implementation as well.

This seems to be quite a common use-case; we should put this into Phobos
IMO.


Agree. Do you (or Denis) have something in reviewable form?

Andrei


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Steven Schveighoffer
On Wed, 27 Mar 2013 14:09:07 -0400, Nick Sabalausky  
seewebsitetocontac...@semitwist.com wrote:



On Wed, 27 Mar 2013 14:07:27 -0400
Nick Sabalausky seewebsitetocontac...@semitwist.com wrote:


On Wed, 27 Mar 2013 13:08:19 -0400

 I just tested it, it works on enum *strings*, but not enum *values*

 For example:

 import std.conv;

 enum X {
   i, j, k
 }

 void main()
 {
 X x = to!X(i); // works!
 x = to!X(1); // fails!
 }


Works for me on 2.063 Win. Keep in mind:

assert(cast(int)X.i == 0);
assert(cast(int)X.j == 1);



I meant of course 2.062



Hah, I have not yet downloaded 2.062.  It did not work in 2.061, not sure  
if that was a bug or it's a new feature.


anyway, that is good to know!

-Steve


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 04:28:16PM -0400, Andrei Alexandrescu wrote:
 On 3/27/13 3:18 PM, H. S. Teoh wrote:
 Which is what Denis' multidimensional array implementation does. As does
 my implementation as well.
 
 This seems to be quite a common use-case; we should put this into Phobos
 IMO.
 
 Agree. Do you (or Denis) have something in reviewable form?

Here is Denis' implementation:

https://github.com/denis-sh/phobos-additions/blob/master/unstd/multidimensionalarray.d

As I didn't write the code, I can't say how review-ready it is.

My own implementation is somewhat incomplete at this time, so it's not
quite ready for review yet. It's missing some functionality that Denis'
implementation has (arbitrary index reordering, more complete
range-based access, opApply, etc.).


T

-- 
EMACS = Extremely Massive And Cumbersome System


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread H. S. Teoh
On Wed, Mar 27, 2013 at 04:22:00PM -0400, Andrei Alexandrescu wrote:
[...]
 * We need to have a battery of multidimensional array shapes along
 with simple iteration and access primitives, at least for interfacing
 with scientific libraries that define and expect such formats. I'm
 thinking rectangular (generally hyperrectangular) matrices, triangular
 matrices, sparse matrices, and band matrices.
[...]

Given that different computational needs will require different
implementations, it might be a good idea to define a generic set of
templates for identifying something as a multi-dimensional array, and
adopt some conventions as to how things are named (e.g., .dimensions[i]
to retrieve the length of the i'th dimension of the array, or the fact
that .opIndex(a,b,c,...) is defined, etc.).

The idea is that we want to implement some generic array algorithms that
don't care about whether it's a dense array, triangular matrix, sparse
array, etc.. These should be independent of the actual storage format.

There are, of course, algorithms that will benefit from specific
implementations (e.g. algorithms that take advantage of the sparseness
of a matrix, say), so those will specificially depend on, say, a sparse
array.

Generic identification of array types is also necessary to maximize
interoperability between computational libraries. For one thing, I do
*not* wish to see a repeat of the C++ situation where the
multidimensional array types between different libraries are
incompatible and require expensive copying and/or layers upon layers of
wrappers just to interoperate. The situation in D should be such that
any library's array type should be interoperable with any other
library's array type, as long as both satisfy the standard
array-identification templates.

In a nutshell, multidimensional arrays should have a standard API so
that any multidimensional array can be used with any algorithm that
expects one.


T

-- 
Always remember that you are unique. Just like everybody else. -- despair.com


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Timon Gehr

On 03/27/2013 06:34 PM, Brad Anderson wrote:

On Wednesday, 27 March 2013 at 17:23:01 UTC, Timon Gehr wrote:

On 03/27/2013 05:04 PM, deadalnix wrote:

On Wednesday, 27 March 2013 at 15:34:20 UTC, Vidar Wahlberg

...
- Foo foo = new Foo(); for global variables/class members. Now you
must Foo foo; static this() { foo = new Foo(); }.


Yes, as it imply an heap allocation. It is an harder problem that it
seems as all thoses object could reference themselves.


Just serialize the CTFE object graph into the static data segment.


I believe that's what this pull aims to do:

https://github.com/D-Programming-Language/dmd/pull/1724


Almost. It does not support TLS, which is a severe limitation.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Timon Gehr

On 03/27/2013 06:46 PM, deadalnix wrote:

On Wednesday, 27 March 2013 at 17:23:01 UTC, Timon Gehr wrote:

I strongly disagree. What would be an example of the problems you are
apparently experiencing?



T foo(alias fallback)() {
 // Do some processing return the result. If an error occurs use
fallback mechanism.
}

Reasonable thing to do as fallback is to try another method workaround
the error, throw, whatever.

The problem is that the fallback type inference makes it painful to work
with, especially if fallback is a template itself.

For instance, in SDC, you can parse ambiguous things as follow :
parseTypeOrExpression!((parsed) {
 static if(is(typeof(parsed) : Expression)) {
 // Do something
 } else {
 throw SomeException();
 }
})(tokenRange);



I see. What is needed is a way to specify that a function does never 
return. (eg. a bottom type)



This is bound to fail. When a function never return, it make no sens to
force a type on it and the magic subtype typeof(null) should be used (as
typeof(null) can cast to anything, it is valid to call the function in
any condition).


It cannot cast to everything.



Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread Timon Gehr

On 03/27/2013 07:20 PM, Andrei Alexandrescu wrote:

On 3/27/13 1:23 PM, Timon Gehr wrote:

- Function that never return are inferred void. I would have preferred
typeof(null) as void lead to many static and repetitive code for nothing
when doing metaprograming.


I strongly disagree.


Ideally such function should return a none type, the bottom of the
hierarchy lattice. We don't have such, so returning typeof(null) (which
we do have) is the next best choice as it's just above bottom.

Andrei


Maybe it is one next best choice. It is still a horrible choice.

It's not any more just above bottom than the following type:

struct JustAboveBottom{ }

We should either go with the real thing or do nothing about it.


Re: My thoughts experiences with D so far, as a novice D coder

2013-03-27 Thread deadalnix
On Wednesday, 27 March 2013 at 18:20:49 UTC, Andrei Alexandrescu 
wrote:

On 3/27/13 1:23 PM, Timon Gehr wrote:
- Function that never return are inferred void. I would have 
preferred
typeof(null) as void lead to many static and repetitive code 
for nothing

when doing metaprograming.


I strongly disagree.


Ideally such function should return a none type, the bottom 
of the hierarchy lattice. We don't have such, so returning 
typeof(null) (which we do have) is the next best choice as it's 
just above bottom.




I thought that typeof(null) was that bottom type. What is the 
difference ?


Anyway, void isn't the right choice here and is a pain to work 
with.