March 27, 2013
On Wed, 27 Mar 2013 10:05:08 -0700
"H. S. Teoh" <hsteoh@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.

March 27, 2013
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.
March 27, 2013
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);

March 27, 2013
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" <hsteoh@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

-- 
Кто везде - тот нигде.
March 27, 2013
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

March 27, 2013
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.
March 27, 2013
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
March 27, 2013
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."
March 27, 2013
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.
March 27, 2013
On Wed, 27 Mar 2013 18:46:09 +0100
"deadalnix" <deadalnix@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!
    }