Jump to page: 1 27  
Page
Thread overview
My thoughts & experiences with D so far, as a novice D coder
Mar 27, 2013
Vidar Wahlberg
Mar 27, 2013
John Colvin
Mar 27, 2013
bearophile
Mar 27, 2013
H. S. Teoh
Mar 28, 2013
renoX
Mar 28, 2013
Vidar Wahlberg
Mar 28, 2013
H. S. Teoh
Mar 28, 2013
1100110
Mar 28, 2013
Chris Cain
Mar 28, 2013
Vidar Wahlberg
Mar 28, 2013
Chris Cain
Mar 28, 2013
Chris Cain
Mar 28, 2013
Chris Cain
Mar 28, 2013
Vidar Wahlberg
Mar 29, 2013
Jonathan M Davis
Mar 29, 2013
Vidar Wahlberg
Mar 29, 2013
Jonathan M Davis
Mar 29, 2013
Jesse Phillips
Mar 29, 2013
Jonathan M Davis
Mar 29, 2013
Jesse Phillips
Mar 29, 2013
Jonathan M Davis
Mar 27, 2013
deadalnix
Mar 27, 2013
Timon Gehr
Mar 27, 2013
Brad Anderson
Mar 27, 2013
Timon Gehr
Mar 27, 2013
deadalnix
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
Timon Gehr
Mar 27, 2013
Vidar Wahlberg
Mar 27, 2013
H. S. Teoh
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
John Colvin
Mar 27, 2013
H. S. Teoh
Mar 27, 2013
H. S. Teoh
Oct 08, 2013
Denis Shelomovskij
Mar 27, 2013
Timon Gehr
Mar 28, 2013
deadalnix
Mar 28, 2013
Timon Gehr
Mar 28, 2013
deadalnix
Mar 27, 2013
Dicebot
Mar 27, 2013
John Colvin
Mar 27, 2013
John Colvin
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
H. S. Teoh
Mar 27, 2013
deadalnix
Mar 27, 2013
deadalnix
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
bearophile
Mar 27, 2013
H. S. Teoh
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
H. S. Teoh
Mar 27, 2013
Nick Sabalausky
Mar 27, 2013
Nick Sabalausky
Mar 28, 2013
1100110
Mar 28, 2013
1100110
Mar 27, 2013
Jesse Phillips
Mar 27, 2013
Dmitry Olshansky
Mar 27, 2013
H. S. Teoh
Mar 28, 2013
Jacob Carlborg
March 27, 2013
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(); }".
March 27, 2013
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);
March 27, 2013
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
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.
> 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.
 - This is very GC unfriendly.

For instance, on a project at a previous work, we had an LRU cache into an application. We knew that most object should traverse the cache and get out very fast, when other will stick in it most of the time for reason that'd be too long to explain.

It lead to difficult to solve performances issues as while going through the LRU, object were considered as old by the GC and treated differently. As a consequence, the application generated a lot of garbage considered as old by the GC (when the GC assume that most objects dies young).

It required a lot of work to make that work, when using value type would have solved the whole this instantly.

> - 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.
>

Very true. enum as they stand have some safety issue IMO.

> - 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.
>

dmd is really uneven with error messages. Some are purely awesome, and other are completely cryptic. A very "funny" one is when you use import instead of module (dmd complain about the module conflicting with itself).

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

Don't get me started on AA !

> - "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.
March 27, 2013
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?
March 27, 2013
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.
March 27, 2013
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".
March 27, 2013
On Wed, 27 Mar 2013 16:34:19 +0100
"Vidar Wahlberg" <vidar.wahlberg@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 = 0b0000_0001;
    FeatureB = 0b0000_0010;
    FeatureC = 0b0000_0100;
    FeatureD = 0b0000_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 HashSet(T)
{
    alias byte[0][T] HashSet;
}

Then just "HashSet!int", "HashSet!string", "HashSet!Foo", etc.


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


IMO, it's better to do lazy initialization:

private Foo _foo;
private bool fooInited;
@property ref Foo foo()
{
    if(!_foo && !fooInited)
    {
        _foo = new Foo();
        fooInited = true;
    }

    return _foo;
}

I prefer to avoid "static this()" because that makes it easy to end up with a "cyclic dependency" error on program startup. If two modules that import each other (directly or indirectly) both have a "static this()", then the runtime has no way to know which needs to run first, so it gives a cyclic dependency error instead. This lazy-initialization avoids that problem.

Of course, it certainly doesn't help with the convenience issue. But all that boilerplate could all be wrapped up in a reusable convenience mixin. I think that would be a great thing to have in Phobos.

March 27, 2013
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 myself needing such a type.


> - "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.


T

-- 
A bend in the road is not the end of the road unless you fail to make the turn. -- Brian White
March 27, 2013
On Wed, 27 Mar 2013 11:34:19 -0400, Vidar Wahlberg <vidar.wahlberg@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
« First   ‹ Prev
1 2 3 4 5 6 7