Re: rdmd bug?
On Mon, 20 Dec 2010 04:27:33 +0300 Nick Voronin wrote: > On Mon, 20 Dec 2010 01:24:02 +0100 > CrypticMetaphor wrote: > > > Anyway, the problem is, if I call rdmd from outside the folder in which > > the main source resides in, and main includes another file in that > > folder, I get an error. > > > // If I'm in a shell, and I do this, I get an error: > > ...\projectfolder>rdmd src\main.d > > src\main.d(2): Error: module test is in file 'test.d' which cannot be read > > import path[0] = C:\D\dmd2\windows\bin\..\..\src\phobos > > import path[1] = C:\D\dmd2\windows\bin\..\..\src\druntime\import > > > Anyway, I want to be able to compile with rdmd from a different folder, > > is this a bug? or should I use a different tool? :-S > > *aahhh* > > Add -Ifullpath_to_projectfolder\src. It's the way it works IMHO, if you > import something it must be relative to search path or to current dir. There > may be a better way (replace current dir with the dir where source is, but it > will take away control), but this works. > > There is a bug though, I can't make it work with -Irelative_path_to_src. > Looks like .deps contain paths relative to where rdmd was ran, while dmd > interprets them as paths relative to where .deps file is. Yes, I think it cannot work, since -I is a option of dmd, not of rdmd. rdmd just passes by options to dmd if I understand correctly. What you want is to influence a feature provided dy rdmd, not dmd, namely automatic inclusion of (non-standard) imports. But sure, it may be a bug: rdmd should look for imports using pathes relative to the location of the (app) module it is given. Or, for simplicity, we can just state it must be called from this location. Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com
Re: Classes or stucts :: Newbie
On Sun, 19 Dec 2010 21:33:56 -0500 bearophile wrote: > >So, putting classes on the stack kind of negates the whole point of having > >both structs and classes in the first place.< > > This is false, the definition of D class instance doesn't specify where the > instance memory is allocated. For me, the important difference is that classes are referenced, while structs are plain values. This is a semantic distinction of highest importance. I would like structs to be subtype-able and to implement (runtime-type-based) polymorphism. Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com
Re: Classes or stucts :: Newbie
On Monday 20 December 2010 01:19:31 spir wrote: > On Sun, 19 Dec 2010 21:33:56 -0500 > > bearophile wrote: > > >So, putting classes on the stack kind of negates the whole point of > > >having both structs and classes in the first place.< > > > > This is false, the definition of D class instance doesn't specify where > > the instance memory is allocated. > > For me, the important difference is that classes are referenced, while > structs are plain values. This is a semantic distinction of highest > importance. I would like structs to be subtype-able and to implement > (runtime-type-based) polymorphism. Except that contradicts the facts that they're value types. You can't have a type which has polymorphism and is a value type. By its very nature, polymorphism requires you to deal with a reference. C++ allows you to put classes on the stack. It even allows you to assign a derived type to a base type where the variable being assigned to is on the stack. The result is shearing. The only part assigned is the base type portion, and the data which is part of the derived type is lost. That's because the variable _is_ the base type. A value type _is_ a particular type _exactly_ and _cannot_ be any other type. This is distinctly different from a reference of a base type which points to an object which is of a derived type. In that case, the variable is a reference of the base type, but the object referenced is in fact the derived type. The indirection allows you to use the derived type as if it were the base type. It allows you to use polymorphism. Without that indirection, you can't do that. So, you _could_ make structs have inheritance, but doing so would introduce shearing, which causes a number of problems. One of the main reasons that structs in D do _not_ have inheritance is to avoid shearing. - Jonathan M Davis
enum ubyte[] vs enum ubyte[3]
Hi, I'm currently patching Ragel (http://www.complang.org/ragel/) to generate D2 compatible code. Right now it creates output like this for static arrays: enum ubyte[] _parseResponseLine_key_offsets = [ 0, 0, 17, 18, 37, 41, 42, 44, 50, 51, 57, 58, 78, 98, 118, 136, 138, 141, 143, 146, 148, 150, 152, 153, 159, 160, 160, 162, 164 ]; Making it output "enum ubyte[30]" would be more complicated, so I wonder if there's a difference between "enum ubyte[]" and "enum ubyte[30]"? -- Johannes Pfau
Re: Classes or stucts :: Newbie
On Mon, 20 Dec 2010 01:29:13 -0800 Jonathan M Davis wrote: > > For me, the important difference is that classes are referenced, while > > structs are plain values. This is a semantic distinction of highest > > importance. I would like structs to be subtype-able and to implement > > (runtime-type-based) polymorphism. > > Except that contradicts the facts that they're value types. You can't have a > type which has polymorphism and is a value type. By its very nature, > polymorphism requires you to deal with a reference. Can you expand on this? At least Oberon has value structs ("records") with inheritance and polyporphism; I guess the turbo Pascal OO model was of that kind, too (unsure) -- at least the version implemented in freepascal seems to work fine that way. And probably loads of less known PLs provide such a feature. D structs could as well IIUC: I do not see the relation with instances beeing implicitely referenced. (Except that they must be passed by ref to "member functions" they are the receiver of, but this is true for any kind of OO, including present D structs.) (I guess we have very different notions of "reference", as shown by previous threads.) Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com
Re: enum ubyte[] vs enum ubyte[3]
Johannes Pfau: Hello Johannes and thank you for developing your tool for D2 too :-) > Making it output "enum ubyte[30]" would be more complicated, so I wonder > if there's a difference between "enum ubyte[]" and "enum ubyte[30]"? In D1 a enum ubyte[] is a compile-time constant dynamic array of unsigned bytes, it is a 2 word long struct that contains a pointer and a length. In D1 you express the same thing with "const ubyte[]". In D2 a "enum ubyte[30]" is a compile-time constant fixed size array of 32 unsigned bytes that gets passed around by value. In D1 a "const ubyte[30]" is a compile-time constant fixed size array of 32 unsigned bytes that gets passed around by reference. So they are two different things and you use one or the other according to your needs. Currently there are also some low performance issues in D with enums that get re-created each time you use them (this is true for associative arrays, but I don't remember if this is true for dynamic arrays too). So better to take a look at the produced asm to be sure, if you want to avoid performance pitfalls. Regardless the array kind you want to use, also take a look at "Hex Strings": http://www.digitalmars.com/d/2.0/lex.html That allow you to write bytes arrays as hex data: x"00 FBCD 32FD 0A" Bye, bearophile
Re: enum ubyte[] vs enum ubyte[3]
At 20.12.2010, 11:02, bearophile wrote : Hello Johannes and thank you for developing your tool for D2 too :-) Actually it's not mine, I'm just a regular user. I don't think I could ever understand the finite state machine code (especially because it's c++), but patching the c/d1 codegen to output d2 code is easy enough ;-) In D1 a enum ubyte[] is a compile-time constant dynamic array of unsigned bytes, it is a 2 word long struct that contains a pointer and a length. Did you mean in D2? I feared that, so I'll have to do some extra work... In D2 a "enum ubyte[30]" is a compile-time constant fixed size array of 32 unsigned bytes that gets passed around by value. Yep, that's what I want. Regardless the array kind you want to use, also take a look at "Hex Strings": http://www.digitalmars.com/d/2.0/lex.html That allow you to write bytes arrays as hex data: x"00 FBCD 32FD 0A" That's interesting, I'll have a look at it, but ragel shares big parts of the c/c++/d code, so as long as the C syntax works there's no need to change that. Bye, bearophile Thanks for your help! -- Johannes Pfau
Re: enum ubyte[] vs enum ubyte[3]
Johannes Pfau: > Did you mean in D2? Right, sorry. Bye, bearophile
Re: Classes or stucts :: Newbie
Nick Voronin: > Here is where we diverge. Choosing struct vs class on criteria of their > placement makes no sense to me. In D you use a class if you want inheritance or when you (often) need reference semantics, and you use a struct when you need a little value passed around by value or when you want a simple form of RAII or when you want to implement something manually (like using PIMPL), or when you want max performance (and you manage structs by pointer, you may even put a tag inside the stuct or the pointer and implement manually some kind of inheritance). With structs you have a literal syntax, postblits, in-place allocation, and you are free to use align() too. Bye, bearophile
Re: define methods apart
On 12/19/10 06:52, spir wrote: > On Sun, 19 Dec 2010 03:37:37 -0600 > Christopher Nicholson-Sauls wrote: > >> On 12/18/10 07:19, spir wrote: >>> Hello, >>> >>> >>> I cannot find a way to define methods (I mean "member functions) outside >>> the main type-definition body: >>> >>> struct X {} >>> void X.say () {writeln("I say!");} >>> ==> >>> Element.d(85): semicolon expected, not '.' >>> >>> Do I overlook anything, or is this simply impossible? In the latter case, >>> what is the problem? >>> (In many languages, not only dynamic ones, method are or at least can be >>> defined apart.) >>> >>> >>> Denis >>> -- -- -- -- -- -- -- >>> vit esse estrany ☣ >>> >>> spir.wikidot.com >>> >> >> As bearophile says, it just isn't the "D way" to do things. >> >> But, if you absolutely must (or just want to, for "playing" sakes) there >> are ways of faking it using opDispatch. Here's one I just tossed >> together and tested (DMD 2.050) right now. >> >> [code snipped] >> >> Generally speaking, though, I'm not sure what the real value would be in >> doing this in D. Did you have a particular use case in mind, or was it >> just idle exploration? > > Thank you very for this example use of opdispatch :-) > I'm still exploring the language (which I like very much, except for some > given features *). Actually, I just wanted to know whether it's possible, > because I'm used to this way and find it more practicle or readable in > various cases. But it is not a problem. > > Denis > > (*) Some inherited from C/C++ (unhelpful syntax or semantics, mainly), some > among the newest (too abstract or complicated, i'd say). > -- -- -- -- -- -- -- > vit esse estrany ☣ > > spir.wikidot.com > No problem. opDispatch has a number of possible uses. Another thing I've done with it before is to wrap the message passing system from std.concurrency, to ease defining message protocols. Basically I define a message as a struct, then define an opDispatch that looks for the pattern 'sendBLAH(...)' and forwards that to 'tid.send(BLAHMessage(...), thisTid())' auto-magically. To make it really magical I had to create some code-generation for the receiving end so it would provide an argument to receive/receiveTimeout for each handleBLAH method I define. It had a few little bugs/quirks though, which is why I haven't ever shared it. -- Chris N-S
Re: Classes or stucts :: Newbie
On Monday 20 December 2010 01:52:58 spir wrote: > On Mon, 20 Dec 2010 01:29:13 -0800 > > Jonathan M Davis wrote: > > > For me, the important difference is that classes are referenced, while > > > structs are plain values. This is a semantic distinction of highest > > > importance. I would like structs to be subtype-able and to implement > > > (runtime-type-based) polymorphism. > > > > Except that contradicts the facts that they're value types. You can't > > have a type which has polymorphism and is a value type. By its very > > nature, polymorphism requires you to deal with a reference. > > Can you expand on this? > > At least Oberon has value structs ("records") with inheritance and > polyporphism; I guess the turbo Pascal OO model was of that kind, too > (unsure) -- at least the version implemented in freepascal seems to work > fine that way. And probably loads of less known PLs provide such a > feature. D structs could as well IIUC: I do not see the relation with > instances beeing implicitely referenced. (Except that they must be passed > by ref to "member functions" they are the receiver of, but this is true > for any kind of OO, including present D structs.) > > (I guess we have very different notions of "reference", as shown by > previous threads.) Okay. This can get pretty complicated, so I'm likely to screw up on some of the details, but this should give you a basic idea of what's going on. In essentially any C-based language, when you declare an integer on the stack like so: int a = 2; you set aside a portion of the stack which is the exact size of an int (typically 32 bits, but that will depend on the language). If you declare a pointer, int* a; then you're setting aside a portion of the stack the size of a pointer (32 bits on a 32 bit machine and 64 bits on a 64 bit machine). That variable then holds an address - typically to somewhere on the heap, though it could be to an address on the stack somewhere. In the case of int*, the address pointed to will refer to a 32-bit block of memory which holds an int. If you have a struct or a class that you put on the stack. Say, class A { int a; float b; } then you're setting aside exactly as much space as that type requires to hold itself. At minimum, that will be the total size of its member variables (in this case an int and a float, so probably a total of 64 bits), but it often will include extra padding to align the variables along appropriate boundaries for the sake of efficiency, and depending on the language, it could have extra type information. If the class has a virtual table (which it will if it has virtual functions, which in most any language other than C++ would mean that it definitely has a virtual table), then that would be part of the space required for the class as well (virtual functions are polymorphic; when you call a virtual function, it calls the version of the function for the actual type that an object is rather than the pointer or reference that you're using to refer to the object; when a non-virtual function function is called, then the version of the function which the pointer or reference is is used; all class functions are virtual in D unless the compiler determines that they don't have to be and optimizes it out (typically because they're final); struct functions and stand- alone functions are never virtual). The exact memory layout of a type _must_ be known at compile time. The exact amount of space required is then known, so that the stack layout can be done appropriately. If you're dealing with a pointer, then the exact memory layout of the memory being pointed to needs to be known when that memory is initialized, but the pointer doesn't necessarily need to know it. This means that you can have a pointer of one type point to a variable of another type. Now, assuming that you're not subverting the type system (e.g. my casting int* to float*), you're dealing with inheritance. For instance, you have class B : A { bool c; } and a variable of type A*. That pointer could point to an object which is exactly of type A, or it could point to any subtype of A. B is derived from A, so the object could be a B. As long as the functions are virtual, you can have polymorphic functions by having the virtual table used to call the version of the function for the type that the object actually is rather than the type that the pointer is. References are essentially the same as pointers (though they may have some extra information with them, making them a bit bigger than a pointer would be in terms of the amount of space required on the stack). However, in the case of D, pointers are _not_ treated as polymorphic (regardless of whether a function is virtual or not), whereas references _are_ treated as polymorphic (why, I don't know - probably to simplify pointers). In C++ though, pointers are polymorphic. Now, if you have a variable of type A*, you could do something l
Re: enum ubyte[] vs enum ubyte[3]
On Mon, 20 Dec 2010 10:26:16 +0100 "Johannes Pfau" wrote: > Hi, > I'm currently patching Ragel (http://www.complang.org/ragel/) to generate > D2 compatible code. Interesting. Ragel-generated code works fine for me in D2. I suppose it mostly uses such a restricted C-like subset of language that it didn't change much from D1 to D2. But if you are going to patch it, please make it add extra {} around action code! The thing is that when there is a label before {} block (and in ragel generated code I saw it's always so) the block isn't considered as a new scope which causes problems when you have local variables declaration inside actions. Anyway, good luck with whatever you plan :) Ragel is cool. > Right now it creates output like this for static > arrays: > > enum ubyte[] _parseResponseLine_key_offsets = [ > 0, 0, 17, 18, 37, 41, 42, 44, > 50, 51, 57, 58, 78, 98, 118, 136, > 138, 141, 143, 146, 148, 150, 152, 153, > 159, 160, 160, 162, 164 > ]; > > Making it output "enum ubyte[30]" would be more complicated, so I wonder > if there's a difference between "enum ubyte[]" and "enum ubyte[30]"? One is fixed size array and other is dynamic. Honestly I doubt that it matters for code generated by Ragel, since this is constant and won't be passed around. If it's harder to make it fixed-size then don't bother. -- Nick Voronin
Re: enum ubyte[] vs enum ubyte[3]
On Monday 20 December 2010 01:26:16 Johannes Pfau wrote: > Hi, > I'm currently patching Ragel (http://www.complang.org/ragel/) to generate > D2 compatible code. Right now it creates output like this for static > arrays: > > enum ubyte[] _parseResponseLine_key_offsets = [ > 0, 0, 17, 18, 37, 41, 42, 44, > 50, 51, 57, 58, 78, 98, 118, 136, > 138, 141, 143, 146, 148, 150, 152, 153, > 159, 160, 160, 162, 164 > ]; > > Making it output "enum ubyte[30]" would be more complicated, so I wonder > if there's a difference between "enum ubyte[]" and "enum ubyte[30]"? ubyte[] is a dynamic array. ubyte[30] is a static array. They are inherently different types. The fact that you're dealing with an enum is irrelevant. So, the code that you're generating is _not_ a static array. It's a dynamic array. This is inherently different from C or C++ where having [] on a type (whether it has a number or not) is _always_ a static array. - Jonathan M Davis
Re: Classes or stucts :: Newbie
Jonathan M Davis: > So, putting classes on the stack kind of negates the whole point of having > both structs and classes in the first place. Where you put the instance is mostly a matter of implementation. This is why a smart JavaVM is able to perform escape analysis and choose where to allocate the class instance. Keep in mind that if you allocate a class on the stack or in-place inside another class, you don't turn it into a value, because beside the class instance you reserve space for its reference too (this reference may even be immutable, if you want). > scoped classes are definitely not in SafeD. Well implemented scoped classes are safe enough (compared to the other things). The compiler may perform escape analysis of all the aliases of a scoped object and statically raise an error if a reference escapes. This isn't 100% safe in a language that has all kind of casts and low-level features, but it's often safe enough, compared to other things. And those casts and low level features that can fool the escape analysis can be disabled statically (with something like @safe), this makes scoped classes 100% safe, probably safer than heap allocations. >The whole point of "safe" when talking about safe in D is memory saftey. I know, but some people (including me) think that "safe D" is a misleading name because it just means "memory safe D". >If the compiler can determine that a particular class object can be put on the >stack and optimize it that way. Fine, but it's pretty rare that it can do that >- essentially only in cases where you don't pass it to _anything_ except for >pure functions (including calls to member functions). I don't agree that it's rare. If a function that allocates an object calls a function (or member function) that's present in the same compilation unit (this more or less means same module), then the compiler is able to continue the escape analysis and determine if the called function escapes the reference. If this doesn't happen, then the class instance is free to be scoped. This situation is common enough. >And if the compiler can do that, then it there's no need for the programmer to >use scope explicitly.< I don't agree. An annotation like "@scope" is a contract between the programmer and the compiler. It means that if the compiler sees a reference escape, then it stops the compilation. >And no, a compiler _can't_ do pure optimizations on its own, >generally-speaking, because that would require looking not only at the body of >the function that's being called but at the function bodies of any functions >that it calls. D is not designed in a way that the compiler even necessarily >has _access_ to a function's body when compiling, and you can't generally look >at a function's body when doing optimizations when calling that function. So, >_some_ pure optimizations could be done, but most couldn't. This is not the >case with scoped classes, because purity already gives you the information >that you need.< Quite often a function calls another function in thee same compilation unit, in this case the analysis is possible. So you limit the optimizations to this common but limited case. And LDC compiler and in future GDC too, have link-time optimization, this means the compiler packs or sees the program code code in a single compilation unit. In this case it's able to perform a more complete analysis (including de-virtualization of some virtual functions). >Safety by convention means that the language and the compiler do not enforce >it in any way.< This is not fully true. If the syntax of the unsafe thing is ugly and long, the programmer is discouraged to use it. This makes the unsafe thing more visible for the eyes of the programmer. Statistically this may reduce bug count. >There's nothing contradictory about Walter's stance. He's for having safety >built into the language as much as reasonably possible and against having it >thrust upon the programmer to program in a particular way to avoid unsafe >stuff.< I think you have missed part of the context of my comments for Nick Voronin, he was trying to say something here: >Yet we won't have library solution for pointers instead of language support >(hopefully)? :) I think it all goes against "being practical" as an objective >of the language. Safety is important but you don't achieve safety by means of >making unsafe thing unconvenient and inefficient. If there is emplace() then >there is no reason not to have scope storage class. At least looking from >user's POV. I don't know how hard it is on the compiler.< >In _general_ case there is no safety in D. With all low-level capabilities one >can always defeat compiler. Removing intermediate-level safer (yet unsafe) >capabilities arguabily gains nothing but frustration. I'm all for encouraging >good practices, but this is different.< In D the convention is to not use certain low-level means to do something (and @s
Re: string comparison
On Sun, 19 Dec 2010 07:01:30 +, doubleagent wrote: > Andrei's quick dictionary illustration [in his book, 'The D Programming > Language'] doesn't seem to work. Code attached. That's strange. I ran the example you posted using DMD 2.050 myself, and it works for me. Are you 100% sure that you are running this version, and that it is not using an outdated Phobos version (from an older installation, for instance)? One suggestion: Try replacing the next-to-last line with this: dictionary[word.idup] = newId; The 'word' array is mutable and reused by byLine() on each iteration. By doing the above you use an immutable copy of it as the key instead. > On my computer, with d2-0.5.0, I got the following output while testing. > > andrei > 0 andrei > andrei > 1 andrei > > > Also, why doesn't 'splitter' show up on the site's documentation of > std.string? And what advantage does 'splitter(strip(line))' offer over > 'split(line)'? splitter is defined in std.algorithm. The fact that it becomes visible when you import std.string is due to bug 314: http://d.puremagic.com/issues/show_bug.cgi?id=314 (std.string is supposed to publically import just a few symbols from std.algorithm, but because of this bug the whole module gets imported publically.) The advantage with splitter is that it is lazy and therefore more efficient. split() is eager and allocates memory to hold the string fragments. -Lars
Re: Classes or stucts :: Newbie
On Mon, 20 Dec 2010 03:11:49 -0800 Jonathan M Davis wrote: > Now, you could conceivably have a language where all of its objects were > actually pointers, but they were treated as value types. So, > > B b; > A a = b; > > would actually be declaring > > B* b; > A* a = b; > > underneath the hood, except that the assignment would do a deep copy and > allocate the appropriate meemory rather than just copying the pointer like > would > happen in a language like C++ or D. Perhaps that's what Oberon does. I have > no > idea. I have never heard of the language before, let alone used it. I don't know how Oberon works. But I'm sure that its records are plain values, _not_ "pointed" under the hood. And their methods all are virtual (they have a virtual method table). I have no more details, sorry. Denis -- -- -- -- -- -- -- vit esse estrany ☣ spir.wikidot.com
Re: string comparison
20.12.2010 8:35, doubleagent пишет: Compared to the relatively snappy response other threads have been receiving I'm going to assume that nobody is interested in my inquiry. That's cool. Can anybody point me to an IRC chatroom for D noobs, and is there anywhere to post errata for the book? Please don't feel offended if you don't get response quickly. Even if it may seem that people are active in other threads doesn't mean they are fast enough to analyse arising questions and problems while discussing some recent ideas and improvements and not forgetting to work and sleep ;) Besides, there are many people here from different parts of the world, different time zones. And lastly, hasn't this by chance been your first post? AFAIR, the first message is being moderated so it doesn't get to the public at once. BTW, There is a #D channel on freenode, if my memory serves.
Re: enum ubyte[] vs enum ubyte[3]
On Monday, December 20, 2010, Nick Voronin wrote: On Mon, 20 Dec 2010 10:26:16 +0100 "Johannes Pfau" wrote: Hi, I'm currently patching Ragel (http://www.complang.org/ragel/) to generate D2 compatible code. Interesting. Ragel-generated code works fine for me in D2. I suppose it mostly uses such a restricted C-like subset of language that it didn't change much from D1 to D2. The most important change is const correctness. Because of that table based output didn't work with D2. And you couldn't directly pass const data (like string.ptr) to Ragel. But if you are going to patch it, please make it add extra {} around action code! The thing is that when there is a label before {} block (and in ragel generated code I saw it's always so) the block isn't considered as a new scope which causes problems when you have local variables declaration inside actions. You mean like this code: - tr15: #line 228 "jpf/http/parser.rl" { if(start != p) { key = line[(start - line.ptr) .. (p - line.ptr)]; } } - should become: ? - tr15: #line 228 "jpf/http/parser.rl" {{ if(start != p) { key = line[(start - line.ptr) .. (p - line.ptr)]; } }} - One is fixed size array and other is dynamic. Honestly I doubt that it matters for code generated by Ragel, since this is constant and won't be passed around. If it's harder to make it fixed-size then don't bother. Could a dynamic array cause heap allocations, even if it's data is never changed? If not, dynamic arrays would work fine. -- Johannes Pfau
Re: Problems with Reflection in Static library
19.12.2010 10:51, Mandeep Singh Brar пишет: Thanks a lot for your reply Tomek. I understand what you are saying but this would not work for me. The reason is that i am trying to make some kind of plugins from these libs. So i would not know the name objectFactory also in advance (multiple plugins will not be implementing the same named method and linking statically). For now i am just merging these two into the same place. In general, it's not a very good idea to make plugins using static linkage. Even if your plugins will be dynamic libraries (dll/so), which is currently not possible at least on Linux (and at least with dmd, I don't know about gdc2), but the core to which they are plugged-in remains static library, you may and most certainly will get unpleasant surprises. Reason being, any static data contained in the static library will be duplicated for every executable/dll that links to it. I don't know if anything can be done with it (actually, I think nothing can be). So for plugins, it's better to keep the 'core' also as a dynamic library. But, again, dmd is currently is not on good terms with dynamic linking (aside from loading a C dll at runtime, but that doesn't count).
Re: string comparison
On Monday, December 20, 2010 06:01:23 Lars T. Kyllingstad wrote: > On Sun, 19 Dec 2010 07:01:30 +, doubleagent wrote: > > Andrei's quick dictionary illustration [in his book, 'The D Programming > > Language'] doesn't seem to work. Code attached. > > That's strange. I ran the example you posted using DMD 2.050 myself, and > it works for me. Are you 100% sure that you are running this version, > and that it is not using an outdated Phobos version (from an older > installation, for instance)? > > One suggestion: Try replacing the next-to-last line with this: > > dictionary[word.idup] = newId; > > The 'word' array is mutable and reused by byLine() on each iteration. By > doing the above you use an immutable copy of it as the key instead. > > > On my computer, with d2-0.5.0, I got the following output while testing. > > > > andrei > > 0 andrei > > > > andrei > > > > 1 andrei > > > > > > Also, why doesn't 'splitter' show up on the site's documentation of > > std.string? And what advantage does 'splitter(strip(line))' offer over > > 'split(line)'? > > splitter is defined in std.algorithm. The fact that it becomes visible > when you import std.string is due to bug 314: > > http://d.puremagic.com/issues/show_bug.cgi?id=314 > > (std.string is supposed to publically import just a few symbols from > std.algorithm, but because of this bug the whole module gets imported > publically.) Actually, while that is a definite bug, splitter() _is_ defined in std.string as well (though it calls std.algorithm.splitter()), but it returns auto, so it doesn't show up in the docs, which is a different bug. - Jonathan M Davis
Re: Classes or stucts :: Newbie
On Monday, December 20, 2010 03:19:48 bearophile wrote: > Jonathan M Davis: > > So, putting classes on the stack kind of negates the whole point of > > having both structs and classes in the first place. > > Where you put the instance is mostly a matter of implementation. This is > why a smart JavaVM is able to perform escape analysis and choose where to > allocate the class instance. > > Keep in mind that if you allocate a class on the stack or in-place inside > another class, you don't turn it into a value, because beside the class > instance you reserve space for its reference too (this reference may even > be immutable, if you want). > > > scoped classes are definitely not in SafeD. > > Well implemented scoped classes are safe enough (compared to the other > things). The compiler may perform escape analysis of all the aliases of a > scoped object and statically raise an error if a reference escapes. This > isn't 100% safe in a language that has all kind of casts and low-level > features, but it's often safe enough, compared to other things. And those > casts and low level features that can fool the escape analysis can be > disabled statically (with something like @safe), this makes scoped classes > 100% safe, probably safer than heap allocations. > > >The whole point of "safe" when talking about safe in D is memory saftey. > > I know, but some people (including me) think that "safe D" is a misleading > name because it just means "memory safe D". Talking about SafeD meaning memory safety makes the meaning of safety clear. If you try and make the term safety encompass more than that, it takes very little for "safety" to become subjective. Regardless of whether it would be nice if SafeD gave types of safety other than memory safety, when D documentation and any of the main D devs talk about safety, it is memory safety which is being referred to. Trying to expand the meaning beyond that will just cause confusion regardless of whether the non-memory safety being discussed is desirable or not. > >If the compiler can determine that a particular class object can be put on > >the stack and optimize it that way. Fine, but it's pretty rare that it > >can do that - essentially only in cases where you don't pass it to > >_anything_ except for pure functions (including calls to member > >functions). > > I don't agree that it's rare. If a function that allocates an object calls > a function (or member function) that's present in the same compilation > unit (this more or less means same module), then the compiler is able to > continue the escape analysis and determine if the called function escapes > the reference. If this doesn't happen, then the class instance is free to > be scoped. This situation is common enough. > > >And if the compiler can do that, then it there's no need for the > >programmer to use scope explicitly.< > > I don't agree. An annotation like "@scope" is a contract between the > programmer and the compiler. It means that if the compiler sees a > reference escape, then it stops the compilation. > > >And no, a compiler _can't_ do pure optimizations on its own, > >generally-speaking, because that would require looking not only at the > >body of the function that's being called but at the function bodies of > >any functions that it calls. D is not designed in a way that the compiler > >even necessarily has _access_ to a function's body when compiling, and > >you can't generally look at a function's body when doing optimizations > >when calling that function. So, _some_ pure optimizations could be done, > >but most couldn't. This is not the case with scoped classes, because > >purity already gives you the information that you need.< > > Quite often a function calls another function in thee same compilation > unit, in this case the analysis is possible. So you limit the > optimizations to this common but limited case. > > And LDC compiler and in future GDC too, have link-time optimization, this > means the compiler packs or sees the program code code in a single > compilation unit. In this case it's able to perform a more complete > analysis (including de-virtualization of some virtual functions). It's trivial to get a reference or pointer to escape and make undetectable to the compiler. Some escape analysis can be and is done, but all it takes is passing a pointer or a reference to another function and the compiler can't determine it anymore unless it has access to the called functions body, and perhaps the bodies of functions that that function calls. And if the compiler can't be 100% correct with escape analysis, then any feature that requires it is not safe. And as great as fancier optimizations such as link-time optimizations may be, the existence of dynamic libraries eliminates any and all guarantees that such optimizations would be able to make if they had all of the source to look at. So, you can't rely on them. They help, and they're great, but no feature can re
Re: Classes or stucts :: Newbie
On Monday, December 20, 2010 06:24:56 spir wrote: > On Mon, 20 Dec 2010 03:11:49 -0800 > > Jonathan M Davis wrote: > > Now, you could conceivably have a language where all of its objects were > > actually pointers, but they were treated as value types. So, > > > > B b; > > A a = b; > > > > would actually be declaring > > > > B* b; > > A* a = b; > > > > underneath the hood, except that the assignment would do a deep copy and > > allocate the appropriate meemory rather than just copying the pointer > > like would happen in a language like C++ or D. Perhaps that's what > > Oberon does. I have no idea. I have never heard of the language before, > > let alone used it. > > I don't know how Oberon works. But I'm sure that its records are plain > values, _not_ "pointed" under the hood. And their methods all are virtual > (they have a virtual method table). I have no more details, sorry. Well, given C's memory model - which D uses - you can't do that. Oberon could use a different memory model and have some other way of doing it, but it won't work for D, so you'll never see structs with polymorphic behavior in D. - Jonthan M Davis
Re: string comparison
On Mon, 20 Dec 2010 00:35:53 -0500, doubleagent wrote: Compared to the relatively snappy response other threads have been receiving I'm going to assume that nobody is interested in my inquiry. Just a tip, don't expect snappy responses on Sunday... We all have lives you know ;) I for one usually have my computer that I do D stuff with off for most of the weekend. -Steve
Re: Classes or stucts :: Newbie
On Sun, 19 Dec 2010 17:38:17 -0500, Jonathan M Davis wrote: On Sunday 19 December 2010 14:26:19 bearophile wrote: Jonathan M Davis: > There will be a library solution to do it, but again, it's unsafe. It can be safer if the compiler gives some help. For me it's one of the important unfinished parts of D. Whereas, I would argue that it's completely unnecessary. structs and classes serve different purposes. There is no need for scoped classes. They may perodically be useful, but on the whole, they're completely unnecessary. The compiler can help, but it can't fix the problem any more that it can guarantee that a pointer to a local variable doesn't escape once you've passed it to another function. In _some_ circumstances, it can catch escaping pointers and references, but in the general case, it can't. If we have library solutions for people who want to play with fire, that's fine. But scoped classes is just not one of those things that the language really needs. They complicate things unnecessarily for minimal benefit. I don't mind having a solution as long as there is a solution. The main need I see for scoped classes is for when you *know* as the programmer that the lifetime of a class or struct will not exceed the lifetime of a function, but you don't want to incur the penalty of allocating on the heap. Mostly this is because the functions you want to call take classes or interfaces. It's difficult to find an example with Phobos since there are not many classes. But with Tango, scoped classes are used everywhere. -Steve
Re: string comparison
> Are you 100% sure that you are running this version I have to be. There are no other versions of phobos on this box and 'which dmd' points to the correct binary. > dictionary[word.idup] = newId; That fixes it. > The 'word' array is mutable and reused by byLine() on each iteration. By > doing the above you use an immutable copy of it as the key instead. I REALLY don't understand this explanation. Why does the mutability of 'word' matter when the associative array 'dictionary' assigns keys by value...it's got to assign them by value, right? Otherwise we would only get one entry in 'dictionary' and the key would be constantly changing. The behavior itself seems really unpredictable prior to testing, and really unintended after testing. I suspect it's due to some sort of a bug. The program, on my box anyway, only fails when we give it identical strings, except one is prefixed with a space. That should tell us that 'splitter' and 'strip' didn't do their job properly. The fly in the ointment is that when we output the strings, they appear as we would expect. I suspect D does string comparisons (when the 'in' keyword is used) based on some kind of a hash, and that hash doesn't get correctly updated when 'strip' or 'splitter' is applied, or upon the next comparison or whatever. Calling 'idup' must force the hash to get recalculated. Obviously, you guys would know if there's any merit to this, but it seems to explain the problem. > The advantage with splitter is that it is lazy and therefore more > efficient. split() is eager and allocates memory to hold the string > fragments. Yeah, that's what I thought would be the answer. Kudos to you guys for thinking of laziness out of the box. This is a major boon for D. You know, there's something this touches on which I was curious about. If D defaults to 'safety first', and with some work you can get down-to-the-metal, why doesn't the language default to immutable variables, with an explicit modifier for mutable ones? C compatibility?
Re: string comparison
I understand. Thank you, and thanks for pointing out the chatroom.
Re: string comparison
On Mon, 20 Dec 2010 11:13:34 -0500, Stanislav Blinov wrote: And lastly, hasn't this by chance been your first post? AFAIR, the first message is being moderated so it doesn't get to the public at once. BTW, this message board is not moderated. -Steve
Re: string comparison
On Mon, 20 Dec 2010 14:05:56 -0500, Steven Schveighoffer wrote: On Mon, 20 Dec 2010 11:13:34 -0500, Stanislav Blinov wrote: And lastly, hasn't this by chance been your first post? AFAIR, the first message is being moderated so it doesn't get to the public at once. BTW, this message board is not moderated. I should clarify, it's retroactively moderated :) That is, if spam appears, it's allowed to go through, but then removed once discovered. -Steve
Re: string comparison
> The reason that std.string.splitter() does not show in the documentation is > that > its return type is auto, and there is currently a bug in ddoc that makes it so > that auto functions don't end up in the generated documentation. Looking at > the > code, it pretty much just forwards to std.algorithm.splitter() using > whitespace > as its separator, so you can look at the documentation there if you'd like. Thanks. The code was pretty self-explanatory but it's helpful to know that auto functions currently don't get documented.
Re: string comparison
On Monday, December 20, 2010 10:44:12 doubleagent wrote: > > Are you 100% sure that you are running this version > > I have to be. There are no other versions of phobos on this box and 'which > dmd' points to the correct binary. > > > dictionary[word.idup] = newId; > > That fixes it. > > > The 'word' array is mutable and reused by byLine() on each iteration. By > > doing the above you use an immutable copy of it as the key instead. > > I REALLY don't understand this explanation. Why does the mutability of > 'word' matter when the associative array 'dictionary' assigns keys by > value...it's got to assign them by value, right? Otherwise we would only > get one entry in 'dictionary' and the key would be constantly changing. Okay. I don't know what the actual code looks like, but word is obviously a dynamic array, and if it's from byLine(), then that dynamic array is mutable - both the array itself and its elements. Using idup gets you an immutable copy. When copying dynamic arrays, you really get a slice of that array. So, you get an array that points to the same array as the original. Any changes to the elements in one affects the other. If you append to one of them and it doesn't have the space to resize in place or dyou o anything else which could cause it to reallocate, then that array is reallocated and they no longer point to the same data and changing will not change the other. If the elements of the array are const or immutable, then the fact that the two arrays point to the same data isn't a problem because the elements can't be changed (except in cases where you'red dealing with const rather than immutable and another array points to the same data but doesn't have const elements). So, assigning one string to another, for instance (string being an alias for immutable(char)[]), will never result in one string altering another. However, if you're dealing with char[] rather than string, one array _can_ affect the elements of another. I believe that byLine() deals with a char[], not a string. Now, as for associative arrays, they don't really deal with const correctly. I believe that they're actually implemented with void* and you can actually do things like put const elements in them in spite of the fact that toHash() on Object is not currently const (there is an open bug on the fact that Object is not const-correct). So, it does not surprise me in the least if it will take mutable types as its key and then allow them to be altered (assuming that they're pointers or reference types and you can therefore have other references to them). But to fix the problem in this case would require immutability rather than const, because you're dealing with a reference type (well, pseudo-reference type since dynamic arrays share their elements such that changes to their elements affect all arrays which point to those elements, but other changes - such as altering their length don't affect other arrays and will even likely result in the arrays then being completely separate). > The behavior itself seems really unpredictable prior to testing, and really > unintended after testing. I suspect it's due to some sort of a bug. The > program, on my box anyway, only fails when we give it identical strings, > except one is prefixed with a space. That should tell us that 'splitter' > and 'strip' didn't do their job properly. The fly in the ointment is that > when we output the strings, they appear as we would expect. > > I suspect D does string comparisons (when the 'in' keyword is used) based > on some kind of a hash, and that hash doesn't get correctly updated when > 'strip' or 'splitter' is applied, or upon the next comparison or whatever. > Calling 'idup' must force the hash to get recalculated. Obviously, you > guys would know if there's any merit to this, but it seems to explain the > problem. in should use toHash() (or whatever built-in functions for built-in types if you're not dealing with a struct or class) followed by ==. I'd be stunned if there were any caching involved. The problem is that byLine() is using a mutable array, so the elements pointed to by the array that you just put in the associative array changed, which means that the hash for them is wrong, and == will fail when used to compare the array to what it was before. > > The advantage with splitter is that it is lazy and therefore more > > efficient. split() is eager and allocates memory to hold the string > > fragments. > > Yeah, that's what I thought would be the answer. Kudos to you guys for > thinking of laziness out of the box. This is a major boon for D. > > You know, there's something this touches on which I was curious about. If > D defaults to 'safety first', and with some work you can get > down-to-the-metal, why doesn't the language default to immutable > variables, with an explicit modifier for mutable ones? C compatibility? C compatability would be one reason. Familiarity would
Re: string comparison
On Mon, 20 Dec 2010 18:44:12 +, doubleagent wrote: >> Are you 100% sure that you are running this version > > I have to be. There are no other versions of phobos on this box and > 'which dmd' points to the correct binary. > >> dictionary[word.idup] = newId; > > That fixes it. > >> The 'word' array is mutable and reused by byLine() on each iteration. >> By doing the above you use an immutable copy of it as the key instead. > > I REALLY don't understand this explanation. Why does the mutability of > 'word' matter when the associative array 'dictionary' assigns keys by > value...it's got to assign them by value, right? Otherwise we would > only get one entry in 'dictionary' and the key would be constantly > changing. This could be related to bug 2954, for which a fix will be released in the next version of DMD. http://d.puremagic.com/issues/show_bug.cgi?id=2954 -Lars
Re: string comparison
> Okay. I don't know what the actual code looks like Here. import std.stdio, std.string; void main() { uint[string] dictionary; // v[k], so string->uint foreach (line; stdin.byLine()) { // break sentence into words // Add each word in the sentence to the vocabulary foreach (word; splitter(strip(line))) { if (word in dictionary) continue; // nothing to do auto newId = dictionary.length; dictionary[word] = newId; writefln("%s\t%s", newId, word); } } } > ... Okay, suppose you're right. The behavior is still incorrect because the associative array has allowed two identical keys...identical because the only difference between two strings which I care about are the contents of their character arrays. > Also, it > would be _really_ annoying to have to mark variables mutable all over the > place > as you would inevitably have to do. Obviously your other points are valid, but I haven't found this to be true (Clojure is pure joy). Maybe you're right because D is a systems language and mutability needs to be preferred, however after only a day or two of exposure to this language that assumption also appears to be wrong. Take a look at Walter's first attempted patch to bug 2954: 13 lines altered to explicitly include immutable, and 4 altered to treat variables as const: http://www.dsource.org/projects/dmd/changeset/749 But I'm willing to admit that my exposure is limited, and that particular example is a little biased.
Re: string comparison
> This could be related to bug 2954, for which a fix will be released in > the next version of DMD. Looking at that new descriptive error message ie error("associative arrays can only be assigned values with immutable keys, not %s", e2->type->toChars()); it appears to be a distinct possibility. Thanks.
Re: string comparison
On Monday, December 20, 2010 16:45:20 doubleagent wrote: > > Okay. I don't know what the actual code looks like > > Here. > > import std.stdio, std.string; > > void main() { > uint[string] dictionary; // v[k], so string->uint > foreach (line; stdin.byLine()) { > // break sentence into words > // Add each word in the sentence to the vocabulary > foreach (word; splitter(strip(line))) { > if (word in dictionary) continue; // nothing to do > auto newId = dictionary.length; > dictionary[word] = newId; > writefln("%s\t%s", newId, word); > } > } > } > > > ... > > Okay, suppose you're right. The behavior is still incorrect because the > associative array has allowed two identical keys...identical because the > only difference between two strings which I care about are the contents of > their character arrays. Array comparison cares about the contents of the array. It may shortcut comparisons if lengths differ or if they point to the same point in memory and have the same length, but array comparison is all about comparing their elements. In this case, you'd have two arrays/strings which point to the same point in memory but have different lengths. Because their lengths differ, they'd be deemed unequal. If you managed to try and put a string in the associative array which has the same length as one that you already inserted, then they'll be considered equal, since their lengths are identical and they point to same point in memory, so in that case, I would expect the original value to be replaced with the new one. But other than that, the keys will be considered unequal in spite of the fact that they point to the same place in memory. The real problem here is that associative arrays currently allow non-immutable keys. Once that's fixed, then it won't be a problem anymore. > > Also, it > > would be _really_ annoying to have to mark variables mutable all over the > > place as you would inevitably have to do. > > Obviously your other points are valid, but I haven't found this to be true > (Clojure is pure joy). Maybe you're right because D is a systems language > and mutability needs to be preferred, however after only a day or two of > exposure to this language that assumption also appears to be wrong. Take > a look at Walter's first attempted patch to bug 2954: 13 lines altered to > explicitly include immutable, and 4 altered to treat variables as const: > http://www.dsource.org/projects/dmd/changeset/749 > > But I'm willing to admit that my exposure is limited, and that particular > example is a little biased. Most programmers don't use const even in languages that have it. And with many programmers programming primarily in languages like Java or C# which don't really have const (IIRC, C# has more of a const than Java, but it's still pretty limited), many, many programmers never use const and see no value in it. So, for most programmers, mutable variables will be the norm, and they'll likely only use const or immutable if they have to. There are plenty of C++ programmers who will seek to use const (and possibly immutable) heavily, but they're definitely not the norm. And, of course, there are plenty of other languages out there with const or immutable types of one sort or another (particularly most functional languages), but those aren't the types of languages that most programmers use. The result is that most beginning D programmers will be looking for mutable to be the norm, and forcing const and/or immutable on them could be seriously off- putting. Now, most code which is going to actually use const and immutable is likely to be a fair mix of mutable, const, and immutable - especially if you don't try to make everything immutable at the cost of efficiency like you'd typically get in a functional language. That being the case, regardless of whether mutable, const, or immutable is the default, you're going to have to mark a fair number of variables as something other than the default. So, making const or immutable the default would likely not save any typing, and it would annoy a _lot_ of programmers. So, the overall gain of making const or immutable the default is pretty minimal if not outright negative. Personally, I use const and immutable a lot, but I still wouldn't want const or immutable to be the default. - Jonathan M Davis
Re: enum ubyte[] vs enum ubyte[3]
On Mon, 20 Dec 2010 17:17:05 +0100 "Johannes Pfau" wrote: > > But if you are going to patch it, please make it add extra {} around > > action code! The thing is that when there is a label before {} block > > (and in ragel generated code I saw it's always so) the block isn't > > considered as a new scope which causes problems when you have local > > variables declaration inside actions. > > You mean like this code: > - > tr15: > #line 228 "jpf/http/parser.rl" > { > if(start != p) > { > key = line[(start - line.ptr) .. (p - line.ptr)]; > } > } > - > should become: ? > - > tr15: > #line 228 "jpf/http/parser.rl" > {{ > if(start != p) > { > key = line[(start - line.ptr) .. (p - line.ptr)]; > } > }} > - Yes. This way it becomes a scope which is kind of what one would expect from it. > > One is fixed size array and other is dynamic. Honestly I doubt that it > > matters for code generated by Ragel, since this is constant and won't be > > passed around. If it's harder to make it fixed-size then don't bother. > > > Could a dynamic array cause heap allocations, even if it's data is never > changed? If not, dynamic arrays would work fine. Sorry, I can't provide reliable information on what can happen in general, but right now there is no difference in produced code accessing elements of enum ubyte[] and enum ubyte[30]. In both cases constants are directly embedded in code. In fact as long as you only access its elements (no passing array as an argument, no assignment to another variable and no accessing .ptr) there is no array object at all. If you do -- new object is created every time you do. I believe Ragel doesn't generate code which passes tables around, so it doesn't matter. -- Nick Voronin
Re: Classes or stucts :: Newbie
On Mon, 20 Dec 2010 05:43:08 -0500 bearophile wrote: > Nick Voronin: > > > Here is where we diverge. Choosing struct vs class on criteria of their > > placement makes no sense to me. > > In D you use a class if you want inheritance or when you (often) need > reference semantics, and you use a struct when you need a little value passed > around by value or when you want a simple form of RAII or when you want to > implement something manually (like using PIMPL), or when you want max > performance (and you manage structs by pointer, you may even put a tag inside > the stuct or the pointer and implement manually some kind of inheritance). > With structs you have a literal syntax, postblits, in-place allocation, and > you are free to use align() too. Well said. Plenty of differences there more important than stack/heap allocation. -- Nick Voronin
Re: string comparison
Good & I agree.
is expression for template structs/classes instances?
Greetings I want to find if a given struct type is instantiated from a particular template struct type. For example: struct S (T) { alias T Type; T t; } And later I want to find out if a given type is of type S(*) (basically any type instantiated from template struct S). In fact I do not know the type value T used at the time of instantiating S!(T). I was looking at "is ( Type Identifier : TypeSpecialization , TemplateParameterList )" expression at http://www.digitalmars.com/d/2.0/expression.html#IsExpression . Thought there would be some way using that, but I could not find any. Regards Cherry
Re: is expression for template structs/classes instances?
On Monday 20 December 2010 20:23:49 d coder wrote: > Greetings > > I want to find if a given struct type is instantiated from a > particular template struct type. For example: > > struct S (T) { > alias T Type; > T t; > } > > And later I want to find out if a given type is of type S(*) > (basically any type instantiated from template struct S). In fact I do > not know the type value T used at the time of instantiating S!(T). > > I was looking at "is ( Type Identifier : TypeSpecialization , > TemplateParameterList )" expression at > http://www.digitalmars.com/d/2.0/expression.html#IsExpression . > Thought there would be some way using that, but I could not find any. > > Regards > Cherry Well, from the compiler's perspective S!int would have no relation to S!float, S!bool, or any other S!T. The template is instantiated with whatever types and values that it's given and then it's its own beast. So, really, there is no relation between the various instantiations of any particular template. I'm not sure that it would be impossible to have something in __traits or std.traits which tested whether a particular type was an instantiation of a particular template, but I'm not at all certain that it _is_ possible. Templates are used to generate code, but once generated, that code is essentially the same as it would have been had you typed it all yourself. So, my guess would be that you can't do what you're trying to do. I agree that it could be useful to be able to do it, but unfortunately, I don't think that it's possible. If you knew enough about the type, you might be able to do some template voodoo to do it in a round-about manner, but it would be specific to the type in question. For instance, given your definiton of S, you could use _traits/std.traits to check that the type that you're testing has a member variable t. You could then check that S!(typeof(t)) was the same as the type that you were testing. So, if you get particularly cunning about it, I believe that it can be tested for in specific cases, but I don't believe that it can be done in any general way. - Jonathan M Davis
Re: is expression for template structs/classes instances?
> For instance, given your definiton of S, you could use > _traits/std.traits to check that the type that you're testing has a member > variable t. You could then check that S!(typeof(t)) was the same as the type > that you were testing. So, if you get particularly cunning about it, I believe > that it can be tested for in specific cases, but I don't believe that it can > be > done in any general way. > Thanks Jonathan That is exactly what I had thought of doing. I was conscious that it may not be the cleanest way. Now that you are saying a cleaner way may not exist, I will go ahead and write the code. Regards - Cherry