Thread overview
First project: questions on how-to, and on language features
Jan 24, 2016
Alex Vincent
Jan 24, 2016
Marc Schütz
Jan 25, 2016
Ali Çehreli
Jan 24, 2016
Chris Wright
Feb 03, 2016
Alex Vincent
January 24, 2016
Source code:
https://alexvincent.us/d-language/samples/intervalmap-rev1.d.txt

After reading Ali Çehreli's book, "Programming in D", I wrote this little sample up as a starting point for my explorations into D.  I've long admired the D language, but I've never actually tried to write practical code in D.

So I wrote this little sample up in dlangide, and as I was going, I realized I had quite a few questions.

(1) It's not clear how to specify certain parts of a module or library as non-exportable.  Is that possible?  Is it desirable?  (It's not that important, yet, but still...)

(2) In the unittest code, I have a block that I want to rewrite using assertThrown, but I can't figure out from either the book or the website the correct usage.  What's the right way to specify a StringException with a particular message I expect to receive?

(3) How do I actually create a library in dub?  How does dub determine what files to build?

(4) How should the scope(exit) and scope(failure) guard statements intermix with preconditions and postconditions?

(5) My append() function has a postcondition that currently depends on debug-only members of the class being set in the precondition.  This seems artificial - not the part about setting these variables in the precondition, but having the variables defined on the class to begin with.  If they were defined only for the lifetime of the function's execution, starting in the precondition, this would be more natural.  Is there a Right Way to define function-only debug variables for use in postconditions?  If not, would this be a valid use-case to consider amending the language specification to clarify?

(6) Would someone please review my sample code and offer feedback?  :-)

(7) Naming:  This code is the start of a port of a mini-library I wrote in JavaScript which I called "ObjectRange".  However, in Phobos, the term "Range" has a very different meaning - in fact, almost the opposite meaning of what this code does.  I asked for a better name in the D IRC channel, and someone suggested Interval, based on the mathematical definition of the word.  IntervalMap seemed more accurate, since there is a payload to each interval.  Does the name make sense in the context?

(8) Is there a similar, more mature library out there which tries to achieve what I'm doing here?  I'm rather surprised I didn't see anything like it in the standard library...
January 24, 2016
On Sunday, 24 January 2016 at 06:07:13 UTC, Alex Vincent wrote:
> (1) It's not clear how to specify certain parts of a module or library as non-exportable.  Is that possible?  Is it desirable?
>  (It's not that important, yet, but still...)

Yes, definitely. By default symbols in a module are `public`, but you can mark them as `private`. These aren't accesible from other modules:

    module test;

    void foo() { }        // public, because there's no annotation
    private bar() { }     // private
    void bar2() { }       // public again

    private:              // everything from here on is private
    void bla() { }
    void blubb() { }

>
> (2) In the unittest code, I have a block that I want to rewrite using assertThrown, but I can't figure out from either the book or the website the correct usage.  What's the right way to specify a StringException with a particular message I expect to receive?

Here's the relevant documentation:
https://dlang.org/phobos/std_exception.html#.assertThrown
https://dlang.org/phobos/std_exception.html#.collectExceptionMsg

`assertThrown()` doesn't allow to check the message directly, it can only check whether a particular type of exception has been thrown:

    assertThrown!StringException(throw new StringException("test"));

Instead, you can use `collectExceptionMsg()` to check both the message and the exception type:

    assert(
        collectExceptionMsg!StringException(throw ...) == "test"
    );

>
> (4) How should the scope(exit) and scope(failure) guard statements intermix with preconditions and postconditions?

Pre- and postconditions are supposed to run before you enter the function, or after you left it, respectively. Therefore, and scope() blocks in the function body would already have completed when the postcondition is entered. OTOH, scope() blocks only run if control flow has passed through them. In a precondition, this hasn't happened yet, and therefore they will not run.

If you mean whether you can use scope() blocks in pre- and postconditions, yes, you can. The will then run when you leave the pre- and postcondition. But usually, pre- and postconditions only consist of very little code that's not supposed to do any serious work, so they are less likely to be used there.

Or, looking at it from a different angle: A scope() block only runs at the end of the lexical scope / block it appears in. Pre- and postconditions are not part of the function body, or vice versa. Therefore, see above.

>
> (5) My append() function has a postcondition that currently depends on debug-only members of the class being set in the precondition.  This seems artificial - not the part about setting these variables in the precondition, but having the variables defined on the class to begin with.  If they were defined only for the lifetime of the function's execution, starting in the precondition, this would be more natural.  Is there a Right Way to define function-only debug variables for use in postconditions?  If not, would this be a valid use-case to consider amending the language specification to clarify?

I'm not an expert in contract programming, but as I see it, your precondition doesn't actually check anything, you're kinda abusing them as preparation for your postcondition. That's likely not the way it's supposed to be. I see what you're trying to achieve, and I believe it's legitimate to check for... You could either just move the assert()s into the function body just before the end, where you have access to the local variables (but you could easily miss an early return), or put them into a scope(exit) block (but then you could accidentally check it too early). Your best bet here is probably to check it in a unittest, although they are for a slightly different purpose, strictly speaking.

January 24, 2016
On Sun, 24 Jan 2016 06:07:13 +0000, Alex Vincent wrote:

> Source code: https://alexvincent.us/d-language/samples/intervalmap-rev1.d.txt

There is no documentation, so I have no idea what you're trying to achieve here. So your questions about why this isn't in Phobos, whether there are any other libraries that do this, and whether there's a way to simplify your contracts are impossible for me to answer.

I notice you're using identifiers that start with double underscores. I'd recommend not making a habit of that. The compiler generates symbols for some things, and those symbols start with a double underscore.

For example:

  class Foo {
    this(int i) {}
    void __ctor(int i) {}
  }
  auto f = new Foo(1);

This produces an error like:

dubleuscore.d(13): Error: dubleuscore.Foo.__ctor called with argument
types (int) matches both:
dubleuscore.d(4):     dubleuscore.Foo.this(int i)
and:
dubleuscore.d(7):     dubleuscore.Foo.__ctor(int i)

The compiler can add more such identifiers without warning, which could break your code in interesting ways.

> After reading Ali Çehreli's book, "Programming in D", I wrote this little sample up as a starting point for my explorations into D.  I've long admired the D language, but I've never actually tried to write practical code in D.
> 
> So I wrote this little sample up in dlangide, and as I was going, I realized I had quite a few questions.
> 
> (1) It's not clear how to specify certain parts of a module or library
> as non-exportable.  Is that possible?  Is it desirable? (It's not that
> important, yet, but still...)

As Marc mentioned, the 'private' keyword. You can use it directly:

  private int f;
  int g;  // implicitly public

in blocks:

  private {
    int h;
    int i;
  }
  int j;  // implicitly public

or label style:

  private:
  int k;
  int m;
  public int n;  // have to explicitly mark anything else public

That's all module-local. If you need to restrict things to your package, you can use the 'package' keyword, which functions identically.

All these syntax variants work everywhere. I find it handy, for instance, to write my code like:

  class Foo {
    private {
      // fields go here
    }
    // everything else is generally public
  }

Aside from that, if you do not add a documentation comment to something, it will not be mentioned at all in the generated documentation. This makes it difficult for users to discover, in case you really need something to be public but don't want people to use it. But using 'package' rather than 'public' will usually suffice in those cases.

> (3) How do I actually create a library in dub?  How does dub determine
> what files to build?

I believe Dub includes all files by default.

> (4) How should the scope(exit) and scope(failure) guard statements
> intermix with preconditions and postconditions?

Marc answered this, but while we're on the topic of preconditions, I notice your usage of enforce:

  enforce(index > upperEdge, new StringException("index must be greater
than upperEdge"));

The idiom in use in Phobos is:

  enforce!StringException(index > upperEdge, "index must be greater than
upperEdge");
January 25, 2016
On 01/24/2016 04:26 AM, Marc Schütz wrote:

>> (2) In the unittest code, I have a block that I want to rewrite using
>> assertThrown, but I can't figure out from either the book or the
>> website the correct usage.  What's the right way to specify a
>> StringException with a particular message I expect to receive?
>
> Here's the relevant documentation:
> https://dlang.org/phobos/std_exception.html#.assertThrown
> https://dlang.org/phobos/std_exception.html#.collectExceptionMsg

Here is another link for completeness:


http://ddili.org/ders/d.en/unit_testing.html#ix_unit_testing.assertThrown,%20std.exception

Ali

February 03, 2016
On Sunday, 24 January 2016 at 18:52:41 UTC, Chris Wright wrote:
> There is no documentation, so I have no idea what you're trying to achieve here. So your questions about why this isn't in Phobos, whether there are any other libraries that do this, and whether there's a way to simplify your contracts are impossible for me to answer.

Objections have been noted and (hopefully) corrected:
https://github.com/ajvincent/d-experiments/blob/master/IntervalMap/source/intervalmap.d

I'm going for the concept of versioning data - first a single value, and then members of an array.  (I haven't implemented the versioning of arrays yet.)  That's why I said it's an inverse of Phobos ranges:  each iteration call to a range could give you a different value.  Here, several versions can point to one value.

Feedback is still most strongly welcomed.