www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Conflict between std.file write() and std.stdio write()

reply "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
Hello,
I have the following program:

import std.file;
import std.stdio;

void main( string[] args ) {
    string str = "Hello";
    write( "file.txt", str );

    string hello_file = readText("file.txt");

    writeln( hello_file );
}

When I try to compile this I get:

test.d(6): Error: std.stdio.write!(string, string).write at
/usr/include/dmd/phobos/std/stdio.d(1656) conflicts with
std.file.write at /usr/include/dmd/phobos/std/file.d(318)

I think this should work.  The example at the end of (D file I/0):

http://www.docwiki.net/view.php?pageid=145

Uses write() exactly the way I am using it here.

Cheers,

Craig
Oct 02 2013
next sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Wednesday, 2 October 2013 at 23:39:39 UTC, Craig Dillabaugh
wrote:
 Hello,
 I have the following program:

 import std.file;
 import std.stdio;

 void main( string[] args ) {
    string str = "Hello";
    write( "file.txt", str );

    string hello_file = readText("file.txt");

    writeln( hello_file );
 }

 When I try to compile this I get:

 test.d(6): Error: std.stdio.write!(string, string).write at
 /usr/include/dmd/phobos/std/stdio.d(1656) conflicts with
 std.file.write at /usr/include/dmd/phobos/std/file.d(318)

 I think this should work.  The example at the end of (D file 
 I/0):

 http://www.docwiki.net/view.php?pageid=145

 Uses write() exactly the way I am using it here.

 Cheers,

 Craig
D compiler DMD 2.063.2
Oct 02 2013
prev sibling next sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, October 03, 2013 01:39:38 Craig Dillabaugh wrote:
 Hello,
 I have the following program:
 
 import std.file;
 import std.stdio;
 
 void main( string[] args ) {
 string str = "Hello";
 write( "file.txt", str );
 
 string hello_file = readText("file.txt");
 
 writeln( hello_file );
 }
 
 When I try to compile this I get:
 
 test.d(6): Error: std.stdio.write!(string, string).write at
 /usr/include/dmd/phobos/std/stdio.d(1656) conflicts with
 std.file.write at /usr/include/dmd/phobos/std/file.d(318)
 
 I think this should work. The example at the end of (D file I/0):
 
 http://www.docwiki.net/view.php?pageid=145
 
 Uses write() exactly the way I am using it here.
You have to give the full path - std.file.write. As both functions can take the same arguments, and you've imported both, the compiler has no way of knowing which you mean. So, you have to disambiguate for it. It's only a problem because you imported both modules. - Jonathan M Davis
Oct 02 2013
next sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Thursday, 3 October 2013 at 00:04:31 UTC, Jonathan M Davis
wrote:
 On Thursday, October 03, 2013 01:39:38 Craig Dillabaugh wrote:
 Hello,
 I have the following program:
 
 import std.file;
 import std.stdio;
 
 void main( string[] args ) {
 string str = "Hello";
 write( "file.txt", str );
 
 string hello_file = readText("file.txt");
 
 writeln( hello_file );
 }
 
 When I try to compile this I get:
 
 test.d(6): Error: std.stdio.write!(string, string).write at
 /usr/include/dmd/phobos/std/stdio.d(1656) conflicts with
 std.file.write at /usr/include/dmd/phobos/std/file.d(318)
 
 I think this should work. The example at the end of (D file 
 I/0):
 
 http://www.docwiki.net/view.php?pageid=145
 
 Uses write() exactly the way I am using it here.
You have to give the full path - std.file.write. As both functions can take the same arguments, and you've imported both, the compiler has no way of knowing which you mean. So, you have to disambiguate for it. It's only a problem because you imported both modules. - Jonathan M Davis
Thanks. Seems kind of an odd design decision (or oversight) that two commonly used functions in the standard library would clash in this manner, but I guess it is no big deal. Cheers, Craig
Oct 02 2013
prev sibling parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Thursday, 3 October 2013 at 00:04:31 UTC, Jonathan M Davis
wrote:
 On Thursday, October 03, 2013 01:39:38 Craig Dillabaugh wrote:
 Hello,
 I have the following program:
 
 import std.file;
 import std.stdio;
 
 void main( string[] args ) {
 string str = "Hello";
 write( "file.txt", str );
 
 string hello_file = readText("file.txt");
 
 writeln( hello_file );
 }
 
 When I try to compile this I get:
 
 test.d(6): Error: std.stdio.write!(string, string).write at
 /usr/include/dmd/phobos/std/stdio.d(1656) conflicts with
 std.file.write at /usr/include/dmd/phobos/std/file.d(318)
 
 I think this should work. The example at the end of (D file 
 I/0):
 
 http://www.docwiki.net/view.php?pageid=145
 
 Uses write() exactly the way I am using it here.
You have to give the full path - std.file.write. As both functions can take the same arguments, and you've imported both, the compiler has no way of knowing which you mean. So, you have to disambiguate for it. It's only a problem because you imported both modules. - Jonathan M Davis
Thanks. Seems kind of an odd design decision (or oversight) that two commonly used functions in the standard library would clash in this manner, but I guess it is no big deal. Cheers, Craig
Oct 02 2013
prev sibling parent reply Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 10/3/13, Craig Dillabaugh <cdillaba cg.scs.carleton.ca> wrote:
 void main( string[] args ) {
     string str = "Hello";
     write( "file.txt", str );

     string hello_file = readText("file.txt");

     writeln( hello_file );
 }
You can also disambiguate by preferring one symbol over another with an alias: alias write = std.file.write; void main( string[] args ) { string str = "Hello"; write( "file.txt", str ); } You can also put the alias inside the function.
Oct 02 2013
parent reply "Craig Dillabaugh" <craig.dillabaugh gmail.com> writes:
On Thursday, 3 October 2013 at 02:57:50 UTC, Andrej Mitrovic
wrote:
 On 10/3/13, Craig Dillabaugh <cdillaba cg.scs.carleton.ca> 
 wrote:
 void main( string[] args ) {
     string str = "Hello";
     write( "file.txt", str );

     string hello_file = readText("file.txt");

     writeln( hello_file );
 }
You can also disambiguate by preferring one symbol over another with an alias: alias write = std.file.write; void main( string[] args ) { string str = "Hello"; write( "file.txt", str ); } You can also put the alias inside the function.
Thanks. It seems that std.file should include a writeText() function for the sake of consistency that is the above alias. When you come across readText() in the documentation you sort of expect that such a function would exist, and then you spot write() below it, and think hey that does what I need. Then you hit upon the syntax error if you are also using std.stdio (which is a very commonly used module). Adding writeText() doesn't really add much to the library, but having to jump through hoops (as minor as they may be) to perform such a simple op is a bit of a pain for people new to the language. Craig
Oct 03 2013
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, October 03, 2013 15:22:28 Craig Dillabaugh wrote:
 It seems that std.file should include a writeText() function for
 the sake of consistency that is the above alias. When you come
 across readText() in the documentation you sort of expect that
 such a function would exist, and then you spot write() below it,
 and think hey that does what I need. Then you hit upon the
 syntax error if you are also using std.stdio (which is a very
 commonly used module).
 
 Adding writeText() doesn't really add much to the library, but
 having to jump through hoops (as minor as they may be) to perform
 such a simple op is a bit of a pain for people new to the
 language.
writeText would be redundant. write will already write arbitrary data to a file - including strings. writeText would add no functionality. Functions should add actual value, or they just clutter up the library. Conflicting functions is just part of life. The module system is designed to let you disambiguate them. We're not going to try and make all of the function names unique just because you might import a module with a conflicting function. If write is the best name for the function, then that's what we'll use, even if it conflicts with a function in another module. To do otherwise would be to ignore the features of the module system and force us to come up with worse names just to avoid conflicts. - Jonathan M Davis
Oct 03 2013
next sibling parent 1100110 <0b1100110 gmail.com> writes:
On 10/03/2013 01:11 PM, Jonathan M Davis wrote:
 On Thursday, October 03, 2013 15:22:28 Craig Dillabaugh wrote:
 It seems that std.file should include a writeText() function for
 the sake of consistency that is the above alias. When you come
 across readText() in the documentation you sort of expect that
 such a function would exist, and then you spot write() below it,
 and think hey that does what I need. Then you hit upon the
 syntax error if you are also using std.stdio (which is a very
 commonly used module).

 Adding writeText() doesn't really add much to the library, but
 having to jump through hoops (as minor as they may be) to perform
 such a simple op is a bit of a pain for people new to the
 language.
writeText would be redundant. write will already write arbitrary data to a file - including strings. writeText would add no functionality. Functions should add actual value, or they just clutter up the library. Conflicting functions is just part of life. The module system is designed to let you disambiguate them. We're not going to try and make all of the function names unique just because you might import a module with a conflicting function. If write is the best name for the function, then that's what we'll use, even if it conflicts with a function in another module. To do otherwise would be to ignore the features of the module system and force us to come up with worse names just to avoid conflicts. - Jonathan M Davis
I *like* the fact I only have to remember one API. A simple alias or disambiguation every once in a while is well worth it IMHO.
Oct 03 2013
prev sibling parent reply "Craig Dillabaugh" <craig.dillabaugh gmail.com> writes:
On Thursday, 3 October 2013 at 18:12:01 UTC, Jonathan M Davis 
wrote:
 On Thursday, October 03, 2013 15:22:28 Craig Dillabaugh wrote:
 It seems that std.file should include a writeText() function 
 for
 the sake of consistency that is the above alias. When you come
 across readText() in the documentation you sort of expect that
 such a function would exist, and then you spot write() below 
 it,
 and think hey that does what I need. Then you hit upon the
 syntax error if you are also using std.stdio (which is a very
 commonly used module).
 
 Adding writeText() doesn't really add much to the library, but
 having to jump through hoops (as minor as they may be) to 
 perform
 such a simple op is a bit of a pain for people new to the
 language.
writeText would be redundant. write will already write arbitrary data to a file - including strings. writeText would add no functionality. Functions should add actual value, or they just clutter up the library. Conflicting functions is just part of life. The module system is designed to let you disambiguate them. We're not going to try and make all of the function names unique just because you might import a module with a conflicting function. If write is the best name for the function, then that's what we'll use, even if it conflicts with a function in another module. To do otherwise would be to ignore the features of the module system and force us to come up with worse names just to avoid conflicts. - Jonathan M Davis
Fair enough. As you point out the fix is pretty simple. However, I can't seem to remember in C++ or any other language (not that I know all that many other languages) coming across a function in the standard library that conflicted with another function in the standard library in this way. I am likely to get corrected on that claim though :o) Maybe it would be worth noting this conflict in the documentations for newbies. Craig
Oct 03 2013
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Craig Dillabaugh:

 However, I can't seem to remember in C++ or any other language 
 (not that I know all that many other languages) coming across a 
 function in the standard library that conflicted with another 
 function in the standard library in this way.
Generally Phobos should be designed to avoid name clashes as much as possible. Because Phobos functions are used often, and because specifying fully the path of function doesn't play well with UFCS chains (unless you use Alias!(), but it's long to write). Recently one name clash, with "chunks", was removed from Phobos. Another clash, with "splitter", is currently worked on. Bye, bearophile
Oct 03 2013
prev sibling parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, October 03, 2013 20:57:20 Craig Dillabaugh wrote:
 On Thursday, 3 October 2013 at 18:12:01 UTC, Jonathan M Davis
 
 wrote:
 On Thursday, October 03, 2013 15:22:28 Craig Dillabaugh wrote:
 It seems that std.file should include a writeText() function
 for
 the sake of consistency that is the above alias. When you come
 across readText() in the documentation you sort of expect that
 such a function would exist, and then you spot write() below
 it,
 and think hey that does what I need. Then you hit upon the
 syntax error if you are also using std.stdio (which is a very
 commonly used module).
 
 Adding writeText() doesn't really add much to the library, but
 having to jump through hoops (as minor as they may be) to
 perform
 such a simple op is a bit of a pain for people new to the
 language.
writeText would be redundant. write will already write arbitrary data to a file - including strings. writeText would add no functionality. Functions should add actual value, or they just clutter up the library. Conflicting functions is just part of life. The module system is designed to let you disambiguate them. We're not going to try and make all of the function names unique just because you might import a module with a conflicting function. If write is the best name for the function, then that's what we'll use, even if it conflicts with a function in another module. To do otherwise would be to ignore the features of the module system and force us to come up with worse names just to avoid conflicts. - Jonathan M Davis
Fair enough. As you point out the fix is pretty simple. However, I can't seem to remember in C++ or any other language (not that I know all that many other languages) coming across a function in the standard library that conflicted with another function in the standard library in this way. I am likely to get corrected on that claim though :o)
I'm sure that it could be found somewhere, but C++ avoids it for two reasons: 1. As good as the STL is, it's pathetically small. 2. It only uses one namespace, so it _has_ to avoid conflicts, even if that means using uglier names. Java or C# might have some conflicts (I'm not sure - they certainly have much richer standard libraries than C++ does), but they almost always avoid it, because they're don't even allow free functions, so you only end up having to worry about class names conflicting. Their module systems are also different from D's (particularly C#'s), which changes things a bit. Other languages like python tend to force you to give the full path anyway, which avoids conflicts. The reason that D runs into them is because the default is to pull everything into the current module when you import it. If we'd taken the approach of making you give the full import path by default or forcing you to explicitly import each symbol, then it wouldn't be a problem (though that would obviously cause other problems). And we'll definitely pick different names where appropriate, but if the best names for two different functions in two different modules happen to be the same name, then we're going to use it. And in same cases, we very purposely picked the same name, because the functions did the same type of thing (e.g. the functions in std.ascii and std.uni which do the same thing but for ASCII and Unicode respectively). - Jonathan M Davis
Oct 03 2013
parent reply "Craig Dillabaugh" <craig.dillabaugh gmail.com> writes:
On Thursday, 3 October 2013 at 19:49:07 UTC, Jonathan M Davis 
wrote:
 On Thursday, October 03, 2013 20:57:20 Craig Dillabaugh wrote:
 On Thursday, 3 October 2013 at 18:12:01 UTC, Jonathan M Davis
clip
 
 - Jonathan M Davis
Fair enough. As you point out the fix is pretty simple. However, I can't seem to remember in C++ or any other language (not that I know all that many other languages) coming across a function in the standard library that conflicted with another function in the standard library in this way. I am likely to get corrected on that claim though :o)
I'm sure that it could be found somewhere, but C++ avoids it for two reasons: 1. As good as the STL is, it's pathetically small. 2. It only uses one namespace, so it _has_ to avoid conflicts, even if that means using uglier names. Java or C# might have some conflicts (I'm not sure - they certainly have much richer standard libraries than C++ does), but they almost always avoid it, because they're don't even allow free functions, so you only end up having to worry about class names conflicting. Their module systems are also different from D's (particularly C#'s), which changes things a bit. Other languages like python tend to force you to give the full path anyway, which avoids conflicts. The reason that D runs into them is because the default is to pull everything into the current module when you import it. If we'd taken the approach of making you give the full import path by default or forcing you to explicitly import each symbol, then it wouldn't be a problem (though that would obviously cause other problems). And we'll definitely pick different names where appropriate, but if the best names for two different functions in two different modules happen to be the same name, then we're going to use it. And in same cases, we very purposely picked the same name, because the functions did the same type of thing (e.g. the functions in std.ascii and std.uni which do the same thing but for ASCII and Unicode respectively). - Jonathan M Davis
That is an excellent explanation. Thank you. Do you think it would be worth noting the conflict in the documentation for readText()/write()? I should have mentioned in my original post that I likely could have figured out the workaround for this, and I posted here more because I was surprised that std.stdio and std.file would have a conflict! It seems like something folks new to D might run into with some frequency, and be thinking "whats up with that!". If others think it is a good idea, maybe I will head over to gitHub and try to add something. Craig
Oct 03 2013
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Thursday, October 03, 2013 22:57:22 Craig Dillabaugh wrote:
 On Thursday, 3 October 2013 at 19:49:07 UTC, Jonathan M Davis
 
 wrote:
 On Thursday, October 03, 2013 20:57:20 Craig Dillabaugh wrote:
 On Thursday, 3 October 2013 at 18:12:01 UTC, Jonathan M Davis
clip
 - Jonathan M Davis
Fair enough. As you point out the fix is pretty simple. However, I can't seem to remember in C++ or any other language (not that I know all that many other languages) coming across a function in the standard library that conflicted with another function in the standard library in this way. I am likely to get corrected on that claim though :o)
I'm sure that it could be found somewhere, but C++ avoids it for two reasons: 1. As good as the STL is, it's pathetically small. 2. It only uses one namespace, so it _has_ to avoid conflicts, even if that means using uglier names. Java or C# might have some conflicts (I'm not sure - they certainly have much richer standard libraries than C++ does), but they almost always avoid it, because they're don't even allow free functions, so you only end up having to worry about class names conflicting. Their module systems are also different from D's (particularly C#'s), which changes things a bit. Other languages like python tend to force you to give the full path anyway, which avoids conflicts. The reason that D runs into them is because the default is to pull everything into the current module when you import it. If we'd taken the approach of making you give the full import path by default or forcing you to explicitly import each symbol, then it wouldn't be a problem (though that would obviously cause other problems). And we'll definitely pick different names where appropriate, but if the best names for two different functions in two different modules happen to be the same name, then we're going to use it. And in same cases, we very purposely picked the same name, because the functions did the same type of thing (e.g. the functions in std.ascii and std.uni which do the same thing but for ASCII and Unicode respectively). - Jonathan M Davis
That is an excellent explanation. Thank you. Do you think it would be worth noting the conflict in the documentation for readText()/write()? I should have mentioned in my original post that I likely could have figured out the workaround for this, and I posted here more because I was surprised that std.stdio and std.file would have a conflict! It seems like something folks new to D might run into with some frequency, and be thinking "whats up with that!". If others think it is a good idea, maybe I will head over to gitHub and try to add something.
I'm inclined to think that there's no need, since people learning D should know how the module system works, and I'd prefer not to clutter the documentation, but I also haven't been a newbie for a very long time. - Jonathan M Davis
Oct 03 2013
parent reply "Craig Dillabaugh" <craig.dillabaugh gmail.com> writes:
On Thursday, 3 October 2013 at 21:58:18 UTC, Jonathan M Davis 
wrote:
 On Thursday, October 03, 2013 22:57:22 Craig Dillabaugh wrote:
 On Thursday, 3 October 2013 at 19:49:07 UTC, Jonathan M Davis
 
 wrote:
 On Thursday, October 03, 2013 20:57:20 Craig Dillabaugh 
 wrote:
 On Thursday, 3 October 2013 at 18:12:01 UTC, Jonathan M 
 Davis
clip
 - Jonathan M Davis
Fair enough. As you point out the fix is pretty simple. However, I can't seem to remember in C++ or any other language (not that I know all that many other languages) coming across a function in the standard library that conflicted with another function in the standard library in this way. I am likely to get corrected on that claim though :o)
I'm sure that it could be found somewhere, but C++ avoids it for two reasons: 1. As good as the STL is, it's pathetically small. 2. It only uses one namespace, so it _has_ to avoid conflicts, even if that means using uglier names. Java or C# might have some conflicts (I'm not sure - they certainly have much richer standard libraries than C++ does), but they almost always avoid it, because they're don't even allow free functions, so you only end up having to worry about class names conflicting. Their module systems are also different from D's (particularly C#'s), which changes things a bit. Other languages like python tend to force you to give the full path anyway, which avoids conflicts. The reason that D runs into them is because the default is to pull everything into the current module when you import it. If we'd taken the approach of making you give the full import path by default or forcing you to explicitly import each symbol, then it wouldn't be a problem (though that would obviously cause other problems). And we'll definitely pick different names where appropriate, but if the best names for two different functions in two different modules happen to be the same name, then we're going to use it. And in same cases, we very purposely picked the same name, because the functions did the same type of thing (e.g. the functions in std.ascii and std.uni which do the same thing but for ASCII and Unicode respectively). - Jonathan M Davis
That is an excellent explanation. Thank you. Do you think it would be worth noting the conflict in the documentation for readText()/write()? I should have mentioned in my original post that I likely could have figured out the workaround for this, and I posted here more because I was surprised that std.stdio and std.file would have a conflict! It seems like something folks new to D might run into with some frequency, and be thinking "whats up with that!". If others think it is a good idea, maybe I will head over to gitHub and try to add something.
I'm inclined to think that there's no need, since people learning D should know how the module system works, and I'd prefer not to clutter the documentation, but I also haven't been a newbie for a very long time. - Jonathan M Davis
There are two problems with this for newbies: 1. They may not understand the module system well. 2. The may not know that a string = char array, and that as such it may not even occur to them that write() will accept a string. Now a careful reading of the docs for readText() should clue them in that string = char array, but when you are new to a language and trying to absorb the new syntax it is something that can easily be overlooked. I have just enough D experience now that for the most part I don't struggle to follow the documentation, but I remember when I was new to D I found it very frustrating. That is even after reading Anderi's book (maybe I am a slow learner, but I am likely fairly representative of the average coder!) Now part of that is the known shortage of documentation, but often example code can be hard to follow, for example, from write: int[] a = [ 0, 1, 1, 2, 3, 5, 8 ]; write("filename", a); assert(cast(int[]) read("filename") == a); Consider the final 'assert' line. On the one hand, it shows how to concisely use language features and good D coding practices, however, on the other hand there is an awful lot going on in a single line of code. To someone who knows the language it looks trivial, but it can be a bit overwhelming to a newbie who wants to see if they can use this new language to write some text to a file! I guess the more fundamental question is, what is the purpose of the documentation? Is it a quick reference for D users, or is it a resource for people trying to learn the language? I learned C++ using Qt, largely from their online docs. The Qt documentation is a reference, but it also tends to provide lots of explanation. I've seen both, documentation strictly as a reference for those who already know how to use it, and docs with more focus on explaining how things work to the uninitiated. I tend to like the later approach, but it is certainly debatable.
Oct 04 2013
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Friday, October 04, 2013 16:12:14 Craig Dillabaugh wrote:
 I guess the more fundamental question is, what is the purpose of
 the documentation? Is it a quick reference for D users, or is it
 a resource for people trying to learn the language? I learned
 C++ using Qt, largely from their online docs. The Qt
 documentation is a reference, but it also tends to provide lots
 of explanation.
It would never have occurred to me that API documentation would be use for teaching the language - even documentation for the standard library. I would expect people to learn the language first. Yes, the standard library documentation needs to be reasonably accessible to newbies, but I would not expect it to be used as a teaching tool for the language. The documentation on a type or function is there to teach you about how to use that particular type or function, not how to use the language. Of course, I'm also the sort of person who thinks that people are nuts to just jump into a game without reading the entire manual first. - Jonathan M Davis
Oct 04 2013
parent "Craig Dillabaugh" <cdillaba cg.scs.carleton.ca> writes:
On Saturday, 5 October 2013 at 02:42:54 UTC, Jonathan M Davis
wrote:
 On Friday, October 04, 2013 16:12:14 Craig Dillabaugh wrote:
 I guess the more fundamental question is, what is the purpose 
 of
 the documentation? Is it a quick reference for D users, or is 
 it
 a resource for people trying to learn the language? I learned
 C++ using Qt, largely from their online docs. The Qt
 documentation is a reference, but it also tends to provide lots
 of explanation.
It would never have occurred to me that API documentation would be use for teaching the language - even documentation for the standard library. I would expect people to learn the language first. Yes, the standard library documentation needs to be reasonably accessible to newbies, but I would not expect it to be used as a teaching tool for the language. The documentation on a type or function is there to teach you about how to use that particular type or function, not how to use the language. Of course, I'm also the sort of person who thinks that people are nuts to just jump into a game without reading the entire manual first. - Jonathan M Davis
Yes, but the manual (Andrei's book?) barely touches on the standard library (ranges are not even covered). Things are getting better now that Ali's book is getting closer to having a complete English translation. For whatever reason, when I first started trying to use Phobos, I found that the knowledge I had gathered from Andrei's book still left me dazed and confused at times. Cheers, Craig
Oct 05 2013