www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - First project: questions on how-to, and on language features

reply Alex Vincent <ajvincent gmail.com> writes:
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...
Jan 23 2016
next sibling parent reply Marc =?UTF-8?B?U2Now7x0eg==?= <schuetzm gmx.net> writes:
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.
Jan 24 2016
parent =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
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
Jan 25 2016
prev sibling parent reply Chris Wright <dhasenan gmail.com> writes:
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");
Jan 24 2016
parent Alex Vincent <ajvincent gmail.com> writes:
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.
Feb 02 2016