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

Nick Sabalausky SeeWebsiteToContactMe at semitwist.com
Wed Mar 27 09:52:25 PDT 2013


On Wed, 27 Mar 2013 16:34:19 +0100
"Vidar Wahlberg" <vidar.wahlberg at 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.



More information about the Digitalmars-d mailing list