March 27, 2013
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.
March 27, 2013
On Wed, 27 Mar 2013 11:13:31 -0700
"H. S. Teoh" <hsteoh@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.)

March 27, 2013
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
March 27, 2013
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
March 27, 2013
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
March 27, 2013
On Wed, 27 Mar 2013 14:09:07 -0400, Nick Sabalausky <SeeWebsiteToContactMe@semitwist.com> wrote:

> On Wed, 27 Mar 2013 14:07:27 -0400
> Nick Sabalausky <SeeWebsiteToContactMe@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
March 27, 2013
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
March 27, 2013
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
March 27, 2013
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.
March 27, 2013
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.